OpenCV与MFC混合编程中的图像格式转换研究

OpenCV作为主流的计算机视觉库,其图像处理、特征检测、视频分析等算法能力强大,被广泛应用于视觉项目开发。但 OpenCV的核心图像容器Mat属于纯数据矩阵格式,仅用于算法运算和数据处理,无法直接在对话框、静态图片框、视图等 MFC 常用控件中渲染显示。

而CImage是MFC 框架提供的原生图像类,完美适配 Windows 图形接口,支持在 MFC 各类控件上直接绘制、显示、保存图像(BMP/JPG/PNG 等格式),是VC++界面端展示图像的标准载体。因此,实现Mat与CImage的双向格式转换,是OpenCV 算法处理后的图像能在 MFC 对话框界面可视化的前提。

要想实现CImage与Mat的相互转换,首先需要明确的是两者数据布局、通道顺序及内存结构上的异同,才能构建出稳定、无错配的转换逻辑,从而使得OpenCV的算法结果能在MFC界面上完美呈现。

一、OpenCV::Mat的基础属性

OpenCV::Mat有五大基础属性:rows(行数)、cols(列数)、dims(维度)、channels(通道数)、type(数据类型)是描述矩阵形态的五大基础属性。同时,掌握Mat数据指针的正确访问方式,是实现格式互转的基本操作。

1.1 rows/cols --- 矩阵的行与列

行与列是二维矩阵的专属属性,对应的是图像空间尺寸:

  1. rows:矩阵的行数,对应的是图像的高度
  2. cols:矩阵的列数,对应的是图像的高度

注意,只有当该矩阵为二维矩阵时,这两个属性才有效。这两个参数直接决定了图像在MFC应用中显示的尺寸。

1.2 dims --- 矩阵维度

矩阵有多维的,但图像一般都是二维的,因此dims一般为2。然而OpenCV的三维重建技术可能需要描述三维图像。

1.3 channels --- 通道数

图像通道数描述的是每个像素点是由几个数值分量组成的,是区分彩色图和灰度图的关键。

  1. channels=1:灰度图,每个像素仅一个亮度值
  2. channels=3:彩色图,通常为BGR三通道
  3. channels=4:在BGR三通道的基础上增加透明度,采用BGRA格式

在图像格式转换中,通道数直接决定了图像创建的格式(8位/24位/32位),同时需要注意BGR与RGB之间的通道顺序转换。

1.4 type --- 数据类型

Mat的数据类型是定义矩阵中每个像素值的存储格式、位数、通道数的核心标识。Mat数据类型的命名是有固定统一规范的(CV_位数+数据类型+C通道数),如CV_8UC1。

位数表示每个数值占用的二进制位数;数据类型主要有三个选择(U表示无符号整数;S代表有符号整数;F代表浮点型);通道数表示每个像素包含的分量数(同1.3)

在图像格式转换中,常用的数据类型只有CV_8UC1、CV_8UC3、CV_8UC4三种。

二、OpenCV::Mat数据指针的访问方法

Mat::data是Mat像素数据的首地址指针,指向矩阵内存块的起始地址。用户可通过该指针直接读写内存。

Mat::ptr<uchar>[i]是第i行数据的起始指针,该指针能自动处理行对齐补齐问题,从而避免内存越界,是像素访问的最常用安全的方式。

Mat::step是指矩阵中每一行占用的总字节数,包含对齐补齐的字节。

三、CImage的基础属性

CImage是MFC提供的一个功能强大图像处理类,封装了加载、保存、绘制和像素访问等功能,是连接图像文件与界面控件的核心桥梁。

CImage最常用的成员包括Load、Create、Destory等用于生命周期管理;Draw、StretchBlt用于图像显示;GetBits、GetPixelAddress用于直接像素操作。

CImage封装了获取图像基本信息的方法,是格式转换的关键依据:

  1. GetWidth()/GetHeight():获取图像的宽度和高度,等同于Mat的cols和rows;
  2. GetBPP():获取每像素的位数,决定了图像的颜色深度(8位,24位,32位),等同于Mat的channels;
  3. GetPitch:获取图像每行的字节跨度(包含内存对齐字节),等同于Mat::step
  4. GetBits():获取指向像素数据缓冲区的首指针,用于直接操作像素,等同于Mat的Mat::data,下面再详细介绍;

CImage提供了增强型的(DDB和DIB)位图支持,可以装入、显示、转换和保存多种格式的图像文件,包括BMP、GIF、JPG、PNG、TIF等

3.1 设备无关位图(DIB)

DIB是一种旨在保证图像在不同显示设备上保持一致外观的位图格式。其核心特点是不依赖于特定硬件的颜色格式、分辨率或调色板,而是通过内嵌的元信息(如颜色表、分辨率、位深度等)来实现跨平台、跨设备的图像一致性。颜色表即调色板。

CImage的调色板主要用于索引颜色模式的图像,如8位的BMP图像,这种图像最多支持256种颜色,通过颜色表映射像素值到实际的RGB颜色。调色板仅用于单通道图像,对于多通道图像,像素值通常直接存储颜色信息,无需通过颜色表确定颜色。

DIB的图像有两种存储方式:Top-Down与Bottom-Up。对于Bottom-Up位图,在内存中是从位图的底部行开始保存,然后一行接着一行,直到位图顶部。因而,内存空间的起始处为图像的左下角像素点。在GDI中,所有的位图都是Bottom-Up类型的位图。对于Top-Down位图,它在内存中的保存顺序是相反的。位图的顶部行保存在内存空间的开始处。因而,内存空间的起始处为图像的左上角像素点。DirectDraw编程采用是Top-Down类型位图。在位图结构体(BITMAPINFOHEADER.biHeight)中可设置该图像的存储方式, biHeight= TRUE,则表示Bottom-Up类型,反之为Top-Down类型。

3.2 CImage的调色板

CImage的调色板本质上是一个由256个RGBQUAD结构组成的颜色表,每个索引对应一组RGB颜色,决定了像素最终显示效果。

调色板主要应用于8位灰度图像展示,24位/32位的真彩色未采用调色板,像素直接存储RGB/RGBA值,无需调色板映射。

CImage可用函数GetColorTable读取调色板颜色表,并用SetColorTable设置调色板颜色表。

四、函数源码

cpp 复制代码
void MatToCImage(Mat& mat, CImage& cImage)
{
	int channels = mat.channels();
	if (!(channels == 1 || channels == 3))
		return;
	int width = mat.cols;
	int height = mat.rows;
	cImage.Destroy();					//这一步是防止重复利用造成内存问题
	cImage.Create(width, height, 8 * channels);
	uchar* ps;
	uchar* pimg = (uchar*)cImage.GetBits();//获取CImage的像素存贮区的指针
	int step = cImage.GetPitch();	//每行的字节数,注意这个返回值有正有负

	// 如果是1个通道的图像(灰度图像) DIB格式才需要对调色板设置  
	// CImage中内置了调色板,我们要对他进行赋值:
	if (1 == channels)
	{	RGBQUAD ColorTable[256];
		for (int i = 0; i < 256; i++)
		{
			ColorTable[i].rgbBlue = (BYTE)i;
			ColorTable[i].rgbGreen = (BYTE)i;
			ColorTable[i].rgbRed = (BYTE)i;
			ColorTable[i].rgbReserved = 0;
		}
		cImage.SetColorTable(0, 256, ColorTable);
	}
	for (int i = 0; i < height; i++)
	{	ps = mat.ptr<uchar>(i);
		for (int j = 0; j < width; j++)
		{	if (1 == channels)
				*(pimg + i * step + j) = ps[j];
			else if (3 == channels)
			{	*(pimg + i * step + j * 3) = ps[j * 3];
				*(pimg + i * step + j * 3 + 1) = ps[j * 3 + 1];
				*(pimg + i * step + j * 3 + 2) = ps[j * 3 + 2];
			}
		}
	}
}
相关推荐
Raink老师7 小时前
【AI面试临阵磨枪】Harness 的环境隔离(沙箱)如何设计?文件、网络、命令、权限四层隔离?
人工智能·ai 面试
人工智能AI技术8 小时前
Python 断言 assert 基础用法
人工智能
我是发哥哈8 小时前
横向评测:五款主流AI培训课程效果与选型分析
人工智能
GetcharZp8 小时前
告别昂贵显卡!llama.cpp 终极指南:在你的电脑上满速运行大模型!
人工智能
AI木马人8 小时前
3.【Prompt工程实战】如何设计一个可复用的Prompt系统?(避免每次手写提示词)
linux·服务器·人工智能·深度学习·prompt
Agent产品评测局9 小时前
临床前同源性反应种属筛选:利用AI Agent加速筛选的实操方案 —— 2026企业级智能体选型与技术落地指南
人工智能·ai·chatgpt
ting94520009 小时前
HunyuanOCR 全方位深度解析
人工智能·架构
woai33649 小时前
AI通识-大模型的原理&应用
人工智能
头发够用的程序员9 小时前
从滑动窗口到矩阵运算:img2col算法基本原理
人工智能·算法·yolo·性能优化·矩阵·边缘计算·jetson