本文搭建一个基于MFC的图像显示平台,供同学们在学习数字图像处理的时候应用纯C++编写代码验证各类图像处理算法,以区别于其他使用高层图像处理库的平台。
博文03. 用C++类和对象封装BMP显示的相关代码介绍了如何利用MFC框架读取和显示BMP图像的问题,在此基础上,本文用一个图像取反算法来演示如何编写C++代码编写数字图像算法并立即展示效果。
首先,我们新建一个名为mfc_dsp_base
的MFC单文档工程,具体方法参见之前的博文。仿照博文博文03. 用C++类和对象封装BMP显示的相关代码添加CBmp类。
接下来我们继续添加一个方便添加数字图像处理算法的类CImageProcess
,系统为我们添加两个文件CImageProcess.h
和CImageProcess.cpp
。
CImageProcess.h
的内容修改文件CImageProcess.h
的内容如下,除了构造函数和析构函数,添加了彩色图像变换为灰度图像的函数Color2Gray
和图像取反的函数imgNegative
作为示例。
#pragma once
class CImageProcess
{
public:
CImageProcess();
~CImageProcess();
public:
int Color2Gray(unsigned char* R, unsigned char* G, unsigned char* B,
int bmpWidth, int bmpHeight, unsigned char* gray_img);
int imgNegative(unsigned char* gray_img,
int bmpWidth, int bmpHeight);
};
CImageProcess.cpp
的内容修改文件CImageProcess.cpp
的内容如下,具体实现函数Color2Gray
和imgNegative
。
#include "pch.h"
#include "CImageProcess.h"
CImageProcess::CImageProcess(){}
CImageProcess::~CImageProcess(){}
//colorful image
//加权平均法
// I(x, y) = 0.3 * I_R(x, y) + 0.59 * I_G(x, y) + 0.11 * I_B(x, y)
int CImageProcess::Color2Gray(unsigned char* R, unsigned char* G, unsigned char* B, int bmpWidth, int bmpHeight, unsigned char* gray_img)
{
double r,g,b;
double gray;
for (int i = bmpHeight - 1; i >= 0; i--)
for (int k = 0; k < bmpWidth; k++) {
r = (double)R[i * bmpWidth + k];
g = (double)G[i * bmpWidth + k];
b = (double)B[i * bmpWidth + k];
gray = 0.3 * r + 0.59 * g + 0.11 * b;
gray_img[i * bmpWidth + k] = (unsigned char)gray;
}
return 0;
}
int CImageProcess::imgNegative(unsigned char* gray_img, int bmpWidth, int bmpHeight)
{
for (int i = bmpHeight - 1; i >= 0; i--)
for (int k = 0; k < bmpWidth; k++) {
gray_img[i * bmpWidth + k] = 255-gray_img[i * bmpWidth + k];
}
return 0;
}
有了这个基础类,我们就可以方便的在CView等界面代码中添加图像处理的代码。我们添加鼠标左键点击和右键点击两个Windows消息到工程中,在鼠标右键点击消息中添加显示原图的功能,在鼠标左键点击消息对原图取反再显示。
#include "Bmp.h"
#include "CImageProcess.h"
CImageProcess imgProcess;
CBmp bmp;
void CmfcdspbaseView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//要绘制的图像文件名
char bmpName[] = "3.bmp";
unsigned char* red_channel = new unsigned char[1920 * 1080];
unsigned char* green_channel = new unsigned char[1920 * 1080];
unsigned char* blue_channel = new unsigned char[1920 * 1080];
unsigned char* gray = new unsigned char[1920 * 1080];
int bmpWidth = 0;
int bmpHeight = 0;
int biBitCount = 0;
int lineByte = 0;
//read bmp image
bmp.readBmp(bmpName, red_channel, green_channel, blue_channel,&bmpWidth, &bmpHeight);
imgProcess.Color2Gray(red_channel, green_channel, blue_channel, bmpWidth, bmpHeight, gray);
imgProcess.imgNegative(gray, bmpWidth, bmpHeight);
//合并绘制三个通道的图像
CClientDC dc(this);
CDC* pDC = &dc;
int offset_left = point.x;
int offset_top = point.y;
bmp.print_matrix(pDC,
gray,
bmpWidth, bmpHeight,
offset_left, offset_top);
//important to clear the memory used
delete[] red_channel;
delete[] green_channel;
delete[] blue_channel;
delete[] gray;
CView::OnLButtonDown(nFlags, point);
}
void CmfcdspbaseView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//要绘制的图像文件名
char bmpName[] = "3.bmp";
unsigned char* red_channel = new unsigned char[1920 * 1080];
unsigned char* green_channel = new unsigned char[1920 * 1080];
unsigned char* blue_channel = new unsigned char[1920 * 1080];
unsigned char* gray = new unsigned char[1920 * 1080];
int bmpWidth = 0;
int bmpHeight = 0;
int biBitCount = 0;
int lineByte = 0;
//read bmp image
bmp.readBmp(bmpName, red_channel, green_channel, blue_channel, &bmpWidth, &bmpHeight);
imgProcess.Color2Gray(red_channel, green_channel, blue_channel, bmpWidth, bmpHeight, gray);
//imgProcess.imgNegative(gray, bmpWidth, bmpHeight);
//合并绘制三个通道的图像
CClientDC dc(this);
CDC* pDC = &dc;
int offset_left = point.x;
int offset_top = point.y;
bmp.print_matrix(pDC,
gray,
bmpWidth, bmpHeight,
offset_left, offset_top);
//important to clear the memory used
delete[] red_channel;
delete[] green_channel;
delete[] blue_channel;
delete[] gray;
CView::OnRButtonDown(nFlags, point);
}
这样就实现了一个简单的基于MFC的数字图像处理算法验证平台,以后可以添加新的算法到CImageProcess
里面,方法仿照imgNegative
即可。