为图像添加色彩滤镜在数字图像处理领域的名称为伪彩色编码。它是通过把灰度图像或黑白图像赋予特殊的调色板来实现的。我们知道,对于灰度图像,其RGB值均相等,即对于图像中的任意一个象素,其红色分量取值=绿色分量取值=蓝色分量取值。
256级灰度图的一般码表为:
{ // 常规灰度编码
{ 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } , //4 { 4, 4, 4 }, { 5, 5, 5 }, { 6, 6, 6 }, { 7, 7, 7 }, //8 { 8, 8, 8 }, { 9, 9, 9 }, { 10, 10, 10 }, { 11, 11, 11 }, //12 { 12, 12, 12 }, { 13, 13, 13 }, { 14, 14, 14 }, { 15, 15, 15 }, //16 { 16, 16, 16 }, { 17, 17, 17 }, { 18, 18, 18 }, { 19, 19, 19 }, //20 { 20, 20, 20 }, { 21, 21, 21 }, { 22, 22, 22 }, { 23, 23, 23 }, //24 … … … … { 228,228,228 }, { 229,229,229 }, { 230,230,230 }, { 231,231,231 }, //232 { 232,232,232 }, { 233,233,233 }, { 234,234,234 }, { 235,235,235 }, //236 { 236,236,236 }, { 237,237,237 }, { 238,238,238 }, { 239,239,239 }, //240 { 240,240,240 }, { 241,241,241 }, { 242,242,242 }, { 243,243,243 }, //244 { 244,244,244 }, { 245,245,245 }, { 246,246,246 }, { 247,247,247 }, //248 { 248,248,248 }, { 249,249,249 }, { 250,250,250 }, { 251,251,251 }, //252 { 252,252,252 }, { 253,253,253 }, { 254,254,254 }, { 255,255,255 }, //256 }//规律:R=G=B=i, for i=0 to 255 |
3 编程部分
下面我们以256级灰度图"angel.bmp"为例,给出用VC++ 6.0编写的主要步骤和关键函数,程序在PC机的Windows 2000 环境中调试通过,并取得了良好的色彩效果。
(1)建立主界面
在VC的MFC Appwizard向导下建立一个single document型的工程,其中CFunnyView的基类为CformView,修改菜单属性,如图1的主界面。
图 1
单击主界面中"彩色编码"菜单时,执行的函数:
void CFunnyGlassView::OnEnhaColor()
{ // TODO: Add your command handler code here // 伪彩色编码 // 获取文档 CFunnyGlassDoc* pDoc = GetDocument(); int nColor; // 保存用户选择的伪彩色编码表索引 LPSTR lpDIB; // 指向DIB的指针 lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 锁定DIB // 判断是否是8-bpp位图(只处理256色位图的伪彩色变换,其它的可以类推) CDlgColor dlgPara; // 参数对话框 // 初始化变量值 if (pDoc->m_nColorIndex >= 0) { // 初始选中当前的伪彩色 dlgPara.m_nColor = pDoc->m_nColorIndex; } else { // 初始选中灰度伪彩色编码表 dlgPara.m_nColor = 0; } // 指向名称数组的指针 dlgPara.m_lpColorName = (LPSTR) ColorScaleName; // 伪彩色编码数目 dlgPara.m_nColorCount = COLOR_SCALE_COUNT; // 名称字符串长度 dlgPara.m_nNameLen = sizeof(ColorScaleName) / COLOR_SCALE_COUNT; // 显示对话框,提示用户设定平移量 if (dlgPara.DoModal() != IDOK) { return; // 返回 } nColor = dlgPara.m_nColor; // 获取用户的设定 delete dlgPara; // 删除对话框 BeginWaitCursor(); // 更改光标形状 // 判断伪彩色编码是否改动 if (pDoc->m_nColorIndex != nColor) { // 调用ReplaceColorPal()函数变换调色板 ::ReplaceColorPal(lpDIB, (BYTE*) ColorsTable[nColor]); pDoc->GetDocPalette()->SetPaletteEntries(0, 256, (LPPALETTEENTRY) ColorsTable [nColor]); // 替换当前文档调色板 pDoc->m_nColorIndex = nColor; // 更新类成员变量 // 设置脏标记 pDoc->SetModifiedFlag(TRUE); OnDoRealize((WPARAM)m_hWnd,0); // 实现新的调色板 pDoc->UpdateAllViews(NULL); // 更新视图 } ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());// 解除锁定 EndWaitCursor(); // 恢复光标 } |
(2)建立新对话框
添加标识为"IDC_Color_List"的对话框,标题为"请选择滤镜颜色:"并在其中添加一个listbox控件和两个命令按钮"OK"和"CANCEL"。
如图2
对话框IDC_Color_List中处理的主要函数:
I、初始化对话框
BOOL CDlgColor::OnInitDialog()
{ CDialog::OnInitDialog(); int i; // 添加伪彩色编码 for (i = 0; i < m_nColorCount; i++) { m_lstColor.AddString(m_lpColorName + i * m_nNameLen); } // 选中初始编码表 m_lstColor.SetCurSel(m_nColor); return TRUE; // // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } |
II、当用户确定所选码表时,执行以下函数:
void CDlgColor::OnOK()
{ // TODO: Add extra validation here // 用户单击确定按钮 m_nColor = m_lstColor.GetCurSel(); CDialog::OnOK(); } |
// 编码表个数
#define COLOR_SCALE_COUNT 6 // 编码表名称 const char ColorScaleName[COLOR_SCALE_COUNT][64] = { " 1 常规灰度编码", " 2 逆灰度编码", " 3 红色饱和度编码", " 4 绿色饱和度编码", " 5 蓝色饱和度编码", " 6 黄色饱和度编码", " 7 青色饱和度编码", " 8 紫色饱和度编码", }; // 编码表RGB数组 const BYTE ColorsTable[COLOR_SCALE_COUNT][256][4] = { { // 红色饱和度编码 { 0, 0, 0 }, { 1, 0, 0 }, { 2, 0, 0 }, { 3, 0, 0 }, //4 { 4, 0, 0 }, { 5, 0, 0 }, { 6, 0, 0 }, { 7, 0, 0 }, //8 { 8, 0, 0 }, { 9, 0, 0 }, { 10, 0, 0 }, { 11, 0, 0 }, //12 { 12, 0, 0 }, { 13, 0, 0 }, { 14, 0, 0 }, { 15, 0, 0 }, //16 { 16, 0, 0 }, { 17, 0, 0 }, { 18, 0, 0 }, { 19, 0, 0 }, //20 … … … … { 224, 0, 0 }, { 225, 0, 0 }, { 226, 0, 0 }, { 227, 0, 0 }, //228 { 228, 0, 0 }, { 229, 0, 0 }, { 230, 0, 0 }, { 231, 0, 0 }, //232 { 232, 0, 0 }, { 233, 0, 0 }, { 234, 0, 0 }, { 235, 0, 0 }, //236 { 236, 0, 0 }, { 237, 0, 0 }, { 238, 0, 0 }, { 239, 0, 0 }, //240 { 240, 0, 0 }, { 241, 0, 0 }, { 242, 0, 0 }, { 243, 0, 0 }, //244 { 244, 0, 0 }, { 245, 0, 0 }, { 246, 0, 0 }, { 247, 0, 0 }, //248 { 248, 0, 0 }, { 249, 0, 0 }, { 250, 0, 0 }, { 251, 0, 0 }, //252 { 252, 0, 0 }, { 253, 0, 0 }, { 254, 0, 0 }, { 255, 0, 0 }, //256 },// 规律:R=i,G=B=0;i=0 to 255 { // 绿色饱和度编码
{ // 蓝色饱和度编码
{ // 黄色饱和度编码
{ // 青色饱和度编码
{ // 紫色饱和度编码
// 编码表结束
|