线性图像亮度一般是将图像像素的RGB转换为HSL(HSV)等颜色空间,对L(V)部分进行增减调整后,再转换为RGB颜色空间,优点是调整过图像层次感很强;缺点是代码较复杂,调整速度慢,而且当图像亮度增减量较大时有很大的失真
针对上面两种方法的优缺点,本人参照Photoshop的对比度、饱和度调整原理,对图像亮度调整方法进行了改进,经测试,效果还不错:主要有不失真调整范围宽、有较好的层次感、尽可能减少图像信息损失量、运算速度较快及代码也不太复杂等。
下面给出采用Delphi的TBitmap对象调整亮度的Delphi测试代码(BASM过程),如果使用GDI+则更简单,因TImageData与GDI+的TBitmapData是兼容的
TImageData = packed record
Width: Integer; // 像素宽度
Height: Integer; // 像素高度
Stride: Integer; // 扫描宽度
PixelFormat: Integer; // 像素信息的格式
Scan0: Pointer; // 扫描行首地址
Reserved: Integer; // 保留
end;
PImageData = ^TImageData;
procedure FillAlpha(Data: TImageData);
asm
mov ecx, [eax].TImageData.Width
imul ecx, [eax].TImageData.Height
mov edx, [eax].TImageData.Scan0
add edx, 3
mov eax, 255
cld
@PixelLoop:
mov [edx], al
add edx, 4
loop @PixelLoop
end;
function GetBitmapData(Bitmap: TBitmap): TImageData;
var
FillFlag: Boolean;
begin
FillFlag := Bitmap.PixelFormat <> pf32bit;
Bitmap.PixelFormat := pf32bit;
Result.Width := Bitmap.Width;
Result.Height := Bitmap.Height;
Result.Stride := Result.Width shl 2;
Result.Scan0 := Bitmap.ScanLine[Result.Height - 1];
Result.PixelFormat := -1; // Windows bitmap format flag
Result.Reserved := 0;
if FillFlag then FillAlpha(Result);
end;
procedure ImageLinearBrightness(Data: TImageData; Value: Integer);
asm
push esi
push edi
push ebx
test edx, edx // if (Value == 0) return
jz @end
mov ebx, edx
mov edi, eax
jl @@2
cmp ebx, 255 // if (Value > 0)
jle @@1 // {
mov ebx, 255 // if (Value > 255) Value = 255
@@1:
mov eax, 65536 // Value = 65536 / (256 - Value) - 256
mov ecx, 256
sub ecx, ebx
cdq
div ecx
sub eax, 256
mov ebx, eax // }
@@2:
mov esi, [edi].TImageData.Height
imul esi, [edi].TImageData.Width
mov edi, [edi].TImageData.Scan0
cld
@PixelLoop:
mov ecx, 3
@RGBLoop:
movzx eax, [edi] // rgb = rgb + rgb * value / 256
mov edx, eax
imul eax, ebx
sar eax, 8
add eax, edx
jns @@3
xor eax, eax
jmp @@4
@@3:
cmp eax, 255
jle @@4
mov eax, 255
@@4:
stosb
loop @RGBLoop
inc edi
dec esi
jnz @PixelLoop
@end:
pop ebx
pop edi
pop esi
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Bmp: TBitmap;
Jpg: TJPEGImage;
Data: TImageData;
begin
Bmp := TBitmap.Create;
Jpg := TJPEGImage.Create;
Jpg.LoadFromFile('D:\001-1.jpg');
Bmp.Assign(Jpg);
Jpg.Free;
Data := GetBitmapData(Bmp);
ImageLinearBrightness(Data, 100);
Canvas.Draw(0, 0, Bmp);
Bmp.Free;
end;