Можно и без дуба. Ручками, дэкодировать изоброжение, и повысеть контрасность, резкость. А потом обратно сжать.
Надеюсь как работать с видео файлами разберешься сам.
Конрасность Для того чтобы произвести корекцию контрасности изоброжения нужно выровнить по трем уровням 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-YMin)*(255-0)/(YMax-YMin)
(G-YMin)*(255-0)/(YMax-YMin)
(B-YMin)*(255-0)/(YMax-YMin)
Где
YMax максимальная интенсивность
YMin минимальная интенсивность.
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;
Тут без оптимизации. Деление можно заменить умножением. Вернее тут просто деление вынести из цикла.
Если владеешь ассемблером, можно и на MMX, SSE переписать.
Резкость.Получается из размытия.
Fs(x,y)=A*F(x,y)-Fb(x,y)
Fs - изоброжение с повышенной резкостью
Fb - размытое исходное
A - коэфицент усиления >=1, при больших значениях у фильтра резко падает эффективность.
Пример состовления матрицы, на основе Гаусовского размытия.
s:=n/3;
for i:=-n to +n do
for j:=-n to +n do
_Mask[i,j]:=-1/(2*pi*s*s)*exp((-i*i-j*j)/(2*s*s));
_Mask[0,0]:=A+_Mask[0,0];
Или использовать следующии матрицы
0 -1 0
-1 A+4 -1
0 -1 0
-1 -1 -1
-1 A+8 -1
-1 -1 -1
А фильтр применяется просто через свертку.
В каждой точке перемножаем значение пикселей, на матрицу и суммируем.
Сумму, делим на маштабирующий коэфицент. Тут везде он равен 1.
Результат заносим в новое изоброжение. По краях не существующии точки принемаются за 0.
procedure TForm1.Button2Click(Sender: TObject);
var i,j,ii,jj:Integer;
Bp,Bp1:TBitmap;
a:array of PByteArray;
p:PByteArray;
R,G,B:Real;
begin
GetMask;
Bp:=TBitmap.Create;
Bp.PixelFormat:=pf24bit;
Bp.Width:=Image1.Picture.Bitmap.Width+n+n;
Bp.Height:=Image1.Picture.Bitmap.Height+n+n;
Bp.Canvas.Draw(n,n,Image1.Picture.Bitmap);
Bp1:=TBitmap.Create;
Bp1.PixelFormat:=pf24bit;
Bp1.Width:=Image1.Picture.Bitmap.Width;
Bp1.Height:=Image1.Picture.Bitmap.Height;
SetLength(a,2*n+1);
for i:=1 to 2*n do
a[i]:=Bp.ScanLine[i-1];
for i:=0 to Bp1.Height-1 do
begin
move(a[1],a[0],4*2*n);
a[Length(a)-1]:= Bp.ScanLine[i+2*n];
p:= Bp1.ScanLine[i];
for j:=0 to Bp1.Width-1 do
begin
R:=0;
G:=0;
B:=0;
for ii:=0 to 2*n do
for jj:=0 to 2*n do
begin
R:=R+a[ii,(j+jj)*3+0]*_Mask[ii-n,jj-n];
G:=G+a[ii,(j+jj)*3+1]*_Mask[ii-n,jj-n];
B:=B+a[ii,(j+jj)*3+2]*_Mask[ii-n,jj-n];
end;
if R>255 then R:=255;
if R<0 then R:=0;
if G>255 then G:=255;
if G<0 then G:=0;
if B>255 then B:=255;
if B<0 then B:=0;
p[j*3+0]:=Round(R);
p[j*3+1]:=Round(G);
p[j*3+2]:=Round(B);
end;
end;
Image2.Canvas.Draw(0,0,Bp1);
SetLength(a,0);
Bp1.Free;
bp.Free;
end;
С сылки:
http://student.kuleuven.be/~m0216922/CG/filtering.htmlhttp://sources.ru/magazine/0805/paint.html