由于刚开始接触MFC,做一个简单的图片读取并且转成灰度图,同时进行边缘检测任务,后续可能在此基础上在进行改进,我目前做的是直接用代码生成一个对话框,不是在资源里面添加对话框
一、创建VS程序
首先创建一个文件打开事件处理程序,这样就可以使用文件下面的打开按钮打开一张自己想要的图片,在资源文件中右键查看.rc代码



右键双击打开→添加事件处理程序→选择View

接下来就可以在这里面操作了,首先我随便响应了一个AfxMessageBox消息框来验证是否成功,在这里还需要将字符集改成多字节字符集(右键→属性→高级)

**自己的想法:**在做一些简单的图像算法处理的时候,我将对话框和图像算法的代码都放在imageshowView.cpp里面进行操作,这样操作不好的一个地方是所有代码都在同一个地方,非常乱,不方便后续操作,因此在这个基础上进行了改进:对话框和图像算法都单独作为.cpp来进行创建,然后再在imageshowView.cpp进行调用展示即可。
补充一下自己的做法(这种做法感觉有点复杂):
cpp
void CimageshowView::OnDraw(CDC* pDC)
{
CimageshowDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if (0 == s_fOpenFile) {
return;
}
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = img_w;
bmi.bmiHeader.biHeight = img_h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
SetDIBitsToDevice(
pDC->m_hDC,
0, 0,
img_w, img_h,
0, 0,
0,
img_h,
img_rgb,
&bmi,
DIB_RGB_COLORS);
}
void RgbToYuv(int w, int h, BYTE* imgRGB1, BYTE* imgGray1)
{
BYTE* pSrc = imgRGB1;
BYTE* pDst = imgGray1;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int B = pSrc[0];
int G = pSrc[1];
int R = pSrc[2];
int Y = (int)(0.299 * R + 0.587 * G + 0.114 * B);
pDst[0] = Y;
pDst[1] = Y;
pDst[2] = Y;
pSrc += 3;
pDst += 3;
}
}
}
void EdgeDetect(SIZE sz, PBYTE pSrcGray, PBYTE pDstGray)
{
ASSERT(pSrcGray);
ASSERT(pDstGray);
int w = sz.cx;
int h = sz.cy;
/*memset(pDstGray, 0, w * h);*/
for (int y = 1; y < h - 1; y++)
{
for (int x = 1; x < w - 1; x++)
{
int v00 = pSrcGray[(y - 1) * w + (x - 1)];
int v01 = pSrcGray[(y - 1) * w + x];
int v02 = pSrcGray[(y - 1) * w + (x + 1)];
int v10 = pSrcGray[y * w + (x - 1)];
int v11 = pSrcGray[y * w + x];
int v12 = pSrcGray[y * w + (x + 1)];
int v20 = pSrcGray[(y + 1) * w + (x - 1)];
int v21 = pSrcGray[(y + 1) * w + x];
int v22 = pSrcGray[(y + 1) * w + (x + 1)];
int g = 4 * v11 - v01 - v10 - v12 - v21;
if (g < 0) g = -g;
if (g > 255) g = 255;
pDstGray[y * w + x] = (BYTE)g;
}
}
}
void ShowEdgeImage(PSTR lpszTitle, SIZE sz, PBYTE pRGB)
{
ASSERT(pRGB);
int w = sz.cx;
int h = sz.cy;
int img_size = w * h;
ASSERT(w <= IMG_MAX_WIDTH && h <= IMG_MAX_HEIGTH && img_size <= IMG_MAX_SIZE);
static BYTE s_pGray[IMG_MAX_SIZE];
static BYTE s_pEdge[IMG_MAX_SIZE];
static BYTE s_pEdgeRGB[IMG_MAX_SIZE * 3];
PBYTE pGray = s_pGray;
PBYTE pEdge = s_pEdge;
RgbToYuv(w, h, pRGB, s_pEdgeRGB);
for (int i = 0; i < img_size; i++)
{
pGray[i] = s_pEdgeRGB[i * 3];
}
EdgeDetect(sz, pGray, pEdge);
for (int i = 0; i < img_size; i++)
{
BYTE e = pEdge[i];
s_pEdgeRGB[i * 3 + 0] = e;
s_pEdgeRGB[i * 3 + 1] = e;
s_pEdgeRGB[i * 3 + 2] = e;
}
CImageDlg dlg(AfxGetMainWnd(), lpszTitle, sz, s_pEdgeRGB, 24);
dlg.DoModal();
}
对上述进行了改进
二、将一幅彩色图像转换为灰度图像,并显示
1、单独创建一个对话框,用来显示各种图片(imgdlg.cpp和imgdlg.h)
.cpp
cpp
CImageDlg::CImageDlg(CWnd* pParent, PSTR lpszTitle, SIZE sz, PBYTE pImg, int nBPP)
: CDialog()
{
m_pWndFocus = GetFocus(); // 保存当前焦点窗口,关闭时还原
int cbBytes = sizeof(DLGTEMPLATE) + 4096; // 在内存中构造一个对话框模板
m_hdt = GlobalAlloc(GMEM_FIXED, cbBytes); // GMEM_FIXED分配固定地址内存
DLGTEMPLATE* pdt = (DLGTEMPLATE*)GlobalLock(m_hdt); // 锁定内存并获得可写指针
memset(pdt, 0, cbBytes);
pdt->style = DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU;
pdt->dwExtendedStyle = 0;
GlobalUnlock(m_hdt);
strcpy_s(m_szTitle, lpszTitle); // 安全版本:保存标题到成员变量
m_szImg = sz;
ASSERT(8 == nBPP || 24 == nBPP);
m_nBPP = nBPP; // 保存图像位深
int rgb_bytes = sz.cx * sz.cy * 3;
m_pRGB = (PBYTE)malloc(rgb_bytes);
ASSERT(m_pRGB);
memcpy(m_pRGB, pImg, rgb_bytes); // 复制图像数据到成员缓冲区
BOOL code = InitModalIndirect(m_hdt, pParent); // 初始化模态对话框
// 构造右键弹出菜单
m_menuCmd.CreatePopupMenu();
// 循环:数组总字节数 / 单个元素字节数 = 元素个数
for (int i = 0; i < sizeof(menuid) / sizeof(menuid[0]); i++) {
PPOPUPMENUID lpmi = &menuid[i]; // 取得当前菜单项的指针
int flag = MF_BYPOSITION | lpmi->nFlag;
// 插入菜单项,后面在OnRButtonDown里会被弹出显示
m_menuCmd.InsertMenu(0, flag, lpmi->idCmd, lpmi->lpszItem);
}
}
CImageDlg::~CImageDlg()
{
if (m_pRGB) {
free(m_pRGB);
m_pRGB = 0;
}
m_menuCmd.DestroyMenu();
if (m_hdt) {
GlobalFree(m_hdt);
}
}
2、简单的图像处理算法
方案一:单独创建RgbToYuv.cpp的代码如下:

.h

我想的是直接在.cpp里面创建一个类来继承CImageDlg,然后在view.cpp里面进行调用

这样写出来又存在一个问题,每次使用时都得写一个DoModal()来调用对话框,而且前面我已经写了一个对话框来显示图片了,所以这里就很多余,我又进行了改进
方案二:RgbToYuv.cpp

RgbToYuv.h

view.cpp

这样写下来和方案一差不多,每次都在调用
方案三(最佳):RgbToYuv.cpp

.h

view.cpp

这种方案就直接在view.cpp中调用RgbToYuv和ShowGrayImage函数来显示对话框里面的图像了,就不用像之前两种方案里面那样每次都得调用一个对话框。
运行结果如下:

总结:在学习这个之前得先了解c++和mfc的一些相关知识,不然就会搞得很复杂,没有逻辑。如果有更好的解决办法可以多多交流!