使用 GDI+ 进行图像处理






4.66/5 (32投票s)
2006 年 5 月 8 日
2分钟阅读

157028

5568
本文描述了图像处理工具的实现。
引言
有很多类似的图像处理工具,正如我在本文中描述的那样。在这个个人工具中,我使用了非常基本的图像处理算法。我重点关注了亮度、颜色反转、对比度、模糊、锐化以及黑白颜色算法。我使用 GDI+ 将图像加载到内存中,并借助为每种图像处理类型提到的公式。代码包括 CImageProcess.cpp 和 CImageProcess.h 文件。我建议不要使用 GetPixel
和 SetPixel
进行图像处理。从性能上来说,它们非常慢。有关更多信息,请查看本文:在任何角度旋转位图,无需 GetPixel/SetPixel。
原始图像
算法和代码
- 亮度
图像可以是亮的或暗的。如果我们想让图像更亮,应该降低 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);
- 颜色反转
当我们反转颜色时,会得到当前像素的相反颜色。
公式
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; } }
- 对比度颜色
对比色是色轮上相对的颜色。在高对比度图像中,你可以看到清晰的边缘,并且该图像的不同元素被突出显示。在低对比度图像中,所有颜色几乎相同,很难辨认出细节。
公式
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; } }
- 失去焦点
模糊是计算机屏幕上一种众所周知的效果,实际上是在所有像素设备上,斜线和曲线都显示为一系列小的之字形水平和垂直线。
公式
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);
- 锐化
公式
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; } }
- 黑白颜色
可以通过为红色、绿色和蓝色赋予相同的值来获得黑白图像。
公式
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; } }