读入一幅RGB图象,编写程序显示图象中任一象素点的RGB值。

1.读入一幅RGB图象,编写程序显示图象中任一象素点的RGB值。
2.利用C++语言编写代码实现。
3.实现彩色图像的显示与RGB值的显示。

实验步骤:

  1. 搭建VS2019环境

  2. 安装MFC工具包

  3. 创建一个工程

  4. 完成界面布局

  5. 添加按键响应函数

程序清单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();
		}
	}
}

  1. 添加鼠标移动响应函数

程序清单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
	}
}


  1. 读取bmp图片

  2. 将鼠标放在图片区域内自动显示坐标和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);
			

		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鄢广杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值