zoukankan      html  css  js  c++  java
  • C++ 图像处理

        在Photoshop中,图像色阶调整应用很广泛,本文介绍的图像色阶调整过程与Photoshop处理效果基本一致。

        Photoshop的色阶调整分输入色阶调整和输出色阶调整,其中输入色阶调整有3个调整点,即通常所说的黑场、白场及灰场调整。

        输入色阶调整的基本算法并不复杂,首先计算出白场与黑场的离差Diff,然后计算出像素各份量值与黑场的离差rgbDiff,如果rgbDiff<=0,像素各份量值等于0,否则,计算以rgbDiff与Diff的比值为底的灰场倒数的幂。用公式表示:

        Diff = Highlight -Shadow

        rgbDiff = RGB - Shadow

        clRGB = Power(rgbDiff / Diff,  1 / Midtones)

        其中Shadow为输入色阶低端数据(黑场),Highlight为输入色阶高端数据(白场), Midtones为输入色阶中间数据(灰场),Diff为二者的离差(必须大于1),RGB为调整前的像素分量值,clRGB为调整输入色阶后的像素分量值。

        输出色阶调整更简单,首先计算输出色阶白场与黑场的离差与255的比值系数,然后用输入色阶调整后的像素分量值乘上这个系数,再加上输出黑场值即可。用公式表示:

        outClRGB = clRGB * (outHighlight - outShadow) / 255 + outShadow

        其中,outShadow为输出黑场,outHighlight为输出白场,outClRGB为全部色阶调整后的像素分量值。

        前面已经提到输入色阶黑白场的离差必须大于1,而输入色阶并没有这个限制,输出黑白场的离差可以为负数,当输出黑场与白场完全颠倒时,输出色阶调整后的图片为原图片的负片。

        色阶调整涉及四个通道,即R、G、B各分量通道及整体颜色通道,如果每个通道单独调整,将是比较麻烦和耗时的,本文采用色阶表替换法,可一次性完成所有四个通道的色阶调整。

        下面是图像色阶调整的代码:

      1 // 色阶项结构
      2 typedef struct
      3 {
      4     UINT Shadow;
      5     FLOAT Midtones;
      6     UINT Highlight;
      7     UINT OutShadow;
      8     UINT OutHighlight;
      9 }ColorLevelItem, *PColorLevelItem;
     10  
     11 typedef struct
     12 {
     13     ColorLevelItem Blue;
     14     ColorLevelItem Green;
     15     ColorLevelItem Red;
     16     ColorLevelItem RGB;
     17 }ColorLevelData, *PColorLevelData;
     18  
     19 VOID InitColorLevelData(PColorLevelData clData)
     20 {
     21     PColorLevelItem item = &clData->Blue;
     22     for (INT i = 0; i < 4; i ++, item ++)
     23     {
     24         item->Shadow = item->OutShadow = 0;
     25         item->Highlight = item->OutHighlight = 255;
     26         item->Midtones = 1.0;
     27     }
     28 }
     29  
     30 BOOL GetColorLevelTable(PColorLevelItem item, LPBYTE clTable)
     31 {
     32     INT diff = (INT)(item->Highlight - item->Shadow);
     33     INT outDiff = (INT)(item->OutHighlight - item->OutShadow);
     34  
     35     if (!((item->Highlight <= 255 && diff < 255 && diff >= 2) ||
     36         (item->OutShadow <= 255 && item->OutHighlight <= 255 && outDiff < 255) ||
     37         (!(item->Midtones > 9.99 && item->Midtones > 0.1) && item->Midtones != 1.0)))
     38         return FALSE;
     39  
     40     DOUBLE coef = 255.0 / diff;
     41     DOUBLE outCoef = outDiff / 255.0;
     42     DOUBLE exponent = 1.0 / item->Midtones;
     43  
     44     for (INT i = 0; i < 256; i ++)
     45     {
     46         INT v;
     47         // 计算输入色阶黑白场
     48         if (clTable[i] <= (BYTE)item->Shadow)
     49             v = 0;
     50         else
     51         {
     52             v = (INT)((clTable[i] - item->Shadow) * coef + 0.5);
     53             if (v > 255)
     54                 v = 255;
     55         }
     56         // 计算输入色阶灰场
     57         v = (INT)(pow(v / 255.0, exponent) * 255.0 + 0.5);
     58         // 计算输出色阶
     59         clTable[i] = (BYTE)(v * outCoef + item->OutShadow + 0.5);
     60     }
     61     return TRUE;
     62 }
     63  
     64 BOOL CheckColorLevelData(PColorLevelData clData, BYTE clTables[][256])
     65 {
     66     BOOL result = FALSE;
     67     INT i, j;
     68     for (i = 0; i < 3; i ++)
     69     {
     70         for (j = 0; j < 256; j ++)
     71             clTables[i][j] = (BYTE)j;
     72     }
     73     PColorLevelItem item = &clData->Blue;
     74     for (i = 0; i < 3; i ++, item ++)
     75     {
     76         if (GetColorLevelTable(item, clTables[i]))
     77             result = TRUE;
     78     }
     79     for (i = 0; i < 3; i ++)
     80     {
     81         if (!GetColorLevelTable(item, clTables[i]))
     82             break;
     83         result = TRUE;
     84     }
     85     return result;
     86 }
     87  
     88 // 图像数据色阶调整
     89 VOID ImageColorLevel(BitmapData *dest, BitmapData *source, PColorLevelData clData)
     90 {
     91     PARGBQuad pd, ps;
     92     UINT width, height;
     93     INT dstOffset, srcOffset;
     94     GetDataCopyParams(dest, source, width, height, pd, ps, dstOffset, srcOffset);
     95  
     96     BYTE clTables[3][256];
     97     if (CheckColorLevelData(clData, clTables))
     98     {
     99         for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
    100         {
    101             for (UINT x = 0; x < width; x ++, ps ++, pd ++)
    102             {
    103                 pd->Blue = clTables[0][ps->Blue];
    104                 pd->Green = clTables[1][ps->Green];
    105                 pd->Red = clTables[2][ps->Red];
    106                 pd->Alpha = ps->Alpha;
    107             }
    108         }
    109     }
    110     else if (dest != source)
    111     {
    112         for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
    113         {
    114             for (UINT x = 0; x < width; x ++, ps ++, pd ++)
    115             {
    116                 pd->Color = ps->Color;
    117             }
    118         }
    119     }
    120 }

    下面给一个简单的图像色阶调整函数调用例子:

     1 void __fastcall TForm1::Button1Click(TObject *Sender)
     2 {
     3     BitmapData dest, source;
     4  
     5     Bitmap *sBmp = new Bitmap(L"..\..\media\source1.jpg");
     6     LockBitmap(sBmp, &source);
     7  
     8     Bitmap *dBmp = new Bitmap(source.Width, source.Height, PixelFormat32bppARGB);
     9     LockBitmap(dBmp, &dest);
    10  
    11     ColorLevelData clData;
    12     InitColorLevelData(&clData);
    13  
    14     clData.RGB.Shadow = 10;
    15     clData.RGB.Midtones = 1.2;
    16     clData.RGB.Highlight = 240;
    17     clData.RGB.OutShadow = 50;
    18     clData.RGB.OutHighlight = 200;
    19  
    20 /*
    21     clData.RGB.OutShadow = 255;
    22     clData.RGB.OutHighlight = 0;
    23 */
    24     ImageColorLevel(&dest, &source, &clData);
    25  
    26     UnlockBitmap(dBmp, &dest);
    27     UnlockBitmap(sBmp, &source);
    28  
    29     Gdiplus::Graphics g(Canvas->Handle);
    30     g.DrawImage(sBmp, 0, 0);
    31     g.DrawImage(dBmp, source.Width, 0);
    32  
    33     delete dBmp;
    34     delete sBmp;
    35 }

    第一张效果图绿色通道色阶调整,第二张效果图是RGB输出色阶调整到完全颠倒时的负片图。
         

     

        本文代码系用BCB XE7编辑和编译。

  • 相关阅读:
    Caliburn micro 学习笔记...
    First steps with Caliburn Micro in Windows Phone 8 系列文章
    WPF and Silverlight.ComboBox 如何通过 Binding IsDropDownOpen 实现下拉菜单展开
    http各个状态码的详解
    点阵字库产生的原理
    Windows 服务调试方法(基于.net framwork4.6)
    关于.net Core 笔记
    JS+ google.maps.api 实现基本的导航功能
    C# 遍历控件检查是否有被选中的项(通用)
    C#编程习惯
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13807602.html
Copyright © 2011-2022 走看看