Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.10.26;
Скачать: CL | DM;

Вниз

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

 
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 вся ветка

Текущий архив: 2008.10.26;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.013 c
15-1220599042
noob_one
2008-09-05 11:17
2008.10.26
Как перенести Delphi на новую windows?


2-1221813260
Цукор5
2008-09-19 12:34
2008.10.26
фон TProgressBar


2-1221840146
Сергей
2008-09-19 20:02
2008.10.26
Как получить путь к файлу?


15-1220412091
Slider007
2008-09-03 07:21
2008.10.26
С днем рождения ! 3 сентября 2008 среда


4-1198653645
Rav
2007-12-26 10:20
2008.10.26
Как опеределить язык GUI Windows!!! Не GetSystemDefaultLCID!!!