打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
MFC:CImage显示OpenCV:Mat矩阵图像
 自从开始学C++的OpenCV,就想把问题都用一个简单的类来解决。原来使用VC6.0使用的是StretchDIBits这类函数来画图,一旦画新的图像或者显示多张位图,势必遇到多次对环境的调色板重新加载。如今都已经VS2010,MFC下的图像显示功能有所加强。使用MFC下的CImage类(貌似VC2005开始支持)可以很轻松的和快速的在MFC下显示图像;(到底是不是很快速还需要更多的考证,但把已经存在的Mat矩阵lena图像显示出来,使用getTimeGet函数测得,貌似低于1ms)。由于网上太多杂乱的内容和很多不够详细的讲解,让我尝试了一天,才把彩色和灰度图像正确显示到界面上。
    我这里使用C++的OpenCV,如果你使用c语言的OpenCV一样可以实现出来。

1.读入Mat矩阵(cvMat一样),Mat img=imread("*.*");//cvLoadImage
确保转换前矩阵中的数据都是uchar(0~255)类型(不是的话量化到此区间),这样才能显示。(初学者,包括我经常忘了此事)
2.根据矩阵大小创建(CImage::Create)新的的CImage类
CImage CI;
int w=img.cols;//宽
int h=img.rows;//高
int chinnels=img.channels();//通道数
CI.Destroy();//创建前,最好使用它,防止重复创建,程序崩溃
CI.Create(w,h,8*chinnels);

3.下来就是对CI进行赋值了,这里是最核心的地方,分二类讨论
(1)如果是1个通道的图像(灰度图像)
CImage中内置了调色板,我们要对他进行赋值:
                RGBQUAD* ColorTable;
                int MaxColors=256;
//这里可以通过CI.GetMaxColorTableEntries()得到大小(如果你是CI.Load读入图像的话)
                ColorTable = new RGBQUAD[MaxColors];
                CI.GetColorTable(0,MaxColors,ColorTable);//这里是取得指针
                for (int i=0; i<MaxColors; i++)
                {
                        ColorTable.rgbBlue = (BYTE)i;
                //BYTE和uchar一回事,但MFC中都用它
                        ColorTable.rgbGreen = (BYTE)i;
                        ColorTable.rgbRed = (BYTE)i;
                }
                CI.SetColorTable(0,MaxColors,ColorTable);
                delete []ColorTable;
然后就是数据拷贝了(这里的矩阵表示方法,根据需要(cvMat or Mat)修改):
        if(chinnels==1)
        {//灰度图像
                uchar *pS;
                uchar *pImg=(uchar *)CI.GetBits();
                int step=CI.GetPitch();
                for(int i=0;i<h;i++)
                {
                        pS=img.ptr<uchar>(i);
                        for(int j=0;j<w;j++)
                        {
                        *(pImg+i*step+j)=pS[j];
                        }
                }
        }
(2)如果是3个通道(彩色图像)
没有调色板,直接赋值
        if(chinnels==3)
        {//彩色图像
                uchar *pS;
                uchar *pImg=(uchar *)CI.GetBits();//得到CImage数据区地址
                int step=CI.GetPitch();
//这个是一行像素站的存储空间w*3,并且结果是4的倍数(这个不用关注,到底是不是4的倍数有待考证)
                for(int i=0;i<h;i++)
                {
                        pS=img.ptr<uchar>(i);
                        for(int j=0;j<w;j++)
                        {
                                for(int k=0;k<3;k++)
                                  *(pImg+i*step+j*3+k)=pS[j*3+k];
                        //注意到这里的step不用乘以3
                        }
                }
        }
4.至此已经构建好CImage,下来就是显示它。我们可以直接在对话框、单文档等地方显示他,还可以使用CPictureCtrl空间显示他。下面给出几个显示方法:
//显示前,这里有个问题,等会讨论
(1)放在一个按钮响应或者函数中
//这里的m_Pic是一个CPictureCtrl的control,其他控件等也一样
//CStatic m_Pic;
//DDX_Control(pDX, IDC_STATIC_Img, m_Pic);
CWnd * pCWnd = CWnd::FromHandle(m_Pic.GetSafeHwnd());
//通过变量得到dc比较复杂,但很好用
CPaintDC dc(pCWnd);//如果这个不能使用就换成CClientDC 。。。。
Invalidate(false);
SetStretchBltMode(dc.m_hDC,COLORONCOLOR);
//这个需要百度看看为什么这样设置
CI.StretchBlt(dc.m_hDC,rect,SRCCOPY);
//这里显示大小rect(CRect类型)也由自己定义,这个函数有许多重载函数
//图像显示的大小和效果,在你能显示出来后,可以慢慢考虑

这里的控件的dc还可以由下面方式取得
CPaintDC dc(GetDlgItem(IDC_STATIC_Img));//IDC_STATIC_Img是空间的ID
(2)直接显示(下面就写得简单点,少的部分自己加)
CDC *pDC=GetDC();
Invalidate(false);
CI.StretchBlt(pDC->m_hDC,rect,SRCCOPY);
或者
CPaintDC dc(this);
CI.Draw(dc.m_hDC,0,0);//这个以某个dc(可以是窗口)的(0,0)为起点

5.问题
        前面提到一个问题,现在讨论下,就是使用StretchBlt可以对图像进行拉伸显示。一般的图像大小和你显示的控件或者区域大小是不一样的,这时使用它显示可以拉伸它到合适的大小。(注意选择合适参数)。但我们还可以直接使用opencv自带的函数对图像进行resize,可以同样达到类似的效果。目前我尝试的结果的是使用opencv经过形变后的显示效果比MFC下的StretchBlt拉伸好看,也不知道这二种的效率如何。

6.小结
        操作数据和算法实现时都是用opencv来实现,当显示时,构造CImage显示到windows系统的窗口上。不得不说,MFC,特别是高版本的MFC,学习起来相当困难。一方面,它本身做的十分复杂,需要很长时间熟悉它才能按照你的想法实现想要的东西。另一方面,缺乏好书来指导,比如说CImage类的用法,我是通过多种途径和以前的积累才实现了最基础的使用方法。虽然最后给出的代码不多,但让代码不出错,弄明白它的简单机制却花费很长时间。到底CImage类+CPictureCtrl是否适合用来显示图像,特别是对实时图像处理的显示,还需要进一步考证。本人对MFC了解有限,都是边写程序边学,有些机制也不是很明白。。欢迎大家讨论和完善。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
OpenCV基础数据结构 - 镜花水月 - JavaEye技术网站
opencv中mat,cvmat,Iplimage构造体定义以及格式互相转换
【从零学习OpenCV 4】Mat类介绍
我的OpenCV学习笔记(24):详细讨论OpenCV中的数据结构
OpenCV学习笔记(五十一)——imge stitching图像拼接stitching
OpenCV-实现直方图均衡化(对比cv::equalizeHist)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服