OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core OpenCV学习笔记(五十七)——在同一窗口显示多幅图片 OpenCV学习笔记(五十八)——读《Mast

OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core

看过OpenCV源代码的朋友,肯定都知道很多函数的接口都是InputArray或者OutputArray型的,这个接口类还是很强大的,今个就来说说它们的那些事。

InputArray这个接口类可以是Mat、Mat_<T>、Mat_<T, m, n>、vector<T>、vector<vector<T>>、vector<Mat>。也就意味着当你看refman或者源代码时,如果看见函数的参数类型是InputArray型时,把上诉几种类型作为参数都是可以的。

有时候InputArray输入的矩阵是个空参数,你只需要用cv::noArray()作为参数即可,或者很多代码里都用cv::Mat()作为空参。

这个类只能作为函数的形参参数使用,不要试图声明一个InputArray类型的变量

如果在你自己编写的函数中形参也想用InputArray,可以传递多类型的参数,在函数的内部可以使用_InputArray::getMat()函数将传入的参数转换为Mat的结构,方便你函数内的操作;必要的时候,可能还需要_InputArray::kind()用来区分Mat结构或者vector<>结构,但通常是不需要的。例如:

  1. void myAffineTransform(InputArray _src, OutputArray _dst, InputArray _m)  
  2. {  
  3.   
  4.     Mat src = _src.getMat(), m = _m.getMat();  
  5.     CV_Assert( src.type() == CV_32FC2 && m.type() == CV_32F && m.size() == Size(3, 2) );  
  6.     _dst.create(src.size(), src.type());  
  7.     Mat dst = _dst.getMat();  
  8.     forint i = 0; i < src.rows; i++ )  
  9.         forint j = 0; j < src.cols; j++ )  
  10.         {  
  11.             Point2f pt = src.at<Point2f>(i, j);  
  12.             dst.at<Point2f>(i, j) = Point2f(m.at<float>(0, 0) * pt.x +  m.at<float>(0, 1) *   pt.y + m.at<float>(0, 2);  
  13.         }  
  14. }  

至于有的源代码里使用 InputArrayOfArrays作为形参,不用慌张,其实它和InputArray是一样一样一样的。

OutputArray是InputArray的派生类。使用时需要注意的问题和InputArray一样。和InputArray不同的是,需要注意在使用_OutputArray::getMat()之前一定要调用_OutputArray::create()为矩阵分配空间。可以用_OutputArray::needed()来检测输出的矩阵是否需要被计算。有时候传进去的参不是空就不需要计算

还有就是OutputArrayOfArrays、InputOutputArray、InputOutputArrayOfArrays都是OutputArray的别名而已



OpenCV学习笔记(五十七)——在同一窗口显示多幅图片

好久没更新blog里,看到OpenCV官网做的越来越好,心里也是很高兴的,真有些冲动将来加入到这个组织里做些事。估计2.4.3要在国庆左右跟大家见面,让我们多期待一下吧。

闲话少说,今天不介绍复杂的算法了,来个简单的,大家写文章做图经常用Matlab,在Matlab里经常在一个窗口里打开多幅图片。遗憾的是OpenCV没有集成这样的功能,但这难不倒大家,让我试试用ROI来解决这个问题。

没啥好讲的,上代码好了:

  1. void imshowMany(const std::string& _winName, const vector<Mat>& _imgs)  
  2. {  
  3.     int nImg = (int)_imgs.size();  
  4.       
  5.     Mat dispImg;  
  6.   
  7.     int size;  
  8.     int x, y;  
  9.   
  10.     // w - Maximum number of images in a row   
  11.     // h - Maximum number of images in a column   
  12.     int w, h;  
  13.     // scale - How much we have to resize the image  
  14.     float scale;  
  15.     int max;  
  16.   
  17.     if (nImg <= 0)   
  18.     {  
  19.         printf("Number of arguments too small....\n");  
  20.         return;  
  21.     }  
  22.     else if (nImg > 12)  
  23.     {  
  24.         printf("Number of arguments too large....\n");  
  25.         return;  
  26.     }  
  27.       
  28.     else if (nImg == 1)  
  29.     {  
  30.         w = h = 1;  
  31.         size = 300;  
  32.     }  
  33.     else if (nImg == 2)  
  34.     {  
  35.         w = 2; h = 1;  
  36.         size = 300;  
  37.     }  
  38.     else if (nImg == 3 || nImg == 4)  
  39.     {  
  40.         w = 2; h = 2;  
  41.         size = 300;  
  42.     }  
  43.     else if (nImg == 5 || nImg == 6)  
  44.     {  
  45.         w = 3; h = 2;  
  46.         size = 200;  
  47.     }  
  48.     else if (nImg == 7 || nImg == 8)  
  49.     {  
  50.         w = 4; h = 2;  
  51.         size = 200;  
  52.     }  
  53.     else  
  54.     {  
  55.         w = 4; h = 3;  
  56.         size = 150;  
  57.     }  
  58.   
  59.     dispImg.create(Size(100 + size*w, 60 + size*h), CV_8UC3);  
  60.   
  61.     for (int i= 0, m=20, n=20; i<nImg; i++, m+=(20+size))  
  62.     {  
  63.         x = _imgs[i].cols;  
  64.         y = _imgs[i].rows;  
  65.   
  66.         max = (x > y)? x: y;  
  67.         scale = (float) ( (float) max / size );  
  68.   
  69.         if (i%w==0 && m!=20)  
  70.         {  
  71.             m = 20;  
  72.             n += 20+size;  
  73.         }  
  74.   
  75.         Mat imgROI = dispImg(Rect(m, n, (int)(x/scale), (int)(y/scale)));  
  76.         resize(_imgs[i], imgROI, Size((int)(x/scale), (int)(y/scale)));  
  77.     }  
  78.   
  79.     namedWindow(_winName);  
  80.     imshow(_winName, dispImg);  
  81. }  

附上效果图一张:


工程的下载链接为http://download.csdn.net/detail/yang_xian521/4531610



OpenCV学习笔记(五十八)——读《Master OpenCV》初感

好久没更新这个系列了。去年12月初的时候就知道出了一本OpenCV的新书《Master OpenCV with Practical Computer Vision Projects》,一直没来得及看,春节前也不想做什么任务,就把这书读一读吧。大概看了一下,和OpenCV的其他书对比了一下,感觉如下:

《Learning OpenCV》是一本经典的老书了,是一个入门教材,读完可以知道OpenCV能做些什么,但里面的具体代码个人觉得还是有点out,但好处就是中文资料很全,网上可以找到很多参考资料。

《OpenCV Cookbook》是我以前推荐过的一本书,是基于2.2版本写的。我的感觉是一本上手教材,书的目的是让大家知道应该如何去调用OpenCV的函数,如何用OpenCV的类去实现简单的视觉任务。需要一定的C++基础。

《Master OpenCV》感觉更像是一个上层建筑,是基于2.4版本写的。是教会大家如何用OpenCV去实现复杂的任务,去完成OpenCV自带函数没有提供的功能。(因为大家经常会因为“OpenCV里面有xxx的函数么?”的否定答案而苦恼,这本书就是告诉大家OpenCV只是个工具,如何去驾驭这个工具进行二次开发是要动脑的)

这本《Master OpenCV》书第一章没有很复杂的东西。

第一章就是介绍了一个边缘检测、肤色检测、一个填充算法,并把这个功能移植到android平台,边缘检测和填充算法都是OpenCV自带的函数功能。这里随便说说读完第一章的几点收获:

1、具体任务要具体分析。这里因为要做到嵌入式平台中,算法的复杂度被放在了首位,所以双边滤波做了简化、填充算法也只是在原图的缩小1/2的图上进行的计算。肤色检测也没有先用经典的人脸检测算法,而是用了一种土鳖的方案,都是为了在嵌入式平台上能运行的高效。这种处理问题的方法值得借鉴学习

2、面向对象编程的思想。这章里也提到了显示FPS,只是人家是在一个类中实现,再对比自己之前写的OpenCV学习笔记(三十八)——显示当前FPS,高下自分。实在是自惭形愧啊~~。

3、貌似把自己的c++工程移植到android平台并不需要改写自己的代码,只要做个JNI function作为接口就可以调用c++的程序了,感觉有点像Matlab中的mex。android下的OpenCV开发基本不懂,这里就不乱讲了。

这几天抓紧把这书读完,把后几章的阅读笔记也写出来分享一下。希望大家多多指正交流



OpenCV学习笔记(五十九)——marker检测识别"Master

第二章原本是讲如何将基于标定的增强现实在ios平台实现,包括以下4个方面:

1、在ios平台建立opencv工程

2、Marker检测识别

3、摄像机标定及Marker姿态估计

4、在Marker基础上渲染一个3维虚拟物体

这里面第一部分是IOS平台的开发,我不是太关注,略去;第四部分是基于OpenGL的3维虚拟物体建立,也是基于IOS平台,因为第三章里还要用到OpenGL,这里留着第三章再解剖。所以这里主要分析第二部分和第三部分。这一篇介绍第二部分。感觉这个东西有点像二维码识别。不知道2维码是怎么做的哦

MarkerDetection类任务processFrame:图1


转为灰度图、2值化(固定阈值法threshold:受光照等影响明显;自适应阈值法adaptiveThreshold:更好)(我这里用OpenCV243里的adaptiveThreshold函数未能实现自适应滤波的效果,效果像边缘检测的算法,很困惑。。最后用threshold函数代替,这个问题未能解决,希望高手指点,ps:网上高手多啊,这个问题已经解决了),检测后的结果如图threshold(图1左上)

findMarkerContours函数进行轮廓检测findContours(用多边形的顶点最好,去掉小于阈值的点(对小的轮廓不感兴趣),把每个轮廓的点按照逆时针排序,并去掉距离太近的轮廓),结果如图contours(图1中上)

接下来findMarkerCandidates函数对轮廓进行筛选,先用approxPolyDP得到轮廓近似的多边形。进行筛选,为凸多边形且顶点为4的才有可能是marker,并检测这个4边形的边长,最小边长如果小于10pixel,也不认为是一个marker。然后把得到的可能的marker的轮廓点按照逆时针排序。并且检测是否检测到重复的marker,如果检测到重复的marker,去掉周长更短的那个。这步之后效果如下markerCandidate(图1左下)

detectMarkers函数有3个任务,去除投影变换的影响(getPerspectiveTransform得到投影矩阵,warpPerspective得到正面的视角的图像),得到marker正面的视图。

然后对这个marker的正面图进行解码,threshold对marker使用THRESH_OTSU进行2值化。效果图:


接下来对这个marker进行识别marker.decode。检测编码marker(对marker解码,marker编码为7*7的栅格,中心5*5为ID,周围一圈为黑色边界,检测的时候先检测周围一圈是否为黑色边界,然后再对中心5*5解码(注意,只有5*5具有旋转不变形才能得到唯一的码),是5bit*5word,每个word中的5bit,2位为id(2位4位),3位为校验码(用来保证旋转),所以5word一共有2^10=1024个不同id,而且第一位要置反,目的是要防止一个word全黑,不易检测。举例,我这里使用的marker的5个word的id分别为10、01、11、11、11。那么如何从刚刚得到的marker图提取出7*7的2值栅格呢,这里用个Mat(Rect)取marker中的小方块,用countNonZero来判断这个方块为0or1。因为marker有4个方向,哪个方向才是我对应的marker的id的,这里用id和我验证用的id的hamming距离来做依据,汉明距最小的即marker的方向。

确认为一个marker后再得到轮廓的细致的corner,使用cornerSubPix,这时才进行细化,是因为这个函数相对耗时,如果之前就对各corner细化,由于候选目标很多,会加重计算负担。)效果图marker(图1右下)。

最后我试了其他的marker编码,都能正确解码出id信息,效果图如下:第一幅图的id为0011010101,第二幅图为第一图的旋转,id相同,第三图id为0011000110,第四图不是一个marker,故没有检测出来。


代码的下载地址:http://download.csdn.net/detail/yang_xian521/5040634

在下一篇里,将介绍如何用这个marker的轮廓位置,和轮廓(红色)的方向(黄点)来在marker上建立一个3维的虚拟物体。



OpenCV"chp.2 OpenCV学习笔记(六十一)——建立支持OpenGL的OpenCV工程“Master OpenCV”chp.3

从OpenCV2.4beta版本,OpenGL就可以有接口到highgui的模块中了。结合Master OpenCV第三章的阅读,这里说说如何在OpenCV的显示中嵌入OpenGL的虚拟物体。

要注意的一点:如果想使OpenCV支持OpenGL,不能使用预编译好的library,要用cmake rebuild工程,注意ENABLE_OPENGL = YES,(在2.4.2版本中,默认ENABLE_OPENGL = NO),标签的改变在CMake的高级版本都是图形界面的,只需把WITH_OPENGL的对号勾选即可。

这里实战过程中我还遇到了一个问题,用这个CMake得到的vs工程(添加了WITH_OPENGL)无法编译通过,郁闷了好久。因为opengl在vs中是支持的,不需要安装,最后找到了这个bug,需要把\modules\core\src\opengl_interop.cpp文件中使用<gl\gl.h>前面添加#include <windows.h>,(其实#include <gl.h>前都需要添加#include <windows.h>这样才能编译通过,这里我只重新编译opencv_core243d.lib 和opencv_highgui243d.lib

已经得到了支持OpenGL的OpenCV lib,接下来就是如何用OpenCV建立OpenGL窗口,基本的调用方式很像OpenCV中鼠标的使用,都是通过回调函数实现,核心代码如下:

  1. // callback function  
  2. void onDraw(void* param)  
  3. {  
  4.     // Draw something using OpenGL here  
  5. }  
  6.   
  7. int main(void)  
  8. {  
  9.     string openGLWindowName = "OpenGL Test";  
  10.     namedWindow(openGLWindowName, WINDOW_OPENGL);  
  11.     resizeWindow(openGLWindowName, 640, 480);  
  12.     setOpenGlContext(openGLWindowName);  
  13.     setOpenGlDrawCallback(openGLWindowName, onDraw, NULL);  
  14.   
  15.     updateWindow(openGLWindowName); // when needed  
  16.     return 0;  
  17. }  

以前我们调用 namedWindow最后一个参数通常会用默认或者使用WINDOW_AUTOSIZE,这回用 WINDOW_OPENGL,然后调用 setOpenGLContext建立窗口关联,为了在这个窗口上画虚拟物体,需要使用回调函数,建立方法就是 setOpenGLDrawCallback,注意这个函数第一个参数是窗口名称,第二个参数是回调函数名,第三个参数是回调函数的参数,因为我这里回调函数onDraw是无参函数,所以这里为NULL。跟MFC重绘需要调用Invalidate或者uadate类似,在需要重绘的时候还要调用 updateWindow

把我做的一个最基础的OpenGL演示上传:http://download.csdn.net/detail/yang_xian521/5023063(附上我rebulid的支持OpenGL的lib),效果图如下:



OpenCV学习笔记(六十二)——《OpenCV Computer Version with Python》阅读摘要

现在python火啊,每次OpenCV自带的ml模块都让我直呼坑爹,索性准备用python来做OpenCV后期的机器学习算法的处理。于是赶紧拿起这本书读读。

适合OpenCV和python都有一定基础的。。。。由于都比较熟悉这两个东西,我阅读之前比较关心的只有几个问题,具体的应用实例没有仔细看。

1.如何在python中安装opencv

2.OpenCV的Mat数据结构能否方便的转换成numpy的array结构

3.OpenCV的GUI模块在python里好用么

4.二者还能擦出什么我想不到的火花么。。。。

书中提到在windows系统中,python-32bit表现的比64bit要好,推荐安装32位的python

第一个问题在windows下很简单,OpenCV安装好之后,找到目录<build_folder>\lib\Release\cv2.pyd(from a Visual Studio build) 这个文件,然后copy到C:\Python2.7\Lib\site-packages。搞定了,就这么简单。毕竟脚本语言,简直无情,\sources\samples下有很多python的例子,跑几个试试就知道是否安装好了。import cv2这句就可以导入cv2模块了

第二个问题也不用担心了,因为python不用声明变量的类型,实验了一下,发现得到的矩阵的数据类型就是array,稳了,直接拿来用

第三个问题也超简单,图像显示读写的模块、摄像头模块、鼠标键盘的响应模块都可以,跟c++的版本使用起来也差不多。

第四个问题我简单粗看了一遍书,没发现什么亮点,只是书中提到一个pygame可以用来做hgui效果还行,支持画画和编辑文本,不过好像对CV也没啥帮助,所以就没研究了。

补充几个我学习的时候遇见的问题:

opencv里的Rect数据结构在python里是没有对应类型的,这个要注意调用的时候需要注意。比如rectangle函数输入的就是矩形两个点的坐标,不是Rect。

还有就是opencv里的很多宏在python里需要加上cv2.cv前缀就可以生效了


from: http://blog.csdn.net/yang_xian521/article/category/910716




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值