Delphi图像处理 -- 亮度/对比度调整

阅读提示:

    《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

    《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

    尽可能保持二者内容一致,可相互对照。

   本文代码必须包括文章《Delphi图像处理 -- 数据类型及公用过程》中的ImageData.pas单元

  

        本人已经写过几篇关于亮度调整的文章,但是关于图像的对比度调整的过程和文章却一直没有写,其原因是一直没找到一个好的算法。可能有人会说,图像的亮度,对比度调整是最简单的图形操作,其算法网上可说是一搜一大把,确实如此,可就是这最简单的操作,网上的文章却五花八门,我拣几个试了一下,好像都不太理想,关键是算法太简单,实际操作效果不好,于是想,Photoshop的对比度还是较好的,而且也通用,但偏偏网上没有介绍它的算法,用了大半天时间研究了一下,再花了1个来小时写了个Delphi过程,试了一下,居然和Photoshop的对比度调整完全一样的效果!于是认真写了个测试程序,把亮度和对比度放在一起进行调整(亮度和对比度处理过程为各自独立的,其中亮度过程基本是本BLOG文章《GDI+ 在Delphi程序的应用 -- 调整图像亮度》的代码),可是效果却和Photoshop大不一样了,是什么原因呢,Photoshop的亮度调整算法是最简单的那种,与我的亮度过程做出来的是一样的(效果比较图参见《GDI+ 在Delphi程序的应用 -- 线性调整图像亮度》),而前面说了,对比度过程算法也是和Photoshop一样的,可放在一起调整就不行了,无论是先调整亮度,还是先调整对比度都这样。后来仔细分析了一下,Photoshop是用一个函数处理亮度/对比度,而且亮度调整是按对比度的正负分别对待的,下面是实现代码(包括一个简单的例子):

function _CheckRgb(Rgb: Integer): Integer;
asm
    test    eax, eax
    jge     @@1
    xor     eax, eax
    ret
@@1:
    cmp     eax, 255
    jle     @@2
    mov     eax, 255
@@2:
end;

procedure ImageBrightContrast(var Data: TImageData; Bright, Contrast, Threshold: Integer);
var
  vs: TGrayTable;
  cv: Single;
  i, v: Integer;
  height, dataOffset: Integer;
begin
  if (Bright = 0) and (Contrast = 0) then Exit;
  if Contrast <= -255 then cv := -1 else cv := Contrast / 255;
  if (Contrast > 0) and (Contrast < 255) then
    cv := 1 / (1 - cv) - 1;
  for i := 0 to 255 do
  begin
    if Contrast > 0 then v := _CheckRgb(i + bright) else v := i;
    if Contrast >= 255 then
    begin
      if v >= Threshold then v := 255 else v := 0;
    end
    else
      v := _CheckRgb(v + Round((v - Threshold) * cv));
    if Contrast <= 0 then vs[i] := _CheckRgb(v + bright) else vs[i] := v;
  end;
  asm
    mov     eax, Data
    call    _SetDataRegs
    mov     height, edx
    mov     dataOffset, ebx
    lea     esi, vs;
@@yLoop:
    push    ecx
@@xLoop:
    movzx   eax, [edi].TARGBQuad.Blue
    movzx   ebx, [edi].TARGBQuad.Green
    movzx   edx, [edi].TARGBQuad.Red
    mov     al, [esi+eax]
    mov     bl, [esi+ebx]
    mov     dl, [esi+edx]
    mov     [edi].TARGBQuad.Blue, al
    mov     [edi].TARGBQuad.Green, bl
    mov     [edi].TARGBQuad.Red, dl
    add     edi, 4
    loop    @@xLoop
    pop     ecx
    add     edi, dataOffset
    dec     height
    jnz     @@yLoop
@@Exit:
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  bmp: TGpBitmap;
  g: TGpGraphics;
  data: TImageData;
begin
  bmp := TGpBitmap.Create('..\media\source1.jpg');
  g := TGpGraphics.Create(Canvas.Handle);
  g.DrawImage(bmp, 0, 0);
  data := LockGpBitmap(bmp);
  ImageBrightContrast(data, 50, 0, 121);
  UnlockGpBitmap(bmp, data);
  g.DrawImage(bmp, data.Width, 0);
  g.Free;
  bmp.Free;
end;

 

    下面对亮度/对比度的原理简单介绍一下。

    一、Photoshop对比度算法。可以用下面的公式来表示:

    (1)、nRGB = RGB + (RGB - Threshold) * Contrast / 255

    公式中,nRGB表示图像像素新的R、G、B分量,RGB表示图像像素R、G、B分量,Threshold为给定的阈值,Contrast为处理过的对比度增量。

    Photoshop对于对比度增量,是按给定值的正负分别处理的:

    当增量等于-255时,是图像对比度的下端极限,此时,图像RGB各分量都等于阈值,图像呈全灰色,灰度图上只有1条线,即阈值灰度;

    当增量大于-255且小于0时,直接用上面的公式计算图像像素各分量;

    当增量等于 255时,是图像对比度的上端极限,实际等于设置图像阈值,图像由最多八种颜色组成,灰度图上最多8条线,即红、黄、绿、青、蓝、紫及黑与白;

    当增量大于0且小于255时,则先按下面公式(2)处理增量,然后再按上面公式(1)计算对比度:

    (2)、nContrast = 255 * 255 / (255 - Contrast) - 255

    公式中的nContrast为处理后的对比度增量,Contrast为给定的对比度增量。

    二、图像亮度调整。本文采用的是最常用的非线性亮度调整(Phoposhop CS3以下版本也是这种亮度调整方式,CS3及以上版本也保留了该亮度调整方式的选项)。

    三、图像亮度/对比度综合调整算法。这个很简单,当亮度、对比度同时调整时,如果对比度大于0,现调整亮度,再调整对比度;当对比度小于0时,则相反,先调整对比度,再调整亮度。

    在亮度/对比度调整函数ImageBrightContrast中,首先按前面介绍的原理制造了一个256个元素大小的查找表,然后对图像数据逐像素按R、G、B分量值在查找表中取得调整后的数据,因此处理速度相当快。

    下面是对比度255时的运行截图:

 

    《Delphi图像处理》系列使用GDI+单元下载地址和说明见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。

    因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

    这里可访问《Delphi图像处理 -- 文章索引》。

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
Delphi11 是最新的 Delphi 版本,而 `delphi-opencv-master` 是一个开源的 Delphi 与 OpenCV 集成的项目,它提供了一组 Delphi 封装的 OpenCV 函数和类,方便 Delphi 开发者使用 OpenCV 进行图像处理和计算机视觉操作。 在 Delphi11 中,你可以通过以下步骤来使用 `delphi-opencv-master`: 1. 首先,你需要下载 `delphi-opencv-master` 项目的源代码,可以从 GitHub 上下载:https://github.com/Laex/Delphi-OpenCV 2. 解压缩下载的源代码,并将其中的 `OpenCV` 文件夹复制到 Delphi11 项目的根目录下。 3. 在 Delphi11 中打开你的项目,然后在菜单栏中选择 `Project` -> `Options` -> `Delphi Compiler` -> `Search Path`,将 OpenCV 文件夹所在的路径添加到搜索路径中。 4. 在 Delphi11 中使用 `uses` 语句引入 `OpenCV_Image` 单元,并调用其中的函数和类来进行图像处理和计算机视觉操作。 例如,以下代码演示了如何使用 `delphi-opencv-master` 进行图像读取和灰度化: ``` uses OpenCV_Image; var img: IplImage; begin // 读取图像 img := LoadImage('lena.jpg'); // 将图像转换为灰度图像 cvCvtColor(img, img, CV_RGB2GRAY); // 显示图像 ShowImage('My Image', img); // 等待用户按下任意键 WaitKey; // 释放图像内存 img.Release; end; ``` 这段代码使用了 `OpenCV_Image` 单元中提供的 `LoadImage` 函数和 `ShowImage` 函数来读取和显示图像,使用了 OpenCV 库中的 `cvCvtColor` 函数将图像转换为灰度图像。你可以根据自己的需要,使用 `delphi-opencv-master` 中提供的其他函数和类来进行更加复杂的图像处理和计算机视觉操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值