#在MFC中使用OpenCV方法.docx
- 文档编号:26726208
- 上传时间:2023-06-22
- 格式:DOCX
- 页数:27
- 大小:76.72KB
#在MFC中使用OpenCV方法.docx
《#在MFC中使用OpenCV方法.docx》由会员分享,可在线阅读,更多相关《#在MFC中使用OpenCV方法.docx(27页珍藏版)》请在冰豆网上搜索。
#在MFC中使用OpenCV方法
在MFC中使用OpenCV
演示程序CVMFC
本程序是在MFC中使用OpenCV的演示程序,由3部分组成。
一、Windows下用MFC编制的程序框架
采用设备无关位图DIB实现Windows多文档模式下图像的显示,实现显示的关键函数StretchDIBits的原型如下:
intStretchDIBits(
HDChdc,//显示设备句柄
intXDest,//目标矩形区域左上角X坐标
intYDest,//目标矩形区域左上角Y坐标
intnDestWidth,//目标矩形区域宽度
intnDestHeight,//目标矩形区域高度
intXSrc,//源矩形区域左上角X坐标
intYSrc,//源矩形区域左上角Y坐标
intnSrcWidth,//源矩形区域宽度
intnSrcHeight,//源矩形区域高度
CONSTVOID*lpBits,//位图的像素存放首地址
CONSTBITMAPINFO*lpBitsInfo,//位图信息存放地址
UINTiUsage,//位图中的颜色类型,RGB模式用DIB_RGB_COLORS
DWORDdwRop//像素操作码,简单复制用SRCCOPY
>。
因为OpenCV中的位图结构中的像素数据与DIB中的像素具有相同的存储结构,见表1中的像素部分。
所以,只要为它构造一个DIB的位图信息就可以调用API函数StretchDIBits实现它的显示了。
表1DIB位图参数与IplImage结构参数
参数
DIB(MFC>
IplImage(OpenCV>
宽度
biWidth
width
高度
biHeight
height
像素位数
biBitCount(1,4,8,16,24,32>=depth*nChannels
depth(8,16,32,64>
通道数
---
nChannels(1,2,3,4>
(单通道位图>调色板单元数
biBitCount
2
(2,16,256>
二值图像显示为灰阶图像
256色彩色图像显示为真彩色图像
位图坐标原点
底-左
origin(0顶-左,1底-左>
像素分量存放方式
交叉存取(按像素为单位存放>
0交叉存取,1位平面方式
对齐方式(行像素数据凑整>
4字节对齐
4字节对齐或8字节对齐
每行字节数
(biWidth*biBitCount+31>/32*4
widthStep
像素字节数
((biWidth*biBitCount+31>/32*4>*biHeight
imageSize
像素存放地址
BYTE*pBits
char*imageData
感兴趣区域
---
roi
表中正体字母部分表示相同的参数,粗体字母表示参数部分相同时的交集,斜体加下划线表示结构特
有的参数。
位图的宽度、高度、像素存放首地址、每行字节数、像素总字节数等5个参数在两种结构中相同。
像素位数、通道数、坐标原点位置、像素分量存放方式、对齐方式等5个参数在两种结构中部分相同,使用时可以取其交集,表中用粗体字表示。
有2个参数是两种位图各自独有的,感兴趣区域为IplImage结构所独有,调色板单元为DIB所独有。
从表1中可以看出,除了高精度图像(位深度16,32,64>外,这两种位图结构在图像处理的绝大部分应
1/14
用中可以通用。
从以上比较中也可看出,IplImage结构适用于高精度处理,并且可以限制处理的区域;而DIB适用于Windows图形操作,并且可以存储低位数图像文件,如每像素一位的二值图像与像素8位的索引图像等。
另一种实现MFC的方法是采用CvvImage类,它有一个特点,就是其成员函数DrawToHDC可将位图全部经缩放后显示到窗口中。
这样,虽然能够察看全图,但当位图与窗口的长宽比不一致时会造成图像失真。
而采用DIB实现的显示比例可选择为1:
1,图像显示没有经过缩放,显示画面按窗口大小进行裁剪,并可使用滑动条选择显示部位,这比较符合图像采集与处理的使用习惯。
二、调用OpenCV函数实现处理
使用OpenCV函数处理图像在MFC环境下显示,实现功能为图像平滑、图像缩小与Canny边缘检测。
根据《学习OpenCV》一书第2章的3个例子(例2-4,2-5,2-6>改编而成。
例2-4与2-5使用例图fruits.jpg,例2-6使用例图lena.jpg。
还增加了若干图像处理常用功能,详见下面表2菜单结构列表。
视频播放也用OpenCV函数实现,根据《OpenCV教程(基础篇>》中第3章的例3-5改编而成,用的是highgui函数,测试视频文件为globe.avi。
例图文件都在image\目录下。
三、用DirectShow编制的视频采集程序
采用DirectShow实现视频采集,其优点是支持高分辨率图像采集,最高分辨率由所用的摄像头决定,如罗技130万像素USB摄像头C300最高分辨率可达1280*1024,在MPEG模式下采集速度为每秒15帧。
使用时CPU的时间占用率在15~30%之间。
通过多图像平均可以采集得到质量不错的图像,经过4幅图像平均采集所得图像的信噪比可提高一倍。
因为需要连续采集多帧图像,约需0.25秒,故适宜采集静态或缓慢移动对象的图像。
视频采集功能调用OpenCVChina网站下载的软件camerads中的函数实现。
主要内容
面列出stdafx.h尾部集中的几个头文件,程序结构由此可见一斑。
//OpenCV头文件
//DirectShow(基于OpenCV>
//视频采集接口
程序分为文件、点处理、邻域处理、二值图像处理、形态学处理、综合处理例与视频采集播放等七、八个菜单条共70个功能,近半数功能由参考文献上的程序修改而成,为了便于找到相应参考材料进行对照,在程序中附上了它们的出处。
程序的菜单结构见表2,其中列出了演示程序的大多数功能。
表2CVMFC菜单结构
文件
点处理
邻域处理
二值图像处理
形态学处理
综合处理例
视频采集播放
打开图像
彩色变灰阶
邻域平均
选择阈值
腐蚀
图像缩小
启动摄像头
恢复图像
图像反相
Gauss滤波
自适应阈值法
膨胀
径向梯度
打开AVI文件
关闭当前窗口
垂直镜像
中值滤波
全局阈值法
开运算
Canny算法
视频解冻
保存当前位图
水平镜像
Sobel算法
外接矩形
闭运算
种子填充
视频冻结
最近文件
180度旋转
Laplace算法
最小面积矩形
形态学梯度
金字塔图像分割
多图像平均
恢复原始图像
30度旋转
点集凸包
顶帽变换
椭圆曲线拟合
关闭视频
当前画面存盘
亮度变换
区域凸包
波谷检测
Snake原理
选择分辨率
退出
图像直方图
轮廓跟踪
分水岭原理
动态边缘检测
直方图均衡化
距离变换
角点检测
LK光流跟踪
典型例图
2/14
各类功能都有一定的特异性,为了突出各功能的实效,建议初次使用时先用表3中列出的例图进行处理。
这些例图在程序包的目录下,表中也对一些功能作了简要的说明。
表3功能的典型例图
功能名称
典型例图
简要说明
外接矩形(BoundingRect>
ExampleL.bmp、
仅适用于单连通区域,
最小面积矩形(MinAreaRect2>
ExampleQ.bmp
不能处理多连通区域与孔边界
区域凸包(ConvexHull2>
轮廓跟踪(FindContours>
ExampleC.bmp、
适用各类二值图像,使用范围较宽
距离变换(DistTransform>
SteelBar.bmp、
图像反相后也可进行处理,得到不同结果
pic3.png
顶帽变换
ExampleD.bmp
为灰值形态学运算,波谷检测又称黑顶帽变换
波谷检测
图像反相后处理与另一方法直接处理等价
图像缩小
lena.jpg、fruits.jpg
径向梯度
lena.jpg、fruits.jpg
Canny算法
lena.jpg
Hough变换(直线>(HoughLines2>
pic1.png
Hough变换(圆>(HoughCircles>
stuff.jpg
平行四边形检测
pic1.png、pic2.png
种子填充(FloodFill>
fruits.jpg
鼠标选种子,命令键C、M、R、S、F、G、8、4,ESC
金字塔图像分割(PyrSegmentation>
fruits.jpg
滑动条调节参数,任意键退出
椭圆曲线拟合(FitEllipse>
stuff.jpg、rice.tif
滑动条调节参数,任意键退出
Snake原理(SnakeImage>
ring.bmp、square.bmp
滑动条调节参数,ESC退出
分水岭原理(Watershed>
fruits.jpg
鼠标绘制区域标记,R清除,W或Enter分割,ESC退出
角点检测(GoodFeaturesToTrack>
chessboard.jpg
滑动条调节参数,鼠标确定检测范围,任意键退出
人脸检测(HaarDetectObjects>
lena.jpg
打开AVI文件
globe.avi
不能播放用Mpeg压缩的视频文件
LK算法光流跟踪
鼠标选择跟踪点,命令键R、C、N,ESC退出
程序结构
程序采用VC++多文档结构,图像的存放与处理则采用OpenCV的结构与函数,图像的显示采用位图信息m_lpBmi实现,为了便于管理对m_lpBmi的操作集中在OnDraw程序中。
待显示位图结构发生改变时用m_dibFlag标志激发m_lpBmi的刷新。
除了文件结构与图像显示外,其余部分基本上是OpenCV程序。
位图数据:
CVMFCDoc中pImg(读入图像文件所得原始位图>CVMFCView中workImg(工作位图>、saveImg(备份位图>
m_lpBmi(工作位图的位图信息>
CVDSCap中m_Frame(视频采集所得位图>
视图的显示:
voidCCVMFC0View:
:
OnDraw(CDC*pDC>
{
CCVMFCDoc*pDoc=GetDocument(>。
ASSERT_VALID(pDoc>。
//TODO:
adddrawcodefornativedatahere
if(pDoc->pImg!
=NULL>{//有磁盘输入图像
CSizesizeTotal。
sizeTotal=CSize(pDoc->pImg->width,pDoc->pImg->height>。
SetScrollSizes(MM_TEXT,sizeTotal>。
if(pDoc->m_Display==0>{//输入图像尚未显示
newCloneImage(pDoc->pImg,&saveImg>。
//复制到备份位图m_dibFlag=newCloneImage(saveImg,&workImg>。
//复制到工作位图m_ImageType=pDoc->pImg->nChannels。
//设置标志
3/14m_SaveFlag=m_ImageType。
pDoc->m_Display=1。
}
}
if(m_dibFlag>{//刷新DIB位图信息
if(m_lpBmi>
free(m_lpBmi>。
m_lpBmi=CtreateMapInfo(workImg,m_dibFlag>。
m_dibFlag=0。
}
if(workImg>{//刷新窗口画面
StretchDIBits(pDC->m_hDC,0,0,workImg->width,workImg->height,
0,0,workImg->width,workImg->height,
workImg->imageData,m_lpBmi,DIB_RGB_COLORS,SRCCOPY>。
}
}
CCVMFC模块中增加了4个函数,即CtreateMapInfo、imageType、imageClone与imageReplace。
CtreateMapInfo函数用于建立工作位图workImg的位图信息m_lpBmi,其特点是可以为单通道位图设置两种调色板,即黑白灰阶调色板与VGA默认调色板。
因为在OpenCV中二值图像显示为灰阶图像,imageType函数可从单通道位图中识别出二值位图。
ImageClone与imageReplace函数使用OpenCV函数实
现位图的复制,自动释放老的指针所指向的存储单元以防止内存泄漏,同时返回的m_dibFlag标志可以用于激发刷新工作位图workImg的位图信息m_lpBmi。
imageReplace与ImageClone相似,但不建立新位图,只用输入位图替换输出位图。
LPBITMAPINFOCtreateMapInfo(IplImage*workImg,intflag>
{//建立位图信息
BITMAPINFOHEADERBIH={40,1,1,1,8,0,0,0,0,0,0}。
LPBITMAPINFOlpBmi。
intwid,hei,bits,colors,i。
RGBQUADColorTab[256]。
wid=workImg->width。
hei=workImg->height。
bits=workImg->depth*workImg->nChannels。
if(bits>8>colors=0。
elsecolors=1< lpBmi=(LPBITMAPINFO>malloc(40+4*colors>。 BIH.biWidth=wid。 BIH.biHeight=hei。 BIH.biBitCount=(BYTE>bits。 memcpy(lpBmi,&BIH,40>。 //复制位图信息头 if(bits==8>{//256色位图 if(flag==1>{//设置灰阶调色板 for(i=0。 i<256。 i++>{ ColorTab[i].rgbRed=ColorTab[i].rgbGreen=ColorTab[i].rgbBlue=(BYTE>i。 } memcpy(lpBmi->bmiColors,ColorTab,1024> 4/14 } elseif(flag==2>{//设置默认调色板memcpy(lpBmi->bmiColors,VgaDefPal,1024>。 } } return(lpBmi>。 } intimageType(IplImage*p>//识别二值图像 { inti,j,k,bpl,n,pg[256]。 BYTE*buf。 k=p->nChannels。 if(k==1>{//检查二值图像for(i=0。 i<256。 i++>pg[i]=0。 buf=(BYTE*>p->imageData。 bpl=p->widthStep。 for(i=0。 i i++>{for(j=0。 j j++>pg[buf[j]]++。 //直方图统计buf+=bpl。 } for(i=0,n=0。 i<256。 i++>if(pg[i]>n++。 if(n==2>k=-1。 //二值图像 } return(k>。 } intimageClone(IplImage*pi,IplImage**ppo>//复制IplImage位图(OpenCV> { if(*ppo>cvReleaseImage(ppo>。 //释放原来位图 (*ppo>=cvCloneImage(pi>。 //复制新位图 return(1>。 } intimageReplace(IplImage*pi,IplImage**ppo>//替换位图(OpenCV> { if(*ppo> cvReleaseImage(ppo>。 //释放原来位图 (*ppo>=pi。 //位图换名 return(1>。 } 像素数据地址的类型 从表1中可见,在OpenCV中像素存放地址imageData为char*类型。 因此,在图像处理时就必须转换为BYTE*类型才可以使用。 例如,在上面的imageType函数中统计图像直方图非使用这种转换不可。 另外,图像类型参数m_ImageType用于菜单功能的使能(Enable>,程序中用到了4种不同类型的图像,即真彩色图像、灰阶图像、二值图像与伪彩色图像,它们的m_ImageType值分别定义为3,1,-1,- 5/14 2。 双操作数函数的参数顺序 本程序是WindowsAPI系统与OpenCV两种体系函数的混合使用,而它们的函数参数的书写习惯是不同的,极容易引起混淆。 这里作一简要说明,请看下面例子: 目的参数Dest源参数Src C: memcpy(pDest,pSrc,size>。 WindowsAPI: BitBlt(hDestDC,0,0,wid,hei,hSrcDC,0,0,SRCCOPY>。 VC++: pDestDC->BitBlt(0,0,p->wid,p->hei,pSrcDC,0,0,SRCCOPY>。 源参数Src目的参数Dest OpenCV: cvCvtColor(pSrcImg,pDestcImg,CV_BGR2GRAY>。 cvSmooth(pSrcImg,pDestcImg,CV_GAUSSIAN,3,0,0>。 本程序中除了OpenCV函数采用后一书写形式外,其他函数都采用前一书写形式,千万注意不能混淆。 OpenCV函数很容易辨认,都以前缀cv-开头,如cvCvtColor、cvSmooth。 新增函数ImageClone与 imageReplace因为调用OpenCV函数,故也采用后一书写形式。 图像处理程序的修改 本程序中待处理图像放在工作位图workImg中,处理结果也放在工作位图workImg中。 同时,工作位图workImg也是窗口画面显示的内容。 所以,处理程序中仅源图像的获取与结果图像的显示与OpenCV程序有所不同,中间处理部分可以完全相同,现以《学习OpenCV》一书中的例2-6为例来作修改说明。 《学习OpenCV》例2-6原始程序: intmain(intargc,char*argv[]>//Canny边缘检测 { IplImage*pImage=NULL。 IplImage*pImgCanny=NULL。 IplImage*pImg8u=NULL。 IplImage*pImg8uSmooth=NULL。 pImage=cvLoadImage(argv[1]>。 //输入待处理图像 if(! pImage>return0。 cvNamedWindow("Example6-in",CV_WINDOW_AUTOSIZE>。 cvShowImage("Example6-in",pImage>。 pImg8u=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 pImg8uSmooth=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 pImgCanny=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 cvCvtColor(pImage,pImg8u,CV_BGR2GRAY>。 cvSmooth(pImg8u,pImg8uSmooth,CV_GAUSSIAN,3,0,0>。 cvCanny(pImg8uSmooth,pImgCanny,100,200,3>。 cvNamedWindow("Example6-out",CV_WINDOW_AUTOSIZE>。 cvShowImage("Example6-out",pImgCanny>。 //显示处理结果cvWaitKey(0>。 cvReleaseImage(&pImage>。 6/14 cvReleaseImage(&pImg8u>。 cvReleaseImage(&pImg8uSmooth>。 cvReleaseImage(&pImgCanny>。 cvDestroyWindow("Example6-in">。 cvDestroyWindow("Example6-out">。 return0。 } 在CVMFC程序中修改为: voidCCVMFC0View: : OnCannyBorddetec(>//Canny边缘检测 {//根据《学习OpenCV》例2-6改编 //定义工作位图 IplImage*pImage。 IplImage*pImg8u=NULL。 IplImage*pImg8uSmooth=NULL。 IplImage*pImgCanny=NULL。 //**输入待处理图像**//修改部分1 pImage=workImg。 //建立辅助位图 pImg8u=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 pImg8uSmooth=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 pImgCanny=cvCreateImage(cvGetSize(pImage>,IPL_DEPTH_8U,1>。 //图像处理 cv
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MFC 使用 OpenCV 方法