您现在的位置:首页 >> 图形媒体 >> 图形媒体 >> 内容

Delphi中实现调整图像的色阶的算法

时间:2011/9/3 15:00:14 点击:

  核心提示:Photoshop的色阶调整主要有3个调整点,即通常所说的黑场、白场及灰场调整,本文代码只涉及到黑场和白场调整,至于灰场调整算法以及与黑白场之间的关系等问题,因为本人还没完全琢磨透,只好以后再完善了(...

Photoshop的色阶调整主要有3个调整点,即通常所说的黑场、白场及灰场调整,本文代码只涉及到黑场和白场调整,至于灰场调整算法以及与黑白场之间的关系等问题,因为本人还没完全琢磨透,只好以后再完善了(其实算法并不复杂,麻烦的是后者)。

    色阶调整的基本算法并不复杂,用伪代码表示:

    Diff = levelHigh - levelLow

    newRGB = (oldRGB - levelLow) * 255 / Diff

    其中levelLow为色阶低端数据(黑场),levelHigh为色阶高端数据(白场),Diff为二者的离差,oldRGB为调整前的像素颜色,newRGB为调整后的颜色。

    色阶调整涉及四个通道,即R、G、B各分量通道及整体颜色通道,如果每个通道单独调整,将是比较麻烦和耗时的,本文过程采用MMX代码,可一次性处理R、G、B3个分量通道,加上整体颜色通道调整,最多需进行2遍调整处理,所以运行速度还是很快的,在我的P42.8G机器上处理一遍千万像素图片,不包括装载图片时间,只需47ms。

    下面直接给出图像色阶调整的源代码:

数据及过程定义:  
type 
  // 色阶调整数据  
  PColorLevelData = ^TColorLevelData;  
  TColorLevelData = packed record 
    BlueLow: LongWord;      // 蓝色通道低阶值  
    BlueHigh: LongWord;     // 蓝色通道高阶值  
    GreenLow: LongWord;     // 绿色通道低阶值  
    GreenHigh: LongWord;    // 绿色通道高阶值  
    RedLow: LongWord;       // 红色通道低阶值  
    RedHigh: LongWord;      // 红色通道高阶值  
  end;  
 
  // 色阶调整。参数:  
  //   Dest输出图,Source原图,Data自身操作图像  
  //   LevelData R、G、B各通道的色阶调整数据  
  //   Callback回调函数,返回True终止操作,CallbackData回调函数参数地址  
  function ImageColorLevels(var Dest: TImageData; const Source: TImageData;  
    const LevelData: TColorLevelData;  
    Callback: TImageAbort = nil; CallbackData: Pointer = nil): Boolean; overload;  
  procedure ImageColorLevels(var Data: TImageData; const LevelData: TColorLevelData); overload;  
 
实现代码:  
 
procedure ColorLevels(mmxBuf: Pointer); pascal;  
asm 
    push        ebx  
    mov         ebx, mmxBuf     // mm5 = 512 Coef Coef Coef  
    movq        mm5, qword ptr [ebx]  
    movq        mm6, qword ptr [ebx+8]  
    pxor        mm7, mm7        // mm6 = 00 00 LevelLow LevelLow LevelLow  
    pop         ebx  
@@yLoop:  
    push        ecx  
@@xLoop:  
    movd        mm0, [esi]  
    punpcklbw   mm0, mm7  
    psubw       mm0, mm6  
    psllw       mm0, 7 
    pmulhw      mm0, mm5  
    packuswb    mm0, mm7        // newRgb = (rgb - LevelLow) * 128 * Coef / 65536  
    movd        [edi], mm0      // newAlpha = (alpha - 0) * 128 * 512 / 65536  
    add         esi, 4 
    add         edi, 4 
    loop        @@xLoop  
    add         esi, eax  
    add         edi, ebx  
    pop         ecx  
    dec         edx  
    jnz         @@yLoop  
    emms  
end;  
 
function ImageColorLevels(var Dest: TImageData; const Source: TImageData;  
  const LevelData: TColorLevelData;  
  Callback: TImageAbort; CallbackData: Pointer): Boolean;  
type 
  TIntArray = array[0..5] of Integer;  
var 
  mmxBuf: array[0..7] of Word;  
  i, j, Diff: Integer;  
begin 
  Result := not ImageEmpty(Dest) and not ImageEmpty(Source);  
  if not Result then Exit;  
  for i := 0 to 3 do 
  begin 
    mmxBuf[i] := 512;  
    mmxBuf[i + 4] := 0;  
  end;  
  j := 0;  
  for i := 0 to 2 do 
  begin 
    Diff := TIntArray(LevelData)[j + 1];  
    if Diff > 255 then Diff := 255;  
    Dec(Diff, TIntArray(LevelData)[j]);  // Diff = LevelHigh - LevelLow  
    if (Diff >= 4) and (Diff < 255) then 
    begin 
      mmxBuf[i] := (255 * 512) div Diff; // Coef = 255 * 512 / Diff  
      mmxBuf[i + 4] := TIntArray(LevelData)[j];  
    end;  
    Inc(j, 2);  
  end;  
  if Assigned(Callback) then 
    Result := ExecuteAbort(Dest, Source, @ColorLevels, [@mmxBuf], Callback, CallbackData)  
  else 
    Result := ExecuteProc(Dest, Source, @ColorLevels, [@mmxBuf]);  
end;  
 
procedure ImageColorLevels(var Data: TImageData; const LevelData: TColorLevelData);  
begin 
  ImageColorLevels(Data, Data, LevelData);  
end; 

上面的调整过程即可一次性调整R、G、B3个分量通道的色阶,也可进行整体颜色通道的色阶调整。当整体颜色通道和分量通道都需要进行色阶调整时,应先调整分量通道,再调整整体颜色通道。

    需要说明的是,Photoshop色阶调整时,白场与黑场之间的离差最小值是2,而本文过程要求的白场与黑场之间离差最小值是4,否则,MMX代码就会溢出了。事实上,无论最小允许离差是2还是4,在实际运用中都没有多大意义。

更多关注请访问作者博客:http://blog.csdn.net/maozefa/archive/2010/06/02/5643459.aspx



迅雷专用高速下载

作者:网络 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
本类推荐
  • 没有
本类固顶
  • 没有
  • 盒子文章(www.2ccc.com) © 2022 版权所有 All Rights Reserved.
  • 沪ICP备05001939号