Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Media";
Текущий архив: 2008.10.26;
Скачать: [xml.tar.bz2];

Вниз

Принцип работы инструментов автокоррекции изображений   Найти похожие ветки 

 
leonidus ©   (2007-08-07 14:35) [0]

В гугловской Picasa, и кажется в ACDSee, есть инструмент с помошью которого можно автоматически поднять якрость/контратность фотографии. Т.е. просто одним кликом программа осветляет фотографию, причем для разных фоток уровень осветления будет разный, в связи с чем вопрос, как программа понимает до какого уровня необходимо осветлить фотку, что бы и не пересветить ее и темного тоже небыло?


 
MBo ©   (2007-08-07 15:16) [1]

например, выравниванием гистограммы


 
leonidus ©   (2007-08-07 15:23) [2]

это как?


 
DVM ©   (2007-08-07 15:29) [3]


> это как?

1) делаешь массив из 256 ячеек.
2) Проходишь по пикселам и узнаешь яркость каждого.
3) Заносишь  +1 в ячейку массива под тем номером какую яркость ты получил.
4) После прохода по картинке у тебя будет массив с количествами пикселов по каждой величине яркости от 0 до 255.

Этот массив - и есть гистограмма


 
DVM ©   (2007-08-07 15:32) [4]

на хорошей фотке гистограмма должна быть более-менее равномерной или хотя бы не напоминать букву U. U-образную гистограмму имеет слишком контрастная фотка.


 
Sdubaruhnul   (2007-08-07 16:34) [5]

Вот небольшая брошюрка об инструменте Curves в Photoshop, на русском.
http://upload2.net/page/download/HJqvQJZznrZOHt2/UsingCurvesInPS.rar.html


 
leonidus ©   (2007-08-07 20:14) [6]

ссылка битая


 
Sdubaruhnul   (2007-08-07 21:36) [7]

>leonidus ©   (07.08.07 20:14) [6]

Да нет, работает. Там внизу секундомер. Но если настаиваешь, то зеркало:
http://www.speedyshare.com/557836353.html


 
leonidus ©   (2007-08-08 00:35) [8]

>DVMА что есть яркость?

Я вот делаю так:

var
btm:tbitmap;
color:tcolor;
r,g,b:integer;
...

 for x:=0 to btm.Width-1 do
  begin
   sum_l:=0;

   for y:=0 to btm.Height-1 do
    begin
     color:=btm.Canvas.Pixels[x,y];
     r:=GetRValue(color);
     g:=GetGValue(color);
     b:=GetBValue(color);

     sum_l:=sum_l+(r+g+b);
    end;

  end;

будет ли в конце каждого цикла "for y", значение sum_l равное высоте столбца гистограммы цветов, или гистограмма строится как-то иначе?


 
pavia ©   (2007-08-08 03:10) [9]

Для того чтобы произвести корекцию изоброжения нужно выровнить по трем уровням R,G,B. Припомощи линейного растяжения интенсивностий.
Делается это так ищем минимумы и максимумы по трем состовляющим.
RMin, RMax, GMin, GMax, BMin, BMax

(R-RMin)*(255-0)/(RMax-RMin)
(G-GMin)*(255-0)/(GMax-GMin)
(B-BMin)*(255-0)/(BMax-BMin)

R,G,B -знначение в точке

Насчет гистограммы.
Гистограмма - представления распределения частот выбранных переменных.
Тоесть то сколько раз встеречается значения переменных.

К примеру можно иметь три гистограммы интенсивнистей R,G,B.
Или одну по яркости, чаще всего пользуются ей. Где яркость можно считать так I=(R+G+B)/3 или  как опишу ниже.

Выравнивание идет также.  
(I-IMin)*(255-0)/(IMax-IMin)
А вообще можно добавить перемещение мыши тогда выравнивание  вести соответственно.

Для того чтобы провести корекцию изоброжения по яркости нужно
1. Перейти из цветового пространства в другое RGB -> YUV
2. Сделать корекцию
3. Сделать обратное преобразование YUV->RGB
Цветовая модель YUV состоит из
яркостную компоненты Y и двумя цветоразностныых компонентами U и V

Преобразование идет по следующим формулам

Y = 0.299R + 0.587G + 0,114B
U = – 0.147R – 0.289G + 0,436B
V = 0.615R + 0.515G + 0,100B = 0,877(R – Y)

R = Y + 1.140V
G = Y – 0.395U – 0.581V
B = Y + 2.032U

Насчет программирования используй ScanLine


Const
RY=0.2989;
GY=0.5866;
BY=0.1144;
Var
Hist:Array [0..255] of Byte;
Bp:TBitmap;
p:PByteArray;
R,G,B:Byte;

// Картинка должна быть в формате 24бита елси нет нужно привести
bp.PixelFormat:=pf24Bit;

FillCher(Hist[0],255,0);
if bp <> nil then
begin
for i:=0 to bp.Height-1 do
 begin
 p:=bp.ScanLine[i];
 for j:=0 to bp.Width-1 do
  begin
  B:=p[j*3+0];
  G:=p[j*3+1];
  R:=p[j*3+2];
  Inc(Hist[Round(RY*R+GY*G+BY*B)]);
  end;
 end;


Код писал прямо сдесь без проверки, думаю что работает.


 
Pavia ©   (2007-08-08 03:20) [10]


> Sdubaruhnul   (07.08.07 21:36) [7]
> >leonidus ©   (07.08.07 20:14) [6]
>
> Да нет, работает. Там внизу секундомер. Но если настаиваешь,
>  то зеркало:
> http://www.speedyshare.com/557836353.html

Интерестная ссылка. Я и так знаю все это так как хорошо представляю что происходит.
Там идет замена одних цветов другими.
Строются три таблицы или одна общая замены.

NewR,NewG,NewB:Array [0..255] of Byte;

И поомеру заменяются
R:=NewR[R];

В фотошопе просто есть поле через которое удобно задовать эти таблицы.
Там либы каждая точка задается как точка поставленная карандошем. Или как крявая. В качестве формылы для кривой новерно используются безье кривые.


 
leonidus ©   (2007-08-08 09:43) [11]

>pavia спасибо за инфу и код, но есть несколько вопросов:

1. Полученный массив содержит гистограмму яркости, я правильно понял?
2. Не понятно что делает функция Inc(Hist[Round(RY*R+GY*G+BY*B)]);
3. после получения
Y = 0.299R + 0.587G + 0,114B (ваш код это делает), нужно продолжить вычисления:

U = – 0.147R – 0.289G + 0,436B
V = 0.615R + 0.515G + 0,100B = 0,877(R – Y)
R = Y + 1.140V
G = Y – 0.395U – 0.581V
B = Y + 2.032U

верно?
4. Как реализовать после этого коррекцию изображения в bp ?


 
DVM ©   (2007-08-08 10:42) [12]


> leonidus ©   (08.08.07 00:35) [8]
> >DVM А что есть яркость?

Y = 0.299R + 0.587G + 0,114B


> 1. Полученный массив содержит гистограмму яркости, я правильно
> понял?

да


 
leonidus ©   (2007-08-08 11:43) [13]

Хорошо, я получил массив яркостей, а как теперь провести коррекцию над исходным изображением?


 
Pavia ©   (2007-08-08 13:14) [14]

1. Да
2. Вычесляет гистограмму.
Находим яркость Round(RY*R+GY*G+BY*B)
И увиличиваем на еденицу значение ячейки равной яркосости по номеру.
Inc(x) все равно что x:=x+1;
3. Мой код делает только вычислении гистограммы. А вот преобразования он не делает. Посмотрел что делает фотошо. Автоконтраст не заморачивается с расчетами. Просто считает что все состовляющии R,G,B равны. И гистограмму строит в соответствии с равенством каналов.

for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width*3-1 do
 begin
 Inc(Hist[p[j]]);
 end;


p:=bp.ScanLine[0];
Y:=p[0];
YMax:= Y;
YMin:= Y;

for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width*3-1 do
 begin
 Y:=p[j];
 if Y>YMax then YMax:=Y;
 if Y<YMin then YMin:=Y;
 end;
end;

for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width-1 do
 begin
 B:=Round((p[j*3+0]-YMin)*255 / (YMax-YMin));
 G:=Round((p[j*3+1]-YMin)*255 / (YMax-YMin));
 R:=Round((p[j*3+2]-YMin)*255 / (YMax-YMin));
 p[j*3+0]:=B;
 p[j*3+1]:=G;
 p[j*3+2]:=R;
 end;
end;



4. К примеру как сделано выше.
Гистограмма служит для других целий отоброжает сколько в картине светлых а сколько темных цветов. Можно к графику гистограммы добаить два ползунка левый и правый конец. С помощью них буде происходить вычисление насколько нужно сжать растянуть или сместить состовляющии цветов.


 
Pavia ©   (2007-08-08 13:20) [15]

Имея гистограмму в распоряжении найти Min и Max можно так

Это значительно быстрее нежели чем пробигать всю картинку.

for i:=0 to 255 do
if Hist[i]>0 then
 begin
 YMin:=i;
 YMax:=i;
 Break;
 end;
for i:=0 to 255 do
if Hist[i]>0 then
 begin
 if Hist[i]>Hist[YMax] then YMax:=i;
 if Hist[i]<Hist[YMin] then YMin:=i;
 end;


 
Pavia ©   (2007-08-08 13:25) [16]

Я там выше писал

> Hist:Array [0..255] of Byte;

Надо так Hist:Array [0..255] of DWord;
И соответственно FillCher(Hist[0],256*4,0);


 
leonidus ©   (2007-08-08 14:18) [17]

Приведенный код почему-то совршенно не увеличивает яркость картинки...

>Pavia пожалуйста ответьте еще не несколько вопросов:
1. В чем так сказалть физический смысл массива яркостей, почему в нем 256 символов и что значит если первый символ скажем равен 800, а 37 - нулю?
2. В чем смысл цикла:
for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width*3-1 do
begin
Inc(Hist[p[j]]);
end;
end;

что здесь делается с гистограммой?

3. Кусок
p:=bp.ScanLine[0];
Y:=p[0];
YMax:= Y;
YMin:= Y;

for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width*3-1 do
begin
Y:=p[j];
if Y>YMax then YMax:=Y;
if Y<YMin then YMin:=Y;
end;
end;

ищет в bp масимальный и минимальный элементы, но откуда bp.Width*3-1, и почему YMax всегда рано 255, а YMin = 0 ?


 
Pavia ©   (2007-08-08 14:35) [18]


> Приведенный код почему-то совршенно не увеличивает яркость
> картинки...

Насчет яркости не знаю, а вот контрасность должен увеличивать.
Изменения могут быть и не заметны глазу, поэтому сделай вывод гистограммы. Ты сможешь увидить как она растягивается и заполняет весь диапозон частот.

1. 256 потому что нам так захотелось. Просто мы имеем три состовляющих цвеа R,G,B каждая варируется от 0 до 255, так почемумы яркость тоже не варьировать в этих приделах поэтому Значение яркости может принемать только 256 значений.
Это значит что на всей картинке яркость со значением 0 встретилась 800 раз, а со значением 37 вообще не встретилась. Если построить график, то ты увидишь где столбики выше(их больше) слева тоесть ближе к нулю значит картинка темная. Если столбики выше справа то картинка светлая.
Если столбики разраяжены. Тоесть встречаются 0 элименты. Значит увеличивали контрасность картинки. Если к примеру заполненна середина гистограммы а покраям нет, то значит нужно увеличить контрасность. И тд.

2.  Вычисляется гистограма по RGB, такую обычно выводит фотошоп.

3.  bp.Width*3-1 так как у нас три состовляющих R,G,B

> почему YMax всегда рано 255, а YMin = 0 ?

Не всегда просто тебе повезло у тебя есть и "белый" цвет на кортинке и "черный". Вернее есть цвет у которого одна из состовляющих равна 255 и есть другой у которого есть 0 значение одного из цветов R,G,B
Для такой картинке автокантраст не нужен.


 
leonidus ©   (2007-08-08 14:49) [19]

Ок, картина проясняется - Pavia большое спасибо. Но все же еще вопрос, а как быть с автояркостью, ее как реализовать?


 
Pavia ©   (2007-08-08 15:05) [20]

При изменении контрасности яркость не должна меняться. Но когда мы делаем автоконтраст яркость у нас тоже меняется.

Если уж не терпиться просто вычти из R,G,B значение  127-HMean. HMean - средне арефметическое по гистограмме.
for i:=0 to 255 do HMean:=HMean+i*Hist[i];
HMean:=HMean div 255;


Есть еще выравнивание освещенности. Тут если не в доваться в теорию. То делаем размытие по некоторому радиусу. И делим исходное изоброжение на размытое. Есть и более сложные мотоды.


 
Pavia ©   (2007-08-08 15:10) [21]

Хотя чето с вычислением HMean я напутал,


 
DVM ©   (2007-08-08 15:12) [22]


> а как быть с автояркостью, ее как реализовать?

В отличии от контраста, с яркостью не все так просто. Нет четкого определения достаточно или недостаточно яркого изображения. В том же фотошопе нет такого действия автояркость, но есть автоконтраст.

Поэтому надо определиться сначала с нижней и верхней границей яркости и потом двигать яркость изображения в зону между этими границами.


 
leonid   (2007-08-09 16:47) [23]

сделал так:

//считаем ср. арифм. по гистограмме
for i:=0 to 255 do HMean:=HMean+i*Hist[i];
HMean:=HMean div 255;

for i:=0 to bp.Height-1 do
begin
p:=bp.ScanLine[i];
for j:=0 to bp.Width-1 do
begin
B:=Round(p[j*3+0]-(127-HMean));
G:=Round(p[j*3+1]-(127-HMean));
R:=Round(p[j*3+2]-(127-HMean));

p[j*3+0]:=B;
p[j*3+1]:=G;
p[j*3+2]:=R;
end;
end;
end;

но почему-то вместо осветления получил какое-то странное смещение цветов.  Но в общем сам аглоритм осветления или затемнения всей фотографии я нашел, вопрос в другом, как принять решении о применеии того или иного алгоритма, и насколько именно затемнять или осветлять фотку... а что если гистограммы разделить на две части и посчитать среднее значение слева и справо, соотв. если слева значение больше, то фотка темная, если справа больше - то светлая. Как вы считаете это реально?


 
DVM ©   (2007-08-09 17:00) [24]


> Как вы считаете это реально?

Реально, но что будет в результате сказать сложно.


 
leonid   (2007-08-09 17:25) [25]

А какие еще приемлемые способы существуют?


 
Pavia ©   (2007-08-09 19:44) [26]

Реально, просто я тогда малость ошибся.
s:=0;
HMean:=0;
for i:=0 to 255 do
begin
HMean:=HMean+i*Hist[i];
s:=s+Hist[i];
end;
HMean:=Round(HMean/S);

Но вот насчет осветления. Осветление не обязана быть линейной операцией. Почитай про гаммо коррекцию.


 
Pavia ©   (2007-08-09 19:56) [27]

А вообще там нет проверки выхода за границу если меньше 0 то пишем 0 если больше 255 то 255


 
leonid   (2007-08-09 22:39) [28]

>А вообще там нет проверки выхода за границу
Где нету проверки?


 
leonid   (2007-08-11 18:01) [29]

>Pavia  сейчас экспериментировал с фотошоповским инструментом "автоконтраст", и как вы верно заметили автоконтраст делается за счет равномерного растяжения гистограммы и заполнения нулевых или близким к нулю элементов гистограммы. Однако я сейчас сверил фотошопом картинку до преобразования вашим кодом и после, гистограмма практически одинаковая, хотя сам фотошоп на тойже картинке автоконтраст не сильный но делает, и гистограмма там явно смещается. Гдеже загвоздка? Фотку могу выложить на которой проводил эксперимент.


 
Ricks ©   (2007-08-12 21:09) [30]

Помучался я над вашей проблемой и вот что получилось:
http://www.ricks.pisem.net/test.zip

улучшал в два прохода.
в первом выравниваются цвета, для чего по каждому каналу находиться среднее значение (можно и с помощью гистограммы), потом находится общее среднее mean = (meanR + meanG + meanB) / 3 и для каждого канала
делаем
new[R, G, B]:=old[R, G, B] - (mean[R, G, B] - mean)
(на моем тестовом рисунке убирается излишек синего цвета)

во втором проходе выравниваются контраст (наверное ;))
для чего находим минимум и максимум "светлоты" и для каждого канала
new[R, G, B]:=255 * (old[R, G, B] - minL) / (maxL - minL)
формулу эту спер отсюда же, у Pavia :)

вроде бы неплохо выравнивает :)


 
Ricks ©   (2007-08-12 21:11) [31]


> во втором проходе выравниваются контраст (наверное ;))
для чего находим минимум и максимум "светлоты" и для каждого
канала



загнался :)

находим не для каждого канала min и max светлоты (т.к это бред :)), а просто минимум и максимум светлоты изображения


 
leonid   (2007-08-14 17:18) [32]

Ricks большое спасибо за потраченное время, сейчас буду смотреть.


 
leonid   (2007-08-14 17:20) [33]

Ricks а можно код глянуть?


 
Ricks ©   (2007-08-16 19:18) [34]

только код почти весь в моих типах, догадайся сам :)

var
  HIST : ImageHistogram;
  HISR : ImageHistogram;
  HISG : ImageHistogram;
  HISB : ImageHistogram;

...

var D : PRGBAArray;
   V : array [0..2] of PRGBAArray;
   H : tagBITMAPINFO;
   B : TBitmap;
   N : Cardinal;
   J : Cardinal;
   L : TLabRec;
   A : TRGBARec;
   lMin, lMax : single;
   hMean      : array [0..3] of single;
   sMean      : array [0..2] of single;
begin
N:=ExtractImageData(SourceImage.Picture.Bitmap.Handle, H, D);
V[0]:=AllocMem( N * 4 );
V[1]:=AllocMem( N * 4 );
V[2]:=AllocMem( N * 4 );

lMax:=0;
lMin:=255;
FillChar(HIST, SizeOf(HIST), 0);
for J:=0 to pred(N) do begin
 L:=RGBAtoLab( D^[J] );
 if L.L > lMax then lMax:=L.L;
 if L.L < lMin then lMin:=L.L;
 Inc(HIST[ Round(L.L)  ]);
 Inc(HISR[ D^[J].Red   ]);
 Inc(HISG[ D^[J].Green ]);
 Inc(HISB[ D^[J].Blue  ]);
end;

FillChar(hMean, SizeOf(hMean), 0);
FillChar(sMean, SizeOf(sMean), 0);
for J:=0 to 255 do begin
 hMean[0]:=hMean[0] + j * HISR[J]; sMean[0]:=sMean[0] + HISR[J];
 hMean[1]:=hMean[1] + j * HISG[J]; sMean[1]:=sMean[1] + HISG[J];
 hMean[2]:=hMean[2] + j * HISB[J]; sMean[2]:=sMean[2] + HISB[J];
end;

hMean[0]:=hMean[0] / sMean[0];
hMean[1]:=hMean[1] / sMean[1];
hMean[2]:=hMean[2] / sMean[2];
hMean[3]:=(hMean[0] + hMean[1] + hMean[2]) / 3;

for J:=0 to pred(N) do begin
 V[0]^[J]:=D^[J];

 A.Blue:= ByteLim( D^[J].Blue  - (hMean[2] - hMean[3]) );
 A.Green:=ByteLim( D^[J].Green - (hMean[1] - hMean[3]) );
 A.Red:=  ByteLim( D^[J].Red   - (hMean[0] - hMean[3]) );
 V[1]^[J]:=A;
end;

for J:=0 to pred(N) do begin
 L:=RGBAtoLab( V[1]^[J] );
 if L.L > lMax then lMax:=L.L;
 if L.L < lMin then lMin:=L.L;
end;
for J:=0 to pred(N) do begin
 A.Blue:= ByteLim( 255 * (V[1]^[J].Blue  - lMin) / (lMax - lMin) );
 A.Green:=ByteLim( 255 * (V[1]^[J].Green - lMin) / (lMax - lMin) );
 A.Red:=  ByteLim( 255 * (V[1]^[J].Red   - lMin) / (lMax - lMin) );
 V[2]^[J]:=A;
end;
.....



Страницы: 1 вся ветка

Форум: "Media";
Текущий архив: 2008.10.26;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.009 c
11-1194440742
misha_shar
2007-11-07 16:05
2008.10.26
Вопрос по TabControl;


2-1221648561
renex
2008-09-17 14:49
2008.10.26
вызов функции из другого модуля


2-1221731916
cyborg
2008-09-18 13:58
2008.10.26
Нужен совет по выбору компонента


3-1208274623
Поп Гапон
2008-04-15 19:50
2008.10.26
Автоматический контроль места под базу.


2-1221889767
AlexDan
2008-09-20 09:49
2008.10.26
Как узнать есть ли файл на диске..





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский