(一)MFC读取并显示一幅位图图像,并获取鼠标点击位置的像素坐标和灰度值
题目是老师布置的一道作业题,要求用C或C++完成,但不能用VTK/Opencv等软件包,经过很多摸索之后实现了该功能,后续可能还有其他功能要实现,所以先写一篇博客记录下,一方面是方便自己以后使用,另一方面是给其他人做个参考,少走一些弯路。说不定以后学弟学妹们就看到了这篇博客(猜猜我是哪个学校的?)
一、作业要求
要求读取一幅位图图像,即BMP位图,并显示该图像在对话框内。鼠标点击该图像时,显示所点击的像素坐标值和RGB灰度分量。
编译环境:vs2015
二、实现步骤
(一)创建对话框MFC
选择基于对话框的MFC,其他后面的都是默认选项,所以可以直接点击完成即可。
点击完成之后出现如下对话框
把中间的对话框放大,把确定和取消两个botton修改为打开图片和保存图片,并增加一个图像控件框和五个编辑框,如下图所示
MFC创建就结束了
(二)添加程序
双击打开图片按钮添加程序,如下图所示
添加代码如下:
//打开文件
CString filter = (CString)"图像文件(*.bmp)|*.bmp;*.BMP||";//指明可供选择的文件类型和相应的扩展名
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter, NULL); //打开文件
//按下确定按钮 dlg.DoModal() 函数显示对话框
if (dlg.DoModal() == IDOK)
{
//打开对话框获取图像信息
CString BmpName = dlg.GetPathName(); //获取文件路径名
CString EntName = dlg.GetFileExt(); //获取文件扩展名
EntName.MakeLower(); //将文件扩展名转换为一个小写字符
if (EntName.Compare(_T("bmp")) == 0) //如果是bmp图片则打开显示
{
//定义变量存储图片信息
BITMAPINFO *pBmpInfo; //记录图像信息头内容
BYTE *pBmpData; //图像数据
BITMAPFILEHEADER bmpHeader; //文件头
BITMAPINFOHEADER bmpInfo; //信息头
CFile bmpFile; //记录打开文件
//以只读的方式打开文件 读取bmp图片各部分 bmp文件头 信息 数据
if (!bmpFile.Open(BmpName, CFile::modeRead | CFile::typeBinary))
return;
if (bmpFile.Read(&bmpHeader, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER))
return;
if (bmpFile.Read(&bmpInfo, sizeof(BITMAPINFOHEADER)) != sizeof(BITMAPINFOHEADER))
return;
pBmpInfo = (BITMAPINFO *)new char[sizeof(BITMAPINFOHEADER)];
//为图像数据申请空间
memcpy(pBmpInfo, &bmpInfo, sizeof(BITMAPINFOHEADER)); //存储图像信息头内容
DWORD dataBytes = bmpHeader.bfSize - bmpHeader.bfOffBits;//图像数据大小,单位为字节
pBmpData = (BYTE*)new char[dataBytes];
bmpFile.Read(pBmpData, dataBytes); //存储图像数据
bmpFile.Close();
//显示图像
CStatic *pwnd = (CStatic*)GetDlgItem(IDC_STATIC); //里面的参数是图片控件的ID
//pwnd->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
pwnd->ModifyStyle(0xf, SS_BITMAP);
pwnd->SetBitmap((HBITMAP)::LoadImage(GetModuleHandle(NULL), BmpName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));//打开图片
}
}
此时已经可以打开图片了,效果如下:
接下来天加显示坐标值和灰度值的代码:
在类向导里添加消息函数WM_LBUTTONDOWN
添加代码:
代码如下:
void CWJ_zuoye1Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
CWnd *pWnd = GetDlgItem(IDC_STATIC);
pWnd->GetWindowRect(&rect);
ScreenToClient(&rect);
//先获取鼠标相对于屏幕的坐标
GetCursorPos(&point);
int temp_x = point.x;
int temp_y = point.y;
//然后得到static控件的rect坐标
CRect pRect;
pWnd->GetClientRect(&pRect);
//最后把当前鼠标的坐标转化为相对于rect的坐标
pWnd->ScreenToClient(&point);
int x = point.x;
int y = point.y;
SetDlgItemInt(IDC_EDIT1, x); //写入坐标值
SetDlgItemInt(IDC_EDIT2, y); //写入
HDC hDC = ::GetDC(NULL);
COLORREF rgb = ::GetPixel(hDC, temp_x, temp_y);
int r = GetRValue(rgb);
int g = GetGValue(rgb);
int b = GetBValue(rgb);
SetDlgItemInt(IDC_EDIT3, r); //写入
SetDlgItemInt(IDC_EDIT4, g); //写入
SetDlgItemInt(IDC_EDIT5, b); //写入
CDialogEx::OnLButtonDown(nFlags, point);
}
编辑运行:
大概就是这么个情况,时间有限,下一篇我将讲一下上面的代码含义以及相关引用 ,对代码含义有要求的同学可以看我的下篇博客