65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 GDI+ 进行图像处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.66/5 (32投票s)

2006 年 5 月 8 日

2分钟阅读

viewsIcon

157028

downloadIcon

5568

本文描述了图像处理工具的实现。

引言

有很多类似的图像处理工具,正如我在本文中描述的那样。在这个个人工具中,我使用了非常基本的图像处理算法。我重点关注了亮度、颜色反转、对比度、模糊、锐化以及黑白颜色算法。我使用 GDI+ 将图像加载到内存中,并借助为每种图像处理类型提到的公式。代码包括 CImageProcess.cppCImageProcess.h 文件。我建议不要使用 GetPixelSetPixel 进行图像处理。从性能上来说,它们非常慢。有关更多信息,请查看本文:在任何角度旋转位图,无需 GetPixel/SetPixel

原始图像

算法和代码

  1. 亮度

    图像可以是亮的或暗的。如果我们想让图像更亮,应该降低 RGB 值。如果想让图像更暗,应该增加 RGB 值。

    公式

    Color = Color + Value(may be –ve)
    if (Color <0) Color = 0; if (Color>255) Color = 255;

    例如,如果我们想降低红色分量

    Red = Red - DecrementVal

    要增加红色分量

    Red = Red + IncrementVal

    代码

    BITMAPINFO bi;
    BOOL bRes;
    char *buf;
    
    // Bitmap header
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = m_nWidth;
    bi.bmiHeader.biHeight = m_nHeight;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    bi.bmiHeader.biSizeImage = m_nWidth * 4 * m_nHeight;
    bi.bmiHeader.biClrUsed = 0;
    bi.bmiHeader.biClrImportant = 0;
    
    // Buffer
    buf = (char *) malloc(m_nWidth * 4 * m_nHeight);
    // Don't use getPixel and SetPixel.It's very slow.
    // Get the all scanline.
    bRes = GetDIBits(hMemDC, m_hBitmap, 0, m_nHeight, buf, &bi,
                           DIB_RGB_COLORS);
    long nCount=0;
    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {
            long lVal=0;
            memcpy(&lVal, &buf[nCount], 4);
            // Get the reverse order
            int b = GetRValue(lVal);
            int g = GetGValue(lVal);
            int r = GetBValue(lVal);
            
            // Red
            r += nRedVal;
            if (r >255)
            {
                r = 255;
            }
            if (r <0)
            {
                r = 0;
            }
    
            // Green
            g += nGreenVal;
            if (g>255)
            {
                g = 255;
            }
            if (g<0)
            {
                g = 0;
            }
    
            // Blue
            b += nBlueVal;
            if (b >255)
            {
                b = 255;
            }
            if (b<0)
            {
                b = 0;
            }
            
            // Store reverse order
            lVal = RGB(b, g, r);
            memcpy(&buf[nCount], &lVal, 4);
    
        // Increment with 4. RGB color take 4 bytes. 
        // The high-order byte must be zero
        // See in MSDN COLORREF
            nCount+=4;
          }
        }
    
        // Set again
        SetDIBits(hMemDC, m_hBitmap, 0, bRes, buf,  &bi,
                           DIB_RGB_COLORS);    
        free(buf);
  2. 颜色反转

    当我们反转颜色时,会得到当前像素的相反颜色。

    公式

    Color = 255 – Color; if (Color <0) Color = 0;
    if (Color>255) Color = 255;

    代码

    // Same header format
    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {
            long lVal=0;
            memcpy(&lVal, &buf[nCount], 4);
            int b = 255-GetRValue(lVal);
            int g = 255-GetGValue(lVal);
            int r = 255-GetBValue(lVal);
                
            lVal = RGB(b, g, r);
                
            memcpy(&buf[nCount], &lVal, 4);
            nCount+=4;
        }
    }
  3. 对比度颜色

    对比色是色轮上相对的颜色。在高对比度图像中,你可以看到清晰的边缘,并且该图像的不同元素被突出显示。在低对比度图像中,所有颜色几乎相同,很难辨认出细节。

    公式

    Color = (((Color - 128) * ContrastVal) / 100) +128
    if (Color <0) Color = 0; if (Color>255) Color = 255;

    这里,对比度值介于 0 和 200 之间。

    代码

    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {            
            long lVal=0;
            memcpy(&lVal, &buf[nCount], 4);
            // Get from buffer in reverse order
            int b = GetRValue(lVal);
            int g = GetGValue(lVal);
            int r = GetBValue(lVal);
    
            r = ((r-128)*nContrastVal)/100 +128;
            g = ((g-128)*nContrastVal)/100 +128;
            b = ((b-128)*nContrastVal)/100 +128;            
            
            // Red
            if (r >255)
            {
                r = 255;
            }
            if (r <0)
            {
                r = 0;
            }
                
            // Green
            if (g>255)
            {
                g = 255;
            }
            if (g<0)
            {
                g = 0;
            }
    
            // Blue            
            if (b >255)
            {
                b = 255;
            }
            if (b<0)
            {
                b = 0;
            }
    
            // Store in reverse order            
            lVal = RGB((int)b, (int)g, (int)r);
            
            memcpy(&buf[nCount], &lVal, 4);
            nCount+=4;
        }
    }
  4. 失去焦点

    模糊是计算机屏幕上一种众所周知的效果,实际上是在所有像素设备上,斜线和曲线都显示为一系列小的之字形水平和垂直线。

    公式

    Color = (C1+C2+C3+C4+C5)/5

    有关模糊和抗锯齿的更多详细信息,请查看本文:为 Web 创建图形:抗锯齿

    这里,C1 是当前像素。C2、C3、C4 和 C5 是附近的像素。

    代码

    pOriBuf = (char *) malloc(m_nWidth * 4 * m_nHeight);
    // Store new value into tempravary buffer
    char *tmpBuf = (char *) malloc(m_nWidth * 4 * m_nHeight);
    bRes = GetDIBits(hMemDC, m_hBitmap, 0, m_nHeight, pOriBuf, &bi,
                           DIB_RGB_COLORS);    
    long nCount=0;
    long c1, c2, c3, c4, c5;
    
    // Retrive from original buffer
    // Caluculate the value and store new value into tmpBuf
    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {
            long lVal=0;
            memcpy(&lVal, &pOriBuf[nCount], 4);
            int b = GetRValue(lVal);
            int g = GetGValue(lVal);
            int r = GetBValue(lVal);
    
            c1 = r;
            // Red
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && 
                (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[nCount-(m_nWidth*4l)], 4);
                c2 = GetBValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetBValue(lVal);
        
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetBValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetBValue(lVal);
                        
                r = (c1+c2+c3+c4+c5)/5;
            }
    
            // Green
            c1 = g;
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && 
                (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[(nCount-(m_nWidth*4l))], 4);
                c2 = GetGValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetGValue(lVal);
        
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetGValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetGValue(lVal);
        
                g = (c1+c2+c3+c4+c5)/5;
            }
    
            // Blue
            c1 = b;
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && 
                (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[(nCount-(m_nWidth*4l))], 4);
                c2 = GetRValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetRValue(lVal);
        
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetRValue(lVal);
        
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetRValue(lVal);
        
                b = (c1+c2+c3+c4+c5)/5;
            }
    
            // Store in reverse order
            lVal = RGB(b, g, r);
                    
            memcpy(&tmpBuf[nCount], &lVal, 4);
        
            nCount+=4;
        }
    }
    
    // Store tmpBuf
    SetDIBits(hMemDC, m_hBitmap, 0, bRes, 
              tmpBuf,  &bi, DIB_RGB_COLORS);
    
    free(pOriBuf);
    free(tmpBuf);
  5. 锐化

    公式

    Color = (C1*5) – (C2+C3+C4+C5).
    if (Color <0) Color = 0; if (Color>255) Color = 255;

    代码

    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {
            long lVal=0;
            memcpy(&lVal, &pOriBuf[nCount], 4);
            int b = GetRValue(lVal);
            int g = GetGValue(lVal);
            int r = GetBValue(lVal);
        
            c1 = r;
            // Red
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[nCount-(m_nWidth*4l)], 4);
                c2 = GetBValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetBValue(lVal);
            
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetBValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetBValue(lVal);
            
                r = (c1*5) - (c2+c3+c4+c5);
            }
    
            // Green
            c1 = g;
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[(nCount-(m_nWidth*4l))], 4);
                c2 = GetGValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetGValue(lVal);
            
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetGValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetGValue(lVal);
            
                g = (c1*5) - (c2+c3+c4+c5);
            }
    
            // Blue
            c1 = b;
            if ((nCount < ((m_nHeight-1)*m_nWidth*4l)) && (nCount > (m_nWidth*4)))
            {
                memcpy(&lVal, &pOriBuf[(nCount-(m_nWidth*4l))], 4);
                c2 = GetRValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount+4], 4);
                c3 = GetRValue(lVal);
            
                memcpy(&lVal, &pOriBuf[(nCount+(m_nWidth*4l))], 4);
                c4 = GetRValue(lVal);
            
                memcpy(&lVal, &pOriBuf[nCount-4], 4);
                c5 = GetRValue(lVal);
            
                b = (c1*5) - (c2+c3+c4+c5);
            }
    
            // Red
            if (r >255)
            {
                r = 255;
            }
            if (r <0)
            {
                r = 0;
            }
            
            // Green
            if (g>255)
            {
                g = 255;
            }
            if (g<0)
            {
                g = 0;
            }
    
            // Blue
            if (b >255)
            {
                b = 255;
            }
            if (b<0)
            {
                b = 0;
            }
            
            // Store in reverse order
            lVal = RGB(b, g, r);
            
            memcpy(&tmpBuf[nCount], &lVal, 4);
            
            nCount+=4;
        }
    }
  6. 黑白颜色

    可以通过为红色、绿色和蓝色赋予相同的值来获得黑白图像。

    公式

    Color = (R+G+B)/3; R = Color; G = Color; B = Color;

    代码

    for (int i=0; i<m_nHeight; ++i)
    {
        for (int j=0; j<m_nWidth; ++j)
        {
            long lVal=0;
            memcpy(&lVal, &buf[nCount], 4);
            // Get the color value from buffer
            int b = GetRValue(lVal);
            int g = GetGValue(lVal);
            int r = GetBValue(lVal);
    
            // get the average color value
            lVal = (r+g+b)/3;
    
            // assign to RGB color            
            lVal = RGB(lVal, lVal, lVal);
            memcpy(&buf[nCount], &lVal, 4);
    
            nCount+=4;
        }
    }
© . All rights reserved.