利用GDI+处理图像的色彩
首先先介绍一下ColorMatrix结构体:表示颜色的变换关系,定义如下:
typedef struct { REAL m[5][5]; } ColorMatrix;
ColorMatrix结构体一般和ImageAttribute类配合使用,使用的方式是先调用ImageAttibute::SetColorMatrix,运用该颜色变化矩阵,然后在绘制函数中将ImageAttribute对象作为DrawImage函数参数。以下的图像色彩变换都会用到这个结构体。
获取对应编码器的CLSID
1 int GetEncoderClsid(const WCHAR* format, CLSID* pClisd); // 获取对应编码器的CLSID 2 3 int CMyDlg::GetEncoderClsid(const WCHAR* format, CLSID* pClisd) // 获取对应编码器的CLSID 4 { 5 UINT num = 0; // 图像编码器的数量 6 UINT size = 0; // 图像编码器数组的字节数 7 8 Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL; 9 GetImageEncodersSize(&num, &size); 10 if (size == 0) 11 return -1; 12 pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size)); 13 14 GetImageEncoders(num, size, pImageCodecInfo); 15 for(UINT j = 0;j<num;++j) 16 { 17 if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) 18 { 19 *pClisd = pImageCodecInfo[j].Clsid; 20 free(pImageCodecInfo); 21 return j; 22 } 23 } 24 free(pImageCodecInfo); 25 return -1; 26 }
一、改变图像的透明度:只需要缩放Alpha分量就能到达效果。
BOOL ChangeImageAlpha(const CString& imagePath, REAL alpha, const CString& savePath);
/********************************************************************************** * 作用:改变指定图像的透明度,并将新图像按照指定的图像格式和路径保存 * 参数:imagePath 为原图路径 * alpha 为分量缩放系数 * savePath 为用于保存处理后图像的路径 * 返回值: 转换是否成功 **********************************************************************************/ BOOL CMyGDIDlg::ChangeImageAlpha(const CString& imagePath, REAL alpha, const CString& savePath) { Bitmap bitmap(imagePath); if (bitmap.GetLastStatus() != Ok) return false; int nWidth = bitmap.GetWidth(); int nHeight = bitmap.GetHeight(); // 构建新图像对象 Bitmap image(nWidth, nHeight); Rect rect(0, 0, nWidth, nHeight); // 利用新图像对象绘制 Graphics graph(&image); // 构建颜色变化矩阵 ColorMatrix colorMatrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, alpha, 0, 0, 0, 0, 0, 1 }; ImageAttributes imageAttr; imageAttr.SetColorMatrix(&colorMatrix); // 运用颜色变换矩阵绘制新图像 graph.DrawImage(&bitmap, rect, 0, 0, nWidth, nHeight, UnitPixel, &imageAttr); CLSID encoderClsid; // 文件编码器的CLSID CString strExt = savePath.Right(3); strExt.MakeLower(); // 根据扩展名获得不同的CLSID if (strExt == _T("png")) GetEncoderClsid(_T("image/png"), &encoderClsid); else if (strExt == _T("jpg")) GetEncoderClsid(_T("image/jpg"), &encoderClsid); else GetEncoderClsid(_T("image/bmp"), &encoderClsid); if (image.Save(savePath, &encoderClsid, NULL) == Ok) return true; else return false; }
调用: ChangeImageAlpha(_T("E:\\素材\\jpg\\1.jpg"), 0.5, _T("D:\\1.png"));
二、将图像转换为灰度图:原理就是使图中红、绿、蓝3个分量值相等。一般有3中方式:
(1)平均值法:使每个像素的三原色值等于红、绿、蓝3分量的平均值
R = G = B = (R + G +B) / 3
(2)最大值法:每个像素的三原色等于红、绿、蓝3分量的最大值
R = G = B = max(R, G, B)
(3)加权平均值法:给予红、绿、蓝3分量不同的权值然后相加
R = G = B = WrR + WgG + WbB
人眼对于三原色的敏感度从高到底分别是绿、红、蓝,所以三原色权值取值关系应该是 Wg > Wr > Wb。
依据YUV颜色空间可知当 R = G = B = 0.299R + 0.587 + 0.114B时能够的到最合理的灰度图。
算法与前文类似,在这里只需修改一下颜色变化矩阵即可:
// 构建颜色变化矩阵 ColorMatrix colorMatrix = { 0.299f, 0.299f, 0.299f, 0, 0, 0.587f, 0.587f, 0.587f, 0, 0, 0.114f, 0.114f, 0.114f, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 };
三、改变图像的亮度:是通过改变红、绿、蓝颜色分量的增量来实现的。公式如下:
// brightness 为亮度变化量 REAL f = brightness / 255.0f; // 构建颜色变化矩阵 ColorMatrix colorMatrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, f, f, f, 0, 1 };
四、改变图像的对比度:一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽;而对比度越小,则会让图画显得比较灰暗。
图像的对比度变化公式如下:其中f为对比度,默认为1.
Rt = 128 + (R - 128)f
Gt = 128 + (G -128)f
Bt = 128+ (B - 128)f
REAL f = 0.0f; if (contrast >= 0) f = (contrast + 10.0f) / 10.0f; else f = (255 + contrast) / 255.0f; // 构建颜色变化矩阵 ColorMatrix colorMatrix = { f, 0, 0, 0, 0, 0, f, 0, 0, 0, 0, 0, f, 0, 0, 0, 0, 0, 1, 0, 0.5f*(1-f), 0.5f*(1 - f), 0.5f*(1 - f), 0, 1 };