1.读入一幅RGB图象,编写程序显示图象中任一象素点的RGB值。
2.利用C++语言编写代码实现。
3.实现彩色图像的显示与RGB值的显示。
实验步骤:
-
搭建VS2019环境
-
安装MFC工具包
-
创建一个工程
-
完成界面布局
-
添加按键响应函数
程序清单1 添加按键按下的响应函数
void CMFCApplication1Dlg::OnBnClickedButtonOpenbmp()
{
// TODO: 在此添加控件通知处理程序代码
//
//打开文件
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.Seek(bmpHeader.bfOffBits,0);//这一步非常重要,必须要把文件指针偏移
bmpFile.Read(pBmpData, dataBytes); //存储图像数据
bmpFile.Close();
//显示图像
//guangjie2333的设计
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE); //获得pictrue控件窗口的句柄
CRect rect;
pWnd->GetClientRect(&rect); //获得pictrue控件所在的矩形区域
CDC* pDC = pWnd->GetDC(); //获得pictrue控件的DC
pDC->SetStretchBltMode(COLORONCOLOR);
StretchDIBits(pDC->GetSafeHdc(), 0, 0, rect.Width(), rect.Height(), 0, 0, bmpInfo.biWidth, bmpInfo.biHeight, pBmpData, pBmpInfo, DIB_RGB_COLORS, SRCCOPY);
//打印信息
TRACE(" rect.Width() = %d , rect.Height() = %d, bmpInfo.biWidth = %d , bmpInfo.biHeight = %d",rect.Width(), rect.Height(), bmpInfo.biWidth, bmpInfo.biHeight);
//X_Scale = bmpInfo.biWidth / rect.Width();
//Y_Scale = bmpInfo.biHeight / rect.Height();
}
}
}
- 添加鼠标移动响应函数
程序清单2 添加鼠标移动的响应函数
void CMFCApplication1Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//guangjie2333的设计
CDialogEx::OnMouseMove(nFlags, point);
CRect pect;
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE);//IDC_PICTURE为控件ID号
pWnd->GetClientRect(&pect);
int high = pect.Height(); //返回高
int width = pect.Width(); //返回宽
TRACE("picture 控件长宽高信息 high = %d width = %d" , high, width);
//确保鼠标在图像内移动
if (point.x >= 12 && point.x<= 12 + width && point.y >= 74 && point.y <= 74 + high)
{
TRACE("捕捉到了鼠标移动,当前位置 X = %d Y = %d", point.x, point.y);
SetDlgItemInt(IDC_EDIT_X, point.x); //写入坐标值x
SetDlgItemInt(IDC_EDIT_Y, point.y); //写入坐标值y
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE); //获得pictrue控件窗口的句柄
CDC* pDC = pWnd->GetDC(); //获得pictrue控件的DC
HDC hDC = pDC->GetSafeHdc(); ;
COLORREF rgb = ::GetPixel(hDC, point.x, point.y); //相对坐标
int r = GetRValue(rgb); //获得灰度分量
int g = GetGValue(rgb);
int b = GetBValue(rgb);
SetDlgItemInt(IDC_EDIT_R, r); //写入灰度分量R
SetDlgItemInt(IDC_EDIT_G, g); //写入灰度分量G
SetDlgItemInt(IDC_EDIT_B, b); //写入灰度分量B
}
else
{
SetDlgItemInt(IDC_EDIT_X, 0); //写入坐标值x
SetDlgItemInt(IDC_EDIT_Y, 0); //写入坐标值y
SetDlgItemInt(IDC_EDIT_R, 0); //写入灰度分量R
SetDlgItemInt(IDC_EDIT_G, 0); //写入灰度分量G
SetDlgItemInt(IDC_EDIT_B, 0); //写入灰度分量B
}
}
-
读取bmp图片
-
将鼠标放在图片区域内自动显示坐标和RGB
2021.10.5
我做后面的实验发现有些地方写的太死了
我对代码做了一些小优化
也改正了一个错误
还有一个需要注意的点就是: RGB格式的图像存储的顺序,并非像字面的顺序,而是以:B、G、R的顺序进行存储。
改正的错误
1.
获取rgb时采用的办法不太明智,改进如下
然而真正的问题在于鼠标的相对位置不对
void CMFCApplication1Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//guangjie2333的设计
//需要注意的是图像存在伸缩,需要更具伸缩比例确定
CDialogEx::OnMouseMove(nFlags, point);
CRect pect;
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE);//IDC_PICTURE为控件ID号
pWnd->GetClientRect(&pect);
int high = pect.Height(); //返回高
int width = pect.Width(); //返回宽
TRACE("picture 控件长宽高信息 high = %d width = %d" , high, width);
//确保鼠标在图像内移动
if (point.x >= 12 && point.x<= 12 + width && point.y >= 74 && point.y <= 74 + high)
{
TRACE("捕捉到了鼠标移动,当前位置 X = %d Y = %d", point.x, point.y);
SetDlgItemInt(IDC_EDIT_X, point.x); //写入坐标值x
SetDlgItemInt(IDC_EDIT_Y, point.y); //写入坐标值y
/*HDC hDC = ::GetDC(NULL);
GetCursorPos(&point);
COLORREF rgb = ::GetPixel(hDC, point.x, point.y ); //后两个参数是相对坐标
*/
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE); //获得pictrue控件窗口的句柄
CDC* pDC = pWnd->GetDC(); //获得pictrue控件的DC
HDC hDC = pDC->GetSafeHdc(); ;
COLORREF rgb = ::GetPixel(hDC, point.x-12, point.y-74); //相对坐标
int r = GetRValue(rgb); //获得灰度分量
int g = GetGValue(rgb);
int b = GetBValue(rgb);
SetDlgItemInt(IDC_EDIT_R, r); //写入灰度分量R
SetDlgItemInt(IDC_EDIT_G, g); //写入灰度分量G
SetDlgItemInt(IDC_EDIT_B, b); //写入灰度分量B
}
else
{
SetDlgItemInt(IDC_EDIT_X, 0); //写入坐标值x
SetDlgItemInt(IDC_EDIT_Y, 0); //写入坐标值y
SetDlgItemInt(IDC_EDIT_R, 0); //写入灰度分量R
SetDlgItemInt(IDC_EDIT_G, 0); //写入灰度分量G
SetDlgItemInt(IDC_EDIT_B, 0); //写入灰度分量B
}
}
进行的优化
在 MFCApplication1Dlg.h 新建了一个管理信息头的结构体
同时在MFCApplication1Dlg.cpp中声明一下
相应位置就要改一下
改过后的代码
void CMFCApplication1Dlg::OnBnClickedButtonOpenbmp()
{
// TODO: 在此添加控件通知处理程序代码
//
//打开文件
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; //记录图像信息头内容
//以只读的方式打开文件 读取bmp图片各部分 bmp文件头 信息 数据
if (!bmpdata.bmpFile.Open(BmpName, CFile::modeRead | CFile::typeBinary))
return;
if (bmpdata.bmpFile.Read(&bmpdata.bmpHeader, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER))
return;
if (bmpdata.bmpFile.Read(&bmpdata.bmpInfo, sizeof(BITMAPINFOHEADER)) != sizeof(BITMAPINFOHEADER))
return;
pBmpInfo = (BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER)];
//为图像数据申请空间
memcpy(pBmpInfo, &bmpdata.bmpInfo, sizeof(BITMAPINFOHEADER)); //存储图像信息头内容
DWORD dataBytes = bmpdata.bmpHeader.bfSize - bmpdata.bmpHeader.bfOffBits;//图像数据大小,单位为字节
bmpdata.pBmpData = (BYTE*)new char[dataBytes];
bmpdata.bmpFile.Seek(bmpdata.bmpHeader.bfOffBits,0);//这一步非常重要,必须要把文件指针偏移
bmpdata.bmpFile.Read(bmpdata.pBmpData, dataBytes); //存储图像数据
bmpdata.bmpFile.Close();
//显示图像
CWnd* pWnd = GetDlgItem(IDC_STATIC_PICTURE); //获得pictrue控件窗口的句柄
CRect rect;
pWnd->GetClientRect(&rect); //获得pictrue控件所在的矩形区域
CDC* pDC = pWnd->GetDC(); //获得pictrue控件的DC
pDC->SetStretchBltMode(COLORONCOLOR);
StretchDIBits(pDC->GetSafeHdc(), 0, 0, rect.Width(), rect.Height(), 0, 0, bmpdata.bmpInfo.biWidth, bmpdata.bmpInfo.biHeight, bmpdata.pBmpData, pBmpInfo, DIB_RGB_COLORS, SRCCOPY);
//打印信息
TRACE(" rect.Width() = %d , rect.Height() = %d, bmpInfo.biWidth = %d , bmpInfo.biHeight = %d",rect.Width(), rect.Height(), bmpdata.bmpInfo.biWidth, bmpdata.bmpInfo.biHeight);
}
}
}