首页 > 代码库 > OpenCV与MFC通用型图像处理开发实践

OpenCV与MFC通用型图像处理开发实践

imagehandler

 

该程序的起源说来话长,它起源自上课的一次作业,后来又由于接触了OpenCV这个开源库,我就试图将OpenCV和MFC搓到一块,毕竟微软近来在界面上也下了狠功夫,尤其是Windows 7大获成功,而WP7.5和Windows 8跃跃欲试。结合Windows桌面也不失为一个有益的尝试。

 

关于imagehandler

本程序是在 MFC 中使用 OpenCV 处理图像的演示程序,由2部分组成。

背景知识:

OpenCV是Intel?开源计算机视觉库。它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法。现在OpenCV已经发布了2.3.1版本,也就是本程序使用的版本。

本程序使用Visual Studio 2010开发环境在Windows 7 SP1 上开发完成,并采用了Microsoft 最新的Ribbon UI,界面友好,使用简便。

一、Windows 下用 MFC(Ribbon 界面) 编制的程序框架

采用设备无关位图DIB实现Windows多文档模式下图像的显示,实现显示的关键函数StretchDIBits的原型如下:

 

int StretchDIBits(

    HDC hdc,                       //  显示设备句柄

    int XDest,                       //  目标矩形区域左上角X坐标

    int YDest,                       //  目标矩形区域左上角Y坐标

    int nDestWidth,                   //  目标矩形区域宽度

    int nDestHeight,                   //  目标矩形区域高度

    int XSrc,                         //  源矩形区域左上角X坐标

    int YSrc,                         //  源矩形区域左上角Y坐标

    int nSrcWidth,                    //  源矩形区域宽度

    int nSrcHeight,                    //  源矩形区域高度

    CONST VOID *lpBits,             //  位图的像素存放首地址

    CONST BITMAPINFO *lpBitsInfo,  //  位图信息存放地址

    UINT iUsage,                     //  位图中的颜色类型,RGB模式用DIB_RGB_COLORS

    DWORD dwRop                  //  像素操作码,简单复制用SRCCOPY

);

 

由于OpenCV中的位图结构中的像素数据与DIB中的像素具有相同的存储结构,见表1中的像素部分。所以,只要为它构造一个DIB的位图信息就可以调用API函数StretchDIBits实现它的显示了。

表1  DIB位图参数与IplImage结构参数

参  数

DIB (MFC)

Mat (OpenCV)

宽  度

biWidth

Mat::cols

高  度

biHeight

Mat::rows

像素位数

biBitCount (1,4,8,16,24,32) = elemSize1*nChannels*8

Mat::elemSize1()

通道数

---

Mat::channels ()

(单通道位图) 调色板单元数

2biBitCount

(2, 16, 256)

二值图像显示为灰阶图像

256色彩色图像显示为真彩色图像

位图坐标原点

底-左

origin (0 顶-左,1 底-左)

像素分量存放方式

交叉存取 (按像素为单位存放)

0 交叉存取,1 位平面方式

对齐方式 (行像素数据凑整)

4字节对齐

8字节对齐

每行字节数

(biWidth*biBitCount+31)/32*4

Mat::step

像素字节数

((biWidth*biBitCount+31)/32*4)* biHeight

----

像素存放地址

BYTE*  pBits

uchar*Mat::data

感兴趣区域

---

roi

 

 

表中正体字母部分表示相同的参数,粗体字母表示参数部分相同时的交集,斜体加下划线表示结构特有的参数。

位图的宽度、高度、像素存放首地址、每行字节数、像素总字节数等5个参数在两种结构中相同。

像素位数、通道数、坐标原点位置、像素分量存放方式、对齐方式等5个参数在两种结构中部分相同,使用时可以取其交集,表中用粗体字表示。

有2个参数是两种位图各自独有的,感兴趣区域为Mat类所独有,调色板单元为DIB所独有。

从表1中可以看出,除了高精度图像(位深度16,32,64)外,这两种位图结构在图像处理的绝大部分应用中可以通用。

从以上比较中也可看出,Mat类适用于高精度处理,并且可以限制处理的区域;而DIB适用于Windows图形操作,并且可以存储低位数图像文件,如每像素一位的二值图像与像素8位的索引图像等。

 

 

二、调用 OpenCV 函数实现处理

使用 OpenCV 函数处理图像在 MFC 环境下显示,实现功能为图像平移、图像翻转与镜像。

 

主要内容

下面列出stdafx.h尾部集中的几个头文件,程序结构由此可见一斑。

 

#include "imagehandler.h"                       //  窗口管理

 

#include "opencv2/core/core.h"                            //  OpenCV 头文件

#include " opencv2/highgui/highgui.h"                      //OpenCV自带界面

#include "opencv2/imgproc/imgproc.h"                     //图像处理函数库,本来可以用上的但是

                                                    //功能没有写完

imagehandler的菜单结构

程序分为主功能和几何变换2部分,程序的菜单结构见表2,其中列出了演示程序的大多数功能。

表2  imagehandler菜单结构

main

几何变换

打开

翻转

保存

镜像

 

平移

程序结构

程序采用VC++多文档结构,图像的存放与处理则采用OpenCV的结构与函数,图像的显示采用位图信息m_lpBmi实现,为了便于管理对m_lpBmi的操作集中在OnDraw程序中。待显示位图结构发生改变时用m_dibFlag标志激发m_lpBmi的刷新。除了文件结构与图像显示外,其余部分基本上是OpenCV程序。

主要功能区为mfcvProcess

CimagehandlerView

CimagehandlerDoc

mfcvProcess的基本功能

 

1实现读入图像写入到Mat中,

2 使用DIB在文档视图中显示,

3 进行几何变换,

4 进行裁剪,图像拼接操作,

5 将修改的数据保存到Mat 格式中,

6 将Mat写入到图像数据中并保存。

 

算法实现:

话说图像

BMP取自位图BitMap的缩写,也称为DIB(与设备无关的位图)是微软视窗图形子系统(GDI)内部使用的一种位图图形格式,它是微软视窗平台上的一个简单的图形文件格式。的图形文件格式。

位图像素宽度必须是4的倍数……

图像可以分解成多个通道存放在一个二维矩阵中,

   Mat即矩阵的简称,它是OpenCV中一个基础的矩阵结构。在CV(computer vision)中,图像就是一个二维的矩阵,Mat的责任就是将图像数据读入到内存块中,并将图像每一个通道的数据通过特殊的数据结构进行表达。通常这些结构的原子就是简单的数字(usigned、double、int、float等)或是无符号的字符(usigned char)。一些常用的函数:

at模板函数,ptr模板函数,create函数,channels函数(获取图像通道数)。。。

图像显示

由于bmp要求图像单行所占字节数必须是4的倍数我于是在显示时都通过OpenCV处理成4的倍数在显示,但实际处理的图像始终按原来大小进行操作。

 图像几何变换

概念建立一种元图像像素与变换后的的图像像素之间的映射关系。

公式如下:(x、y表示输出图像像素坐标,x0,y0表示输入图像像素的坐标

    ;

采用统一的矩阵表示法:

向前映射  入射→输出

浮点数坐标(放大缩小),映射不完全和映射重叠(向后映射:输出图像的像素坐标来确定输入图像像素坐标)

图像放大缩小问题

第一位,确定所处理的对象是一个什么结构,在这里我使用了OpenCV中的C++接口,使用了微软的MFC程序框架,只有这两个东西可以提供数据结构容器,否则就只有用C++的标准函数(fopen)和数组(向量(vector.h))了。为了简化后续应用算法,这里采用OpenCV的矩阵结构Mat。这是一个以矩阵形式存储图像数据或矩阵的C++类。

其次要决定的是采用什么样的算法对图像进行处理。通常图像放大有:最近邻法、双线性插值法、二次卷积插值法、三次卷积插值法等。

图像的旋转

仍然采用向后映射,旋转的同时注意改变图像的大小和图像对齐的问题

图像平移

应用向后映射原理,通过目标图像象素点坐标计算出该点在原图中的坐标,如果坐标值存在,复制数据,否则什么也不干。因为在此之前,我已经缓存图像的所有像素都赋值了。

设 (x0,y0)为原图像上一点,图像水平平移量为tx,垂直平移量为ty,平移后的点为(x1,y1) x1=x0+tx;y1=y0+ty,转换后x0=x1-tx;y0=y1-ty这样平移后的图像上的每一点都可以在原图像中找到对应的点,可以根据x0和y0的值,判断原来的点是否在图像中,如果超出了原来图像的范围,就把点(x1,y1)的值设置成0(黑色)或255(白色)如果希望保留原图所有像素,则根据平移量增加相应的象素点即可。


参考文献

算法学习:

[1]  左飞.万晋森.刘航 Visual C++数字图像处理开发入门与编程实践[M]. 北京:电子工业出版社, 2008

[2] [Laganière 2011] Robert Laganière Overview of OpenCV 2 Computer VisionApplication Programming Cookbook,Birmingham(UK):Packt Publishing Ltd;2011

OpenCV学习

[3]  (美)布拉德斯基(Bradski G)(美)克勒(keahler,A).学习OpenCV[M] 于士祺 刘瑞祯译. 北京:清华大学出版社2009

[4] OpenCV Reference ,US,2011

其他:

百度空间,新浪博客,网易博客,CSDN以及Stackoverflow,Guru,CodeProject等社区。


目前的工作结果:

计划中的工作:(有兴趣的筒子可以一起学习QQ:547792075

添加遥感影像处理

OpenCV与MFC通用型图像处理开发实践