精华内容
下载资源
问答
  • opencv图像识别

    千次阅读 2016-02-28 15:39:19
    利用OpenCV检测图像中的长方形画布或纸张并提取图像内容   问题如下: 也就是在一张照片里,已知有个长方形的物体,但是经过了透视投影,已经不再是规则的长方形,那么如何提取这个图形里的内容呢?...


    利用OpenCV检测图像中的长方形画布或纸张并提取图像内容



     
    问题如下:




    也就是在一张照片里,已知有个长方形的物体,但是经过了透视投影,已经不再是规则的长方形,那么如何提取这个图形里的内容呢?这是个很常见的场景,比如在博物馆里看到一幅很喜欢的画,用手机找了下来,可是回家一看歪歪斜斜,脑补原画内容又觉得不对,那么就需要算法辅助来从原图里提取原来的内容了。不妨把应用的场景分为以下:
    纸张四角的坐标(图中红点)已知的情况


    也就是上面的左图中4个红点是可以准确获取,比如手动标注,那么就简单了:用OpenCV的Perspective Transform就可以。具体步骤如下:
    1) 将标注好的四个点坐标存入一个叫corner的变量里,比如上面的例子中,原图的分辨率是300x400,定义x和y的方向如下:


    那么纸张的四角对应的坐标分别是:
    左上:157.6, 71.5
    右上:295.6, 118.4   右下:172.4, 311.3   左下:2.4, 202.4
     
    把这四个坐标按如上顺序放到一个叫corner的变量里。如果我们打算把这幅图案恢复到一个300x400的图像里,那么按照对应的顺序把下面四个坐标放到一个叫canvas的变量里:
    左上:0, 0
    右上:300, 0
    右下:300, 400   左下:0, 400
     
    假设原图已经用OpenCV读取到一个叫image的变量里,那么提取纸张图案的代码如下:
    1 M = cv2.getPerspectiveTransform(corners, canvas)
    2 result = cv2.warpPerspective(image, M, (0, 0))
    把左图剪裁出来,去掉红点后试了试,结果如下:


    当然,其实这一步用Photoshop就可以了。。
    纸张四角的坐标未知或难以准确标注的情况


    这种场景可能是小屏幕应用,或是原始图像就很小,比如我这里用的这个300x400例子,点坐标很难精确标注。这种情况下一个思路是,用边缘检测提取纸张四边,然后求出四角坐标,再做Perspective Transform。
     
    1) 图像预处理
    一般而言即使做普通的边缘检测也需要提前对图像进行降噪避免误测,比如最常见的办法是先对图像进行高斯滤波,然而这样也会导致图像变得模糊,当待检测图形边缘不明显,或是图像本身分辨率不高的情况下(比如本文用的例子),会在降噪的同时把待检测的边缘强度也给牺牲了。具体到本文的例子,纸张是白色,背景是浅黄带纹路,如果进行高斯滤波是显然不行的,这时候一个替代方案是可以考虑使用Mean Shift,Mean Shift的优点就在于如果是像背景桌面的浅色纹理,图像分割的过程中相当于将这些小的浮动过滤掉,并且保留相对明显的纸张边缘,结果如下:
    原图


    处理后


    Meanshift的代码:
    1 image = cv2.pyrMeanShiftFiltering(image, 25, 10)
    因为主要目的是预处理降噪,windows size和color distance都不用太大,避免浪费计算时间还有过度降噪。降噪后可以看到桌面上的纹理都被抹去了,纸张边缘附近干净了很多。然而这还远远不够,图案本身,和图像里的其他物体都有很多明显的边缘,而且都是直线边缘。


    2) 纸张边缘检测


    虽然降噪了,可是图像里还是有很多边缘明显的元素。怎么尽量只保留纸张的边缘呢,这时候可以考虑用分割算法,把图像分为纸张部分和其他部分,这样分割的mask边缘就和纸张边缘应该是差不多重合的。在这里可以考虑用GrabCut,这样对于简单的情况,比如纸张或画布和背景对比强烈的,直接把图像边缘的像素作为bounding box就可以实现自动分割。当自动分割不精确的情况下再引入手动辅助分割,具体到我这里用的例子,背景和画面接近,所以需要手动辅助:


    结果如下:


    可以看到,分割后的结果虽然能基本区分纸张形状了,可是边缘并不准确,另外键盘和部分桌面没能区分开来。这时可以继续用GrabCut+手动标注得到只有纸张的分割。或者为了用户友好的话,尽量少引入手动辅助,那么可以考虑先继续到下一步检测边缘,再做后期处理。假设我们考虑后者,那么我们得到的是如下的mask:


    这个mask并不精确,所以不能直接用于边缘检测,但是它大致标出了图片里最明显的边缘位置所在,所以可以考虑下面的思路:保留降噪后位于mask边缘附近的信息用于真正的边缘检测,而把其他部分都模糊处理,也就是说基于上面得到的mask做出下面的mask用于模糊处理:


    基于这个mask得到的用于边缘检测的图像如下:


    用canny算子检测出边缘如下:


    3) 直线检测


    对检测到的边缘使用Hough变换检测直线,我例子里用的是cv2.HoughLinesP,分辨率1像素和1°,可以根据图像大小设置检测的阈值和minLineLength去除大部分误检测。特别提一下的是如果使用OpenCV的Python binding,OpenCV 2和OpenCV 3的结果结构是不一样的,如果进行代码移植需要相应的修改。检测到的结果如下:


    可以看到,有些线几乎重合在一起了,这是难以避免的,上图中一共检测到9条线,其中两对(下、右边缘)重合。可以通过距离判断和直线相对角度来判断并把重合线段合为一条:


    剩下的都是没有重合的线了。
    4) 判断纸张边缘


    那么如何选取纸张边缘的四条线呢(即使图像分割步骤非常好得分开了纸张和其他部分,这在有些情况下还是难以避免的,比如图案里有和边缘平行的线条),可以沿着提取线段的两边采样像素的灰度:


    在线段的两个端点之间平均采样左右两边像素的值,因为一般来说如果是纸张或者画布,边缘和背景的颜色在四边上应该都是类似的。然而这样做的话引入另外一个问题是需要区分线段的“左”和“右”,对于线段本身而言就是要区分前后。所以需要对画面里所有的线段端点进行排序,而这个排序的基准就是相对画布。


    具体到本文的例子就是把图像中心定义为所有线段的“左”边,如上图。而决定线段端点“前”和“后”可以用如下办法:


    先假设线段的前后端点,将两个端点坐标分别减去中心点(红点)的坐标,然后将得到的两个向量a和b求叉积,如果叉积大于0则说明假设正确,如果<0则交换假设的前后端点。线段端点的顺序确定后就可以进行采样了,简单起见可以分别采样左右两侧的像素灰度值,如果希望更准确可以采样RGB通道的值进行综合比较,下面是7条线段对应的两侧像素灰度的中值分布:


    可以看到其中有4个点距离非常近(红色),说明他们的像素灰度分布也很接近,把这4条选出来,结果如下:


    正是要的结果。


    5) 计算四角的坐标


    接下来计算四条线的交点,方法点这里。因为有4条线,会得到6个结果,因为在这种应用场景中,方形的物体在透视变换下不会出现凹角,所以直接舍弃离纸张中心最远的两个交点就得到了四个角的坐标,结果如下:






    这样就回到了一开始四角坐标已经得到的情况,直接进行透视变换就行了。


    Camera Calibration?


    写了这么多,其实有一条至关重要的假设,甚至可以说是最关键的步骤之一我一直没提,那就是Camera Calibration,如果有相机的情况下,meta data都知道,那么需要先坐Camera Calibration才能知道纸张或者画布的原始尺寸。我这里试的例子当然是没有的,也可以有,相应的算法OpenCV里也有现成的,不过即便如此还是非常麻烦,所以我的所有流程都是默认原始尺寸已经获得了。再说了,就算没有,变换回方形之后使用者凭感觉进行简单轴缩放都比Camera Calibration方便得多。。


    ========


    用 Python 和 OpenCV 检测图片上的条形码



     
    这篇博文的目的是应用计算机视觉和图像处理技术,展示一个条形码检测的基本实现。我所实现的算法本质上基于StackOverflow 上的这个问题,浏览代码之后,我提供了一些对原始算法的更新和改进。


    首先需要留意的是,这个算法并不是对所有条形码有效,但会给你基本的关于应用什么类型的技术的直觉。


    假设我们要检测下图中的条形码:






    图1:包含条形码的示例图片


    现在让我们开始写点代码,新建一个文件,命名为detect_barcode.py,打开并编码:


    1 # import the necessary packages
    2 import numpy as np
    3 import argparse
    4 import cv2
    5
    6 # construct the argument parse and parse the arguments
    7 ap = argparse.ArgumentParser()
    8 ap.add_argument("-i", "--image", required = True, help = "path to the image file")
    9 args = vars(ap.parse_args())
    我们首先做的是导入所需的软件包,我们将使用NumPy做数值计算,argparse用来解析命令行参数,cv2是OpenCV的绑定。


    然后我们设置命令行参数,我们这里需要一个简单的选择,–image是指包含条形码的待检测图像文件的路径。


    现在开始真正的图像处理:


    11 # load the image and convert it to grayscale
    12 image = cv2.imread(args["image"])
    13 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    14
    15 # compute the Scharr gradient magnitude representation of the images
    16 # in both the x and y direction
    17 gradX = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 1, dy = 0, ksize = -1)
    18 gradY = cv2.Sobel(gray, ddepth = cv2.cv.CV_32F, dx = 0, dy = 1, ksize = -1)
    19
    20 # subtract the y-gradient from the x-gradient
    21 gradient = cv2.subtract(gradX, gradY)
    22 gradient = cv2.convertScaleAbs(gradient)
    12~13行:从磁盘载入图像并转换为灰度图。


    17~18行:使用Scharr操作(指定使用ksize = -1)构造灰度图在水平和竖直方向上的梯度幅值表示。


    21~22行:Scharr操作之后,我们从x-gradient中减去y-gradient,通过这一步减法操作,最终得到包含高水平梯度和低竖直梯度的图像区域。


    上面的gradient表示的原始图像看起来是这样的:






    图:2:条形码图像的梯度表示


    注意条形码区域是怎样通过梯度操作检测出来的。下一步将通过去噪仅关注条形码区域。


    ?
    24 # blur and threshold the image
    25 blurred = cv2.blur(gradient, (9, 9))
    26 (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
    25行:我们要做的第一件事是使用9*9的内核对梯度图进行平均模糊,这将有助于平滑梯度表征的图形中的高频噪声。


    26行:然后我们将模糊化后的图形进行二值化,梯度图中任何小于等于255的像素设为0(黑色),其余设为255(白色)。


    模糊并二值化后的输出看起来是这个样子:






    图3:二值化梯度图以此获得长方形条形码区域的粗略近似


    然而,如你所见,在上面的二值化图像中,条形码的竖杠之间存在缝隙,为了消除这些缝隙,并使我们的算法更容易检测到条形码中的“斑点”状区域,我们需要进行一些基本的形态学操作:


    28 # construct a closing kernel and apply it to the thresholded image
    29 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
    30 closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    29行:我们首先使用cv2.getStructuringElement构造一个长方形内核。这个内核的宽度大于长度,因此我们可以消除条形码中垂直条之间的缝隙。


    30行:这里进行形态学操作,将上一步得到的内核应用到我们的二值图中,以此来消除竖杠间的缝隙。


    现在,你可以看到这些缝隙相比上面的二值化图像基本已经消除:






    图4:使用形态学中的闭运算消除条形码竖条之间的缝隙


    当然,现在图像中还有一些小斑点,不属于真正条形码的一部分,但是可能影响我们的轮廓检测。


    让我们来消除这些小斑点:


    32 # perform a series of erosions and dilations
    33 closed = cv2.erode(closed, None, iterations = 4)
    34 closed = cv2.dilate(closed, None, iterations = 4)
    我们这里所做的是首先进行4次腐蚀(erosion),然后进行4次膨胀(dilation)。腐蚀操作将会腐蚀图像中白色像素,以此来消除小斑点,而膨胀操作将使剩余的白色像素扩张并重新增长回去。


    如果小斑点在腐蚀操作中被移除,那么在膨胀操作中就不会再出现。


    经过我们这一系列的腐蚀和膨胀操作,可以看到我们已经成功地移除小斑点并得到条形码区域。






    图5:应用一系列的腐蚀和膨胀来移除不相关的小斑点


    最后,让我们找到图像中条形码的轮廓:


    36 # find the contours in the thresholded image, then sort the contours
    37 # by their area, keeping only the largest one
    38 (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
    39  cv2.CHAIN_APPROX_SIMPLE)
    40 c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
    41
    42 # compute the rotated bounding box of the largest contour
    43 rect = cv2.minAreaRect(c)
    44 box = np.int0(cv2.cv.BoxPoints(rect))
    45
    46 # draw a bounding box arounded the detected barcode and display the
    47 # image
    48 cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
    49 cv2.imshow("Image", image)
    50 cv2.waitKey(0)
    38~40行:幸运的是这一部分比较容易,我们简单地找到图像中的最大轮廓,如果我们正确完成了图像处理步骤,这里应该对应于条形码区域。


    43~44行:然后我们为最大轮廓确定最小边框


    48~50行:最后显示检测到的条形码


    正如你在下面的图片中所见,我们已经成功检测到了条形码:






    图6:成功检测到示例图像中的条形码


    下一部分,我们将尝试更多图像。


    成功的条形码检测


    要跟随这些结果,请使用文章下面的表单去下载本文的源码以及随带的图片。


    一旦有了代码和图像,打开一个终端来执行下面的命令:


    $ python detect_barcode.py --image images/barcode_02.jpg




    图7:使用OpenCV检测图像中的一个条形码


    检测椰油瓶子上的条形码没有问题。


    让我们试下另外一张图片:


    $ python detect_barcode.py --image images/barcode_03.jpg




    图8:使用计算机视觉检测图像中的一个条形码


    我们同样能够在上面的图片中找到条形码。


    关于食品的条形码检测已经足够了,书本上的条形码怎么样呢:


    $ python detect_barcode.py --image images/barcode_04.jpg




    图9:使用Python和OpenCV检测书本上的条形码


    没问题,再次通过。


    那包裹上的跟踪码呢?


    $ python detect_barcode.py --image images/barcode_05.jpg




    图10:使用计算机视觉和图像处理检测包裹上的条形码


    我们的算法再次成功检测到条形码。


    最后,我们再尝试一张图片,这个是我最爱的意大利面酱—饶氏自制伏特加酱(Rao’s Homemade Vodka Sauce):


    $ python detect_barcode.py --image images/barcode_06.jpg




    图11:使用Python和Opencv很容易检测条形码


    我们的算法又一次检测到条形码!


    总结


    这篇博文中,我们回顾了使用计算机视觉技术检测图像中条形码的必要步骤,使用Python编程语言和OpenCV库实现了我们的算法。


    算法概要如下:


    计算x方向和y方向上的Scharr梯度幅值表示
    将x-gradient减去y-gradient来显示条形码区域
    模糊并二值化图像
    对二值化图像应用闭运算内核
    进行系列的腐蚀、膨胀
    找到图像中的最大轮廓,大概便是条形码
    需要注意的是,该方法做了关于图像梯度表示的假设,因此只对水平条形码有效。


    如果你想实现一个更加鲁棒的条形码检测算法,你需要考虑图像的方向,或者更好的,应用机器学习技术如Haar级联或者HOG + Linear SVM去扫描图像条形码区域。


    ========


    数字万用表(七段数码管)的图像识别(opencv实现)



    版权声明:欢迎转载,但请保留文章原始出处:)http://blog.csdn.net/xgbing
            最近接触图像处理,要实现数字万用表数据的自动读取。我使用opencv+VC2005环境开发,OpenCV是Intel 开源计算机视觉库,它提供了强大的图像处理函数库。Opencv的介绍在这里太不多说,可以看看百度百科了解一下:http://baike.baidu.com/view/1343775.htm。
            万用表的识别过程是先提取摄像头的一帧数据,然后对这幅图像做处理:


    (1)提取摄像头的一帧数据
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
    //读取摄像头一帧数据  
    img0=cvQueryFrame(m_Video);  


    (2)对图像进行平滑处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
    cvSmooth(src_img, src_img,CV_GAUSSIAN, 5, 0);  


    (3)图像的灰度处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        cvCvtColor(src_img, gray_img, CV_BGR2GRAY);  
      
        //灰度图像  
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow(PIC_GLAY_WINDOW_NAME, CV_WINDOW_AUTOSIZE);  
        cvShowImage(PIC_GLAY_WINDOW_NAME, gray_img);  
    #endif  


    (4)对图像进行直方图均衡化处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        IplImage* img_zf = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
        cvEqualizeHist(gray_img, img_zf);  
      
        cvReleaseImage(&gray_img);  
      
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow("直方图均衡化", CV_WINDOW_AUTOSIZE);  
        cvShowImage("直方图均衡化", img_zf);  
    #endif  


    (5)对图像进行二值化处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        //二值化图像  
        IplImage* pic2_img = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
      
        cvThreshold(img_zf, pic2_img, 50, 255, CV_THRESH_BINARY_INV);  
        cvReleaseImage(&img_zf);  
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow(PIC_2_WINDOW_NAME, CV_WINDOW_AUTOSIZE);  
        cvShowImage(PIC_2_WINDOW_NAME, pic2_img);  
    #endif  


    (6)细化处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        IplImage* img3 = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
        cvZero(img3);  
      
        cvThin(pic2_img, img3, 5);//细化,通过修改iterations参数进一步细化  
        cvReleaseImage(&pic2_img);  
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow("细化", CV_WINDOW_AUTOSIZE);  
        cvShowImage("细化", img3);  
    #endif  


    (7)图像腐蚀
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        IplImage* img4 = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
          
      
        /图像腐蚀  
    #if 1  
        cvErode(img3, img4, NULL, 1);  
        cvReleaseImage(&img3);  
      
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow("图像腐蚀", CV_WINDOW_AUTOSIZE);  
        cvShowImage("图像腐蚀", img4);    
    #endif  


    {8}图像膨胀
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
        ///图像膨胀  
        IplConvKernel *iplele = cvCreateStructuringElementEx(3, 3, 0, 0, CV_SHAPE_RECT);      
      
        cvDilate(img4, img4, iplele, 1);  
      
        cvReleaseStructuringElement(&iplele);  
          
    #ifdef SHOW_PROC_IMG  
        cvNamedWindow("图像膨胀", CV_WINDOW_AUTOSIZE);  
        cvShowImage("图像膨胀", img4);  
    #endif  


    (9)进一步细化处理
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
    IplImage* img3_2 = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
    cvZero(img3_2);  
      
    cvThin(img4, img3_2, 5);//细化,通过修改iterations参数进一步细化  
    cvCopy(img3_2, img4);  
    cvReleaseImage(&img3_2);  


    (10)查找轮廓,进行数字分割
    [cpp] view plain copy 在CODE上查看代码片派生到我的代码片
    IplImage* img5 = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );  
    cvCopy(img4, img5);  
      
    CvSeq *contour = NULL;  
    CvMemStorage* storage = cvCreateMemStorage(0);  
    cvFindContours( img5, storage, &contour, sizeof(CvContour),CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  
      
    cvReleaseImage(&img5);  


    (11)消除杂点并进行数字的识别


    ========


    opencv 几种图像识别方法的速度和准确率比较



    最近需要使用 opencv 做一个项目,比较了几种算法,貌似都不能满足我的需求,下面看一下试验结果。git 地址 https://github.com/fredjiang/yutianDetect.git


    接着上一篇博客 http://fred.easymorse.com/?p=1358,这里比较一下几种不同算法的优缺点


    Screen Shot 2013 04 30 at 3 47 18 PM


    如上图,我这里组合使用了不同的 featureDetector、descriptorExtractor、matcher,分别对速度和准确率做了比较。


    输入框中的数字对应上图中的 -detectImage_x,右上角的数字是时间(毫秒),X 和 V 表示是否识别到了对象


    速度:


    Screenshot 2013 04 30 15 26 44 Screenshot 2013 04 30 15 26 54


    Screenshot 2013 04 30 15 27 06 Screenshot 2013 04 30 15 27 22


    准确率:


    Screenshot 2013 04 30 15 28 01 Screenshot 2013 04 30 15 28 17


    Screenshot 2013 04 30 15 28 39 Screenshot 2013 04 30 15 28 54


    根据以上结果,我想在 1 秒以内正确识别不同的图像,要么是速度不够,要么是准确率不够。


    看来只能看看还有不有其它的算法了,或者使用 haartraining 了。


    再补充一个


    Screen Shot 2013 04 30 at 5 02 06 PM


    -detectImage_4(时间3544,又快了 200 毫秒左右)


    ========


    图像处理和图像识别中常用的OpenCV函数  





    1、cvLoadImage:将图像文件加载至内存;


    2、cvNamedWindow:在屏幕上创建一个窗口;


    3、cvShowImage:在一个已创建好的窗口中显示图像;


    4、cvWaitKey:使程序暂停,等待用户触发一个按键操作;


    5、cvReleaseImage:释放图像文件所分配的内存;


    6、cvDestroyWindow:销毁显示图像文件的窗口;


    7、cvCreateFileCapture:通过参数设置确定要读入的AVI文件;


    8、cvQueryFrame:用来将下一帧视频文件载入内存;


    9、cvReleaseCapture:释放CvCapture结构开辟的内存空间;


    10、cvCreateTrackbar:创建一个滚动条;


     


    11、cvSetCaptureProperty:设置CvCapture对象的各种属性;


    12、cvGetCaptureProperty:查询CvCapture对象的各种属性;


    13、cvGetSize:当前图像结构的大小;


    14、cvSmooth:对图像进行平滑处理;


    15、cvPyrDown:图像金字塔,降采样,图像缩小为原来四分之一;


    16、cvCanny:Canny边缘检测;


    17、cvCreateCameraCapture:从摄像设备中读入数据;


    18、cvCreateVideoWriter:创建一个写入设备以便逐帧将视频流写入视频文件;


    19、cvWriteFrame:逐帧将视频流写入文件;


    20、cvReleaseVideoWriter:释放CvVideoWriter结构开辟的内存空间;


     


    21、CV_MAT_ELEM:从矩阵中得到一个元素;


    22、cvAbs:计算数组中所有元素的绝对值;


    23、cvAbsDiff:计算两个数组差值的绝对值;


    24、cvAbsDiffS:计算数组和标量差值的绝对值;


    25、cvAdd:两个数组的元素级的加运算;


    26、cvAddS:一个数组和一个标量的元素级的相加运算;


    27、cvAddWeighted:两个数组的元素级的加权相加运算(alpha运算);


    28、cvAvg:计算数组中所有元素的平均值;


    29、cvAvgSdv:计算数组中所有元素的绝对值和标准差;


    30、cvCalcCovarMatrix:计算一组n维空间向量的协方差;


     


    31、cvCmp:对两个数组中的所有元素运用设置的比较操作;


    32、cvCmpS:对数组和标量运用设置的比较操作;


    33、cvConvertScale:用可选的缩放值转换数组元素类型;


    34、cvCopy:把数组中的值复制到另一个数组中;


    35、cvCountNonZero:计算数组中非0值的个数;


    36、cvCrossProduct:计算两个三维向量的向量积(叉积);


    37、cvCvtColor:将数组的通道从一个颜色空间转换另外一个颜色空间;


    38、cvDet:计算方阵的行列式;


    39、cvDiv:用另外一个数组对一个数组进行元素级的除法运算;


    40、cvDotProduct:计算两个向量的点积;


     


    41、cvEigenVV:计算方阵的特征值和特征向量;


    42、cvFlip:围绕选定轴翻转;


    43、cvGEMM:矩阵乘法;


    44、cvGetCol:从一个数组的列中复制元素;


    45、cvGetCols:从数据的相邻的多列中复制元素;


    46、cvGetDiag:复制数组中对角线上的所有元素;


    47、cvGetDims:返回数组的维数;


    48、cvGetDimSize:返回一个数组的所有维的大小;


    49、cvGetRow:从一个数组的行中复制元素值;


    50、cvGetRows:从一个数组的多个相邻的行中复制元素值;


     


    51、cvGetSize:得到二维的数组的尺寸,以CvSize返回;


    52、cvGetSubRect:从一个数组的子区域复制元素值;


    53、cvInRange:检查一个数组的元素是否在另外两个数组中的值的范围内;


    54、cvInRangeS:检查一个数组的元素的值是否在另外两个标量的范围内;


    55、cvInvert:求矩阵的逆;


    56、cvMahalonobis:计算两个向量间的马氏距离;


    57、cvMax:在两个数组中进行元素级的取最大值操作;


    58、cvMaxS:在一个数组和一个标量中进行元素级的取最大值操作;


    59、cvMerge:把几个单通道图像合并为一个多通道图像;


    60、cvMin:在两个数组中进行元素级的取最小值操作;


     


    61、cvMinS:在一个数组和一个标量中进行元素级的取最小值操作;


    62、cvMinMaxLoc:寻找数组中的最大最小值;


    63、cvMul:计算两个数组的元素级的乘积(点乘);


    64、cvNot:按位对数组中的每一个元素求反;


    65、cvNormalize:将数组中元素进行归一化;


    66、cvOr:对两个数组进行按位或操作;


    67、cvOrs:在数组与标量之间进行按位或操作;


    68、cvReduce:通过给定的操作符将二维数组简为向量;


    69、cvRepeat:以平铺的方式进行数组复制;


    70、cvSet:用给定值初始化数组;


     


    71、cvSetZero:将数组中所有元素初始化为0;


    72、cvSetIdentity:将数组中对角线上的元素设为1,其他置0;


    73、cvSolve:求出线性方程组的解;


    74、cvSplit:将多通道数组分割成多个单通道数组;


    75、cvSub:两个数组元素级的相减;


    76、cvSubS:元素级的从数组中减去标量;


    77、cvSubRS:元素级的从标量中减去数组;


    78、cvSum:对数组中的所有元素求和;


    79、cvSVD:二维矩阵的奇异值分解;


    80、cvSVBkSb:奇异值回代计算;


     


    81、cvTrace:计算矩阵迹;


    82、cvTranspose:矩阵的转置运算;


    83、cvXor:对两个数组进行按位异或操作;


    84、cvXorS:在数组和标量之间进行按位异或操作;


    85、cvZero:将所有数组中的元素置为0;


    86、cvConvertScaleAbs:计算可选的缩放值的绝对值之后再转换数组元素的类型;


    87、cvNorm:计算数组的绝对范数, 绝对差分范数或者相对差分范数;


    88、cvAnd:对两个数组进行按位与操作;


    89、cvAndS:在数组和标量之间进行按位与操作; 


    90、cvScale:是cvConvertScale的一个宏,可以用来重新调整数组的内容,并且可以将参数从一种数


                      据类型转换为另一种;


     


    91、cvT:是函数cvTranspose的缩写;


    92、cvLine:画直线;


    93、cvRectangle:画矩形;


    94、cvCircle:画圆;


    95、cvEllipse:画椭圆;


    96、cvEllipseBox:使用外接矩形描述椭圆;


    97、cvFillPoly、cvFillConvexPoly、cvPolyLine:画多边形;


    98、cvPutText:在图像上输出一些文本;


    99、cvInitFont:采用一组参数配置一些用于屏幕输出的基本个特定字体;


    100、cvSave:矩阵保存;


     


    101、cvLoad:矩阵读取;


    102、cvOpenFileStorage:为读/写打开存储文件;


    103、cvReleaseFileStorage:释放存储的数据;


    104、cvStartWriteStruct:开始写入新的数据结构;


    105、cvEndWriteStruct:结束写入数据结构;


    106、cvWriteInt:写入整数型;


    107、cvWriteReal:写入浮点型;


    108、cvWriteString:写入字符型;


    109、cvWriteComment:写一个XML或YAML的注释字串;


    110、cvWrite:写一个对象;


     


    111、cvWriteRawData:写入多个数值;


    112、cvWriteFileNode:将文件节点写入另一个文件存储器;


    113、cvGetRootFileNode:获取存储器最顶层的节点;


    114、cvGetFileNodeByName:在映图或存储器中找到相应节点;


    115、cvGetHashedKey:为名称返回一个惟一的指针;


    116、cvGetFileNode:在映图或文件存储器中找到节点;


    117、cvGetFileNodeName:返回文件的节点名;


    118、cvReadInt:读取一个无名称的整数型;


    119、cvReadIntByName:读取一个有名称的整数型;


    120、cvReadReal:读取一个无名称的浮点型;


     


    121、cvReadRealByName:读取一个有名称的浮点型;


    122、cvReadString:从文件节点中寻找字符串;


    123、cvReadStringByName:找到一个有名称的文件节点并返回它;


    124、cvRead:将对象解码并返回它的指针;


    125、cvReadByName:找到对象并解码;


    126、cvReadRawData:读取多个数值;


    127、cvStartReadRawData:初始化文件节点序列的读取;


    128、cvReadRawDataSlice:读取文件节点的内容;


    129、cvGetModuleInfo:检查IPP库是否已经正常安装并且检验运行是否正常;


    130、cvResizeWindow:用来调整窗口的大小;


     


    131、cvSaveImage:保存图像;


    132、cvMoveWindow:将窗口移动到其左上角为x,y的位置;


    133、cvDestroyAllWindow:用来关闭所有窗口并释放窗口相关的内存空间;


    134、cvGetTrackbarPos:读取滑动条的值;


    135、cvSetTrackbarPos:设置滑动条的值;


    136、cvGrabFrame:用于快速将视频帧读入内存;


    137、cvRetrieveFrame:对读入帧做所有必须的处理;


    138、cvConvertImage:用于在常用的不同图像格式之间转换;


    139、cvErode:形态腐蚀;


    140、cvDilate:形态学膨胀;


     


    141、cvMorphologyEx:更通用的形态学函数;


    142、cvFloodFill:漫水填充算法,用来进一步控制哪些区域将被填充颜色;


    143、cvResize:放大或缩小图像;


    144、cvPyrUp:图像金字塔,将现有的图像在每个维度上都放大两倍;


    145、cvPyrSegmentation:利用金字塔实现图像分割;


    146、cvThreshold:图像阈值化;


    147、cvAcc:可以将8位整数类型图像累加为浮点图像;


    148、cvAdaptiveThreshold:图像自适应阈值;


    149、cvFilter2D:图像卷积;


    150、cvCopyMakeBorder:将特定的图像轻微变大,然后以各种方式自动填充图像边界;


    151、cvSobel:图像边缘检测,Sobel算子;


    152、cvLaplace:拉普拉斯变换、图像边缘检测;


    153、cvHoughLines2:霍夫直线变换;


    154、cvHoughCircles:霍夫圆变换;


    155、cvRemap:图像重映射,校正标定图像,图像插值;


    156、cvWarpAffine:稠密仿射变换;


    157、cvGetQuadrangleSubPix:仿射变换;


    158、cvGetAffineTransform:仿射映射矩阵的计算;


    159、cvCloneImage:将整个IplImage结构复制到新的IplImage中;


    160、cv2DRotationMatrix:仿射映射矩阵的计算;


    161、cvTransform:稀疏仿射变换;


    162、cvWarpPerspective:密集透视变换(单应性);


    163、cvGetPerspectiveTransform:计算透视映射矩阵;


    164、cvPerspectiveTransform:稀疏透视变换;


    165、cvCartToPolar:将数值从笛卡尔空间到极坐标(极性空间)进行映射;


    166、cvPolarToCart:将数值从极性空间到笛卡尔空间进行映射;


    167、cvLogPolar:对数极坐标变换;


    168、cvDFT:离散傅里叶变换;


    169、cvMulSpectrums:频谱乘法;


    170、cvDCT:离散余弦变换;


    171、cvIntegral:计算积分图像;


    172、cvDistTransform:图像的距离变换;


    173、cvEqualizeHist:直方图均衡化;


    174、cvCreateHist:创建一新直方图;


    175、cvMakeHistHeaderForArray:根据已给出的数据创建直方图;


    176、cvNormalizeHist:归一化直方图;


    177、cvThreshHist:直方图阈值函数;


    178、cvCalcHist:从图像中自动计算直方图;


    179、cvCompareHist:用于对比两个直方图的相似度;


    180、cvCalcEMD2:陆地移动距离(EMD)算法;


    181、cvCalcBackProject:反向投影;


    182、cvCalcBackProjectPatch:图块的方向投影;


    183、cvMatchTemplate:模板匹配;


    184、cvCreateMemStorage:用于创建一个内存存储器;


    185、cvCreateSeq:创建序列;


    186、cvSeqInvert:将序列进行逆序操作;


    187、cvCvtSeqToArray:复制序列的全部或部分到一个连续内存数组中;


    188、cvFindContours:从二值图像中寻找轮廓;


    189、cvDrawContours:绘制轮廓;


    190、cvApproxPoly:使用多边形逼近一个轮廓;


    191、cvContourPerimeter:轮廓长度;


    192、cvContoursMoments:计算轮廓矩;


    193、cvMoments:计算Hu不变矩;


    194、cvMatchShapes:使用矩进行匹配;


    195、cvInitLineIterator:对任意直线上的像素进行采样;


    196、cvSampleLine:对直线采样;


    197、cvAbsDiff:帧差;


    198、cvWatershed:分水岭算法;


    199、cvInpaint:修补图像;


    200、cvGoodFeaturesToTrack:寻找角点;


    201、cvFindCornerSubPix:用于发现亚像素精度的角点位置;


    202、cvCalcOpticalFlowLK:实现非金字塔的Lucas-Kanade稠密光流算法;


    203、cvMeanShift:mean-shift跟踪算法;


    204、cvCamShift:camshift跟踪算法;


    205、cvCreateKalman:创建Kalman滤波器;


    206、cvCreateConDensation:创建condensation滤波器;


    207、cvConvertPointsHomogenious:对齐次坐标进行转换;


    208、cvFindChessboardCorners:定位棋盘角点;


    209、cvFindHomography:计算单应性矩阵;


    210、cvRodrigues2:罗德里格斯变换;


    211、cvFitLine:直线拟合算法;


    212、cvCalcCovarMatrix:计算协方差矩阵;


    213、cvInvert:计算协方差矩阵的逆矩阵;


    214、cvMahalanobis:计算Mahalanobis距离;


    215、cvKMeans2:K均值;


    216、cvCloneMat:根据一个已有的矩阵创建一个新矩阵;


    217、cvPreCornerDetect:计算用于角点检测的特征图;


    218、cvGetImage:CvMat图像数据格式转换成IplImage图像数据格式;


    219、cvMatMul:两矩阵相乘;
    ========
    展开全文
  • Opencv图像识别从零到精通(37)----KNN算法 一 KNN简介 K最近邻(k-Nearest Neighbor,KNN)分类算法,该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个...

    Opencv图像识别从零到精通(37)----KNN算法

    一 KNN简介     K最近邻(k-Nearest Neighbor,KNN)分类算法,该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。你可以简单的理解为由那离自己最近的K个点来投票决定待分类数据归为哪一类。     KNN算法的过程为:     选择一种距离计算方式, 通过数据所有的特征计算新数据与已...
    阅读(740) 评论(0)

    Opencv图像识别从零到精通(36)----DFT离散傅里叶变换

    这篇就是图像的时域到频域的开始,也是信号处理中比较常见的傅立叶变换。一、傅立叶图像  对一张图像使用傅立叶变换就是将它分解成正弦和余弦两部分。也就是将图像从空间域(spatial domain)转换到频域(frequency domain)。 这一转换的理论基础来自于以下事实:任一函数都可以表示成无数个正弦和余弦函数的和的形式。傅立叶变换就是一个用来将函数分解的工具。 2维图像的傅立叶...
    阅读(2869) 评论(0)

    Opencv图像识别从零到精通(35)---SURF

    SIFT在前面已经说过了,可以说在实现过程中是精益求精,用了各种手段来删除不符合条件的特征点,同时也得到了很好的效果但是实时性不高,于是就有了SURF(speeded up robusr features).SURF是一种尺度,旋转不变的detector和descriptor.最大的特点是快!在快的基础上保证性能(repeatability,distinctiveness和robustne...
    阅读(3329) 评论(0)

    Opencv图像识别从零到精通(34)---SIFI

    一、理论知识  Scale Invariant Feature Transform,尺度不变特征变换匹配算法,对于算法的理论介绍,可以参考这篇文章http://blog.csdn.net/qq_20823641/article/details/51692415,里面很详细,可以更好的学习。这里就不多介绍。后面就挑选重点的来说二、SIFT 主要思想  SIFT算法是一种提取局部特征的...
    阅读(1594) 评论(0)

    Opencv图像识别从零到精通(33)----moravec角点、harris角点

    一、角点    图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints)、特征点(feature points) 被大量用于解决物体识别,图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析。如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那...
    阅读(1846) 评论(0)

    Opencv图像识别从零到精通(32)----直方图对比,模版匹配,方向投影

    0、预备知识归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。函数原型:void normalize(InputArray src,OutputArray dst, double alpha=1,doublebeta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )...
    阅读(2572) 评论(0)

    Opencv图像识别从零到精通(31)----图像修补,分离合并通道

    一、图像修复简介       图像修复是图像复原中的一个重要内容,其目的是利用图像现有的信息来恢复丢失的信息。可用于旧照片中丢失信息的恢复,视频文字去除以及视频错误隐藏等。简言之,图像修复就是对图像上信息缺损区域进行信息填充的过程,其目的就是为了对有信息缺损的图像进行复原,并且使得观察者无法察觉到图像曾经缺损或者已经修复     图像修复技术简单来说,就是利用那些被破坏区域的边缘,即是...
    阅读(1719) 评论(0)

    Opencv图像识别从零到精通(30)---重映射,仿射变换

    一、序言面对图像处理的时候,我们会旋转缩放图像,例如前面所提高的resize 插值改变,也是几何变换:几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标。这时就需要灰度级差值将映射的新坐标匹配到输出像素之间。最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿。...
    阅读(3193) 评论(2)

    Opencv图像识别从零到精通(29)-----图像金字塔,向上上下采样,resize插值

    金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低                                                      一、两个金字塔高斯金字塔(Gaussianpyramid): 用来向下采样,主要的图像金字塔拉普拉斯金字塔(Laplacianpyra...
    阅读(2211) 评论(1)

    Opencv图像识别从零到精通(28)----Kmeans

    K-means算法算是个著名的聚类算法了,不仅容易实现,并且效果也不错,训练过程不需人工干预,实乃模式识别等领域的居家必备良品啊,今天就拿这个算法练练手。属于无监督学习中间接聚类方法中的动态聚类流程:1.随机选取样本中的K个点作为聚类中心2.计算所有样本到各个聚类中心的距离,将每个样本规划在最近的聚类中3.计算每个聚类中所有样本的中心,并将新的中心代替原来的中心4.检查...
    阅读(1505) 评论(0)

    Opencv图像识别从零到精通(27)---grabcut

    图割graph cuts ----grad cut       Graph Cuts算法是用来确定网络流的最小分割,即寻找一个容量最小的边的集合,去掉这个集合中的所有边就可以阻挡这个网络了。需要注意的是,通常所说的Graph Cuts算法是指的采用最大流-最小分割来优化的模型,其它的Graph Cutting算法一般用graphpartitioning这个名词来代替。  首先还得先...
    阅读(1538) 评论(0)

    Opencv图像识别从零到精通(26)---分水岭

    分水岭是区域分割三个方法的最后一个,对于前景背景的分割有不错的效果。      分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢...
    阅读(5818) 评论(0)

    Opencv图像识别从零到精通(25)------区域分裂与合并

    区域分割一般认为有漫水填充,区域分裂与合并,分水岭,这篇是中间的区域分裂和合并。        区域分裂合并算法的基本思想是先确定一个分裂合并的准则,即区域特征一致性的测度,当图像中某个区域的特征不一致时就将该区域分裂成4 个相等的子区域,当相邻的子区域满足一致性特征时则将它们合成一个大区域,直至所有区域不再满足分裂合并的条件为止.   当分裂到不能再分的情况时,分裂结束,然后它将查找相邻...
    阅读(2922) 评论(0)

    Opencv图像识别从零到精通(24)------漫水填充,种子填充,区域生长、孔洞填充

    可以说从这篇文章开始,就结束了图像识别的入门基础,来到了第二阶段的学习。在平时处理二值图像的时候,除了要进行形态学的一些操作,还有有上一节讲到的轮廓连通区域的面积周长标记等,还有一个最常见的就是孔洞的填充,opencv这里成为漫水填充,其实也可以叫种子填充,或者区域生长,基本的原理是一样的,但是应用的时候需要注意一下,种子填充用递归的办法,回溯算法,漫水填充使用堆栈,提高效率,同时还提供了一种方式...
    阅读(3104) 评论(0)

    Opencv图像识别从零到精通(23)----轮廓

    当看到轮廓的时候,发现没有办法具体到什么, 因为关系轮廓的东西似乎有很多,例如检测轮廓,提取轮廓,轮廓跟踪,轮廓面积,周长,标记,匹配,还有一系列的外接最小矩形,圆形,椭圆,图像矩,填充孔洞等,不得不说东西真的很好。轮廓其实最容易和边缘检测联系到一起,有很多的相同,但是我理解的是边缘是检测,是预处理,而轮廓就可能是你要用的特征。一、函数:一个是找,一个是画void findContou...
    阅读(2825) 评论(0)

    Opencv图像识别从零到精通(22)-----hough变换检测直线与圆

    今天要看的是霍夫变换,常用用来检测直线和圆,这里是把常见的笛卡尔坐标系转换成极坐标下,进行累计峰值的极大值,确定。HoughLines,HoughLinesP,HoughCircles,三个函数,首先先看看原理,最后会用漂亮的matlab图,来回归一下,霍夫直线变换。霍夫线变换:众所周知, 一条直线在图像二维空间可由两个变量表示. 例如:在 笛卡尔坐标系...
    阅读(2360) 评论(0)

    Opencv图像识别从零到精通(21)-----canny算子边缘检测

    最后来看看canny算子,这个是被成为最好的算子,因为过程多,有准测,后面会列出来,也是边缘检测的最后一个,所以这里作为结尾,来看看各个边缘检测的效果。边缘检测结果比较Roberts算子检测方法对具有陡峭的低噪声的图像处理效果较好,但是利用roberts算子提取边缘的结果是边缘比较粗,因此边缘的定位不是很准确。Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel...
    阅读(2145) 评论(0)

    Opencv图像识别从零到精通(20)---laplace LOG DOG边缘检测

    经过了上一篇的简单的边缘检测,现在来看一下二阶导数的边缘检测,分别是Laplace LOG DOG,看到他们心里还是有点遗憾,要是自己能加快一点学习的步伐,在面试的时候也许就可以轻松回答了,亲爱的你们只是来的晚了2天。希望和我一样的同学,要加快脚步,认真学习了。废话不再多说,让我看看是怎么回事。一、Laplacian    Laplacian算子定义为表示成...
    阅读(2151) 评论(0)

    Opencv图像识别从零到精通(19)----Robert,prewitt,Sobel边缘检测

    图像的边缘检测,是根据灰度的突变或者说不连续来检测,对于其中的算子有一阶导数和二价导数,这里先说基础的三种方法。         一梯度          首先介绍下梯度,梯度并非是一个数值,梯度严格意义上是一个向量,这个向量指向当前位置变化最快的方向,可以这么理解,当你站在一个山上,你有360°的方向可以选择,哪个方向下降速度最快(最陡峭),便是梯度方向,梯度的长度,表示为向量的长度,表...
    阅读(5062) 评论(1)

    Opencv图像识别从零到精通(18)-------击中击不中

    在我们学习了膨胀腐蚀和基于膨胀腐蚀的变化之后,我比较喜欢的一个是击中击不中,因为喜欢所以就要单独列出来,心里总是觉得他可以有很多的用处,以后模版匹配,特征检测都会用,更深入的是,他会加深对膨胀腐蚀的理解,是一个很好的例子。下面先看一个算法步骤和原理:Hit-miss算法步骤:击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。它的原理就是使用腐蚀;如果要在一幅图像A上找...
    阅读(1912) 评论(0)
    展开全文
  • 步骤: 1先读取视频(or图片)文件 2将图像转换为hsv 3通过判断hsv值范围识别颜色 hsv范围颜色对应: ...示例:识别视频中的黄色区域...opencv2\opencv.hpp> using namespace cv; using namespace std; int H, S...

    步骤:

    1先读取视频(or图片)文件

    2将图像转换为hsv

    3通过判断hsv值范围识别颜色

    hsv范围颜色对应:

     示例:识别视频中的黄色区域,并变成白色显示

    #include <iostream>
    #include <opencv2\opencv.hpp>
    using namespace cv;
    using namespace std;
    int H, S, V;
    
    void GetHSV(Mat &image, int div = 64)
    {
    	int nl = image.rows;         //行数
    	int nc = image.cols;         //列数
    
    	for (int j = 0; j < nl; j++)
    	{
    		for (int i = 0; i < nc; i++)
    		{
    			H = image.at<Vec3b>(j, i)[0];
    			S = image.at<Vec3b>(j, i)[1];
    			V = image.at<Vec3b>(j, i)[2];
    			//cout << "H=" << H << "S=" << S << "V=" << V << endl;
    
    			if ((H >= 0) && (H <= 180) && (S >= 0) && (S <= 255) && (V >= 0) && (V <= 46))            //检测黑色
    			{
    				image.at<Vec3b>(j, i)[0] = 0;
    				image.at<Vec3b>(j, i)[1] = 0;
    				image.at<Vec3b>(j, i)[2] = 255;
    			}
    		}
    	}
    }
    
    int main()
    {
    
    	VideoCapture capture(0);
    	while (1)
    	{
    		Mat frame, hsv;                    //定义一个Mat变量,用于存储每一帧的图像
    		char input;
    		capture >> frame;
    		cvtColor(frame, hsv, COLOR_BGR2HSV);
    		GetHSV(hsv);
    		cvtColor(hsv, hsv, CV_HSV2BGR);
    
    		imshow("转换图", hsv);
    		imshow("原图", frame);
    		input = waitKey(100);
    		if (waitKey(50) == 27)
    			break;
    	}
    	return 0;
    }
    

     

    展开全文
  • opencv形状识别学习总结

    万次阅读 多人点赞 2016-03-16 13:20:30
    OpenCV基元检测 Primitive Detection 目录 基元的概念 基元泛指图像中有特点的单元。常说的基元有:边缘、角点、斑点、直线段、圆、等 基元检测是图像分析的基础 边缘(Edge)检测 边缘是图像...

    OpenCV基元检测 Primitive Detection

     


    目录
    基元的概念
    基元泛指图像中有特点的单元。常说的基元有:边缘、角点、斑点、直线段、圆、等
    基元检测是图像分析的基础

     

     

     

     

    边缘(Edge)检测

     

     

     

     

    边缘是图像中像素灰度值发生剧烈变化而不连续的结果
    边缘是赋予单个像素的一种性质,与图像函数在该像素的一个邻域内的梯度特性相关
    边缘幅值:梯度的幅值
    边缘方向:梯度方向旋转-90度

     

    边缘检测既是常见基元检测的基础,也是基于边界的图像分割的第一步。

     

    边缘检测算法
    OpenCV边缘检测:Sobel、拉普拉斯算子
    OpenCV边缘检测:坎尼算子算子


    斑点(Blob)检测
    斑点:与周围灰度有一定差别的区域
    面部的雀斑
    卫星照片中的一棵数
    钢材X光照片中的杂质或气泡

     

    医学图像中的细微肿块

     

     

    斑点检测算法
    OpenCV LoG算子:SIFT算法
    OpenCV Blob特征检测算子

    角点(Conner)检测
    角点:物体的拐角、交叉点、 曲线上曲率最大的点等

     

    角点的邻域是图像中信息比较丰富的区域

     

     

    角点检测方法
    基于边缘的方法:在小邻域内有两个不同的主边缘方向,实际图像中,孤立点、线段端点也会有类似特
    性。缺点是:1)需要先提取边缘并编码,计算量大;2)局部变化对稳定性影响大。

     

    基于灰度的方法:计算点的曲率和梯度,目前的主流

     

     

    角点检测算法:
    OpenCV 角点检测:Harris算子

     

     

     

    哈夫变换-几何形状检测

     

     

     

     

    基本哈夫变换:直线检测
    点–线对偶性:直线所在的图像空间(记为XY)和参数空间PQ(p斜率,q截距)之间的一一映射
    XY空间中的直线检测就等同于PQ空间的点检测
    基本哈夫变换:曲线检测
    对于任意能够用f(x,c)=0(其中x是图像点坐标矢量,c是参数矢量)表示曲线或目标轮廓,均可用类似

    的方法检测,只是计算复杂度随着c维数的增加而增加,需要考虑降维
    广义哈夫变换:目标检测
    问题:待检目标不是参数化曲线(如正方形),而只是一组轮廓点,希望自动检测目标的存在及其中心


    参考点(p,q)
    广义哈夫变换能够检测到特定目标的位置(即参考点(p,q) ),或者说任意位置的待检目标都是可以发

    现的,满足平移不变性

     

    多尺度检测

     

    万物都有其合适的尺度
    原子和基本粒子:普朗克常数
    集成电路:微米、纳米
    人、车、树、建筑:米-厘米-毫米
    地理:千米
    太空:光年
    多分辨率 与 尺度空间
    多分辨率( 图像金字塔):(低通滤波)再下采样,多级进行形成金字塔;可能出现假结构.
    尺度空间(Wikin’83):用一列单参数、宽度递增的高斯滤波器将原始信号滤波而得到的一组低频信号

    ;高斯核是实现尺度变换的唯一变换核,具有多种优良性质,不会引入假信号

    OpenCV 尺度空间与图像金字塔

    http://blog.csdn.net/xiaowei_cqu

    ========

    利用opencv识别并提取图片中的矩形

     


    这次是利用opencv来识别图片中的矩形。 
    其中遇到的问题主要是识别轮廓时矩形内部的形状导致轮廓不闭合。 
    过程如下:


    1. 对输入灰度图片进行高斯滤波 
    2. 做灰度直方图,提取阈值,做二值化处理 
    3. 提取图片轮廓 
    4. 识别图片中的矩形 
    5. 提取图片中的矩形

    1.对输入灰度图片进行高斯滤波

        cv::Mat src = cv::imread("F:\\t13.bmp",CV_BGR2GRAY);
        cv::Mat hsv;
        GaussianBlur(src,hsv,cv::Size(5,5),0,0);
    2.做灰度直方图,提取阈值,做二值化处理 
    由于给定图片,背景是黑色,矩形背景色为灰色,矩形中有些其他形状为白色,可以参考为: 
    提取轮廓时,矩形外部轮廓并未闭合。因此,我们需要对整幅图做灰度直方图,找到阈值,进行二值化

    处理。即令像素值(黑色)小于阈值的,设置为0(纯黑色);令像素值(灰色和白色)大于阈值的,设

    置为255(白色)

     

     

     

     

     

     

    // Quantize the gray scale to 30 levels
    int gbins = 16;
    int histSize[] = {gbins};
       // gray scale varies from 0 to 256
    float granges[] = {0,256};
    const float* ranges[] = { granges };
    cv::MatND hist;
    // we compute the histogram from the 0-th and 1-st channels
    int channels[] = {0};
    
    //calculate hist
    calcHist( &hsv, 1, channels, cv::Mat(), // do not use mask
                hist, 1, histSize, ranges,
                true, // the histogram is uniform
                false );
    //find the max value of hist
    double maxVal=0;
    minMaxLoc(hist, 0, &maxVal, 0, 0);
    
    int scale = 20;
    cv::Mat histImg;
    histImg.create(500,gbins*scale,CV_8UC3);
    
    //show gray scale of hist image
    for(int g=0;g<gbins;g++){
        float binVal = hist.at<float>(g,0);
        int intensity = cvRound(binVal*255);
        rectangle( histImg, cv::Point(g*scale,0),
                           cv::Point((g+1)*scale - 1,binVal/maxVal*400),
                            CV_RGB(0,0,0),
                           CV_FILLED );
    }
    cv::imshow("histImg",histImg);
    
    //threshold processing
    cv::Mat hsvRe;
    threshold( hsv, hsvRe, 64, 255,cv::THRESH_BINARY);

     

     

     

    3.提取图片轮廓 
    为了识别图片中的矩形,在识别之前还需要提取图片的轮廓。在经过滤波、二值化处理后,轮廓提取后

    的效果比未提取前的效果要好很多。


    4.识别矩形 
    识别矩形的条件为:图片中识别的轮廓是一个凸边形、有四个顶角、所有顶角的角度都为90度。 
    具体可以参考: 
    http://opencv-code.com/tutorials/detecting-simple-shapes-in-an-image/

     

     

     

     

     

    vector<Point> approx;
    
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(Mat(contours[i]), approx, 
                     arcLength(Mat(contours[i]), true)*0.02, true);
    
        if (approx.size() == 4 &&
            fabs(contourArea(Mat(approx))) > 1000 &&
            isContourConvex(Mat(approx)))
        {
            double maxCosine = 0;
    
            for( int j = 2; j < 5; j++ )
            {
                double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                maxCosine = MAX(maxCosine, cosine);
            }
    
            if( maxCosine < 0.3 )
                squares.push_back(approx);
        }
    }

     

    5.提取图片中的矩形 
    由于图片中矩形倾斜角度不太大,所以没有做倾斜校正这步操作 
    这是主函数提取部分代码
     

        //get rect from image
        std::vector<int> compression_params;
        compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
        compression_params.push_back(9);
    
        for(int i=0;i<squares.size();i++){
            int rect[4],*tmp;
            tmp = findRectInfo(squares[i]);
            for(int j=0;j<4;j++)
                rect[j] = *(tmp+j);
            cv::Rect roi(rect[1],rect[0],rect[3],rect[2]);
            cv::Mat roi_of_image = src(roi);
    
            char * filename = new char[100];
            sprintf(filename,"F:\\vs\\ConsoleApplication2\\resultPic_t35\\%i.png",i);
            cv::imwrite(filename,roi_of_image,compression_params);
        }

     

     

    这是计算每个矩形的点x,y坐标和长宽值

     

     

     

     

     

     

    int* findRectInfo(std::vector<cv::Point> rect)
    {
        int rectInfo[4] = {0};
        int x[4]= {0},y[4]= {0};
        int maxX = 0,maxY = 0,minX = 2000,minY = 2000;
        //get the rect points
        for(int i=0;i<4;i++){
            x[i] = rect[i].x;
            y[i] = rect[i].y;
            if(maxX<x[i])
                maxX = x[i];
            if(maxY<y[i])
                maxY = y[i];
            if(minX>x[i])
                minX = x[i];
            if(minY>y[i])
                minY = y[i];
        }
        rectInfo[0] = minY;
        rectInfo[1] = minX;
        rectInfo[2] = maxY - minY;
        rectInfo[3] = maxX - minX;
        return rectInfo;
    }


    识别并提取结果为: 

     

    利用opencv识别并提取图片中的矩形

    Reference: 
    1.http://opencv-code.com/tutorials/detecting-simple-shapes-in-an-image/ 
    2.http://stackoverflow.com/questions/8667818/opencv-c-obj-c-detecting-a-sheet-of-paper-

    square-detection 
    3.http://blog.csdn.net/timidsmile/article/details/8519751 
    4.http://blog.163.com/lee_020/blog/static/1247556020136473917915/
    ========

    OpenCV实现Hough变换检测圆形

          在图像处理中,Hough变换(霍夫变换)主要用来识别已知的几何形状,最常见的比如直线、线段

    、圆形、椭圆、矩形等。如果要检测比较复杂的曲线图形,就需要利用广义霍夫变换。

          霍夫变换的原理是根据参数空间的统计规律进行参数估计。

          具体说来就是,将直角坐标系中的图形(x,y)变换到参数空间(k1,...,kn),对直角坐标系中的每

    一个像素点,计算它在参数空间里的所有可能的参数向量。处理完所有像素点后,把出现次数(频率)

    最多的(一个或几个)参数向量的坐标作为参数代入直角坐标方程,即检测到的图形方程。

          以直线检测为例,详细讲一下步骤:(圆和直线的原理相同,只是直线的公式比较好打~)

          1.图像二值化,待检测的线变为黑色,背景置为白色。既然是形状检测,这步是必不可少的。

          2.假设直线的参数方程为p=x*cosa+y*sina,对于直线上的某个点(x,y)来说,变换到参数空间的

    坐标就是(p,a),而且这条直线上的所有点都对应于(p,a)。对于一个固定点(x,y)来说,经过它的直线系

    可以表示为p=(x^2+y^2)^1/2*sin(a+b),其中tanb=x/y,对应参数空间里的一条正弦曲线。也就是说,

    图像中的一条直线对应参数空间的一点,图像中的一点对应参数空间的一条正弦曲线。
          
    关于参数变换,我再白话几句。如果直线方程写成y=k*x-b,则对应于参数空间里的点(k,-b),这就有点

    像图论中的对偶变换了。在写图的程序时有时会遇到若干半平面求交的问题(整张平面被一条直线分割

    后得到两张半平面)。半平面求交关键在于找到求交后的边界(如果交集非空),既可以使用递增式算

    法(在已经找到的一部分边界基础上引入下一张半平面的直线求下一步的边界),也可以使用上面提到

    的参数变换方法。

          比如我想求几张方向都朝上(y轴正方向)的半平面的交,我想得到的应该是一个下侧以向下凸的

    折线为边界的上侧无穷的区域。我的问题关键在于找到这条下凸的折线。直线y=k*x-b做参数变换,得到

    点(k,-b),所有半平面的边界直线经变换得到若干个点。这些点形成的点集存在一个凸包(包含点集的

    最小凸多边形,而且该多边形每个顶点都来自点集),其中构成折线的直线所对应的点恰好是凸包的上

    半部分,也就是“下包络”变换成上凸包。而求点集的上凸包可是很简单的(也是增量式算法)。

          3.把参数空间分割为n*m个格子,得到参数矩阵,矩阵元(pi,aj)的初始值均为0,用来对参数计数

    。计数值代表这个参数是最终结果的可能性,计数值越大,说明落在这条直线上的像素点越多,也就说

    明它越有可能是我们想找到的参数。p的范围可以是[0,图像对角线长度],a的范围可以是[0,PI/2](如

    果取左上角为原点的话),但要包含整个图像。

          4.按照栅格顺序扫描图像,遇到黑色像素就做如下操作:

            pi的i从0取到n-1,对每一个pi,把它和像素点的坐标(x,y)代入参数方程,计算得到相应的ai

    ,如果ai在定义域范围内(或者在图像内),将矩阵元(pi,ai)加一。

            处理完所有像素后,如果想识别d条直线,就在参数矩阵中找到前d个数值最大的矩阵元,他们

    的坐标作为方程参数,在直角坐标系绘制出直线就可以了。

          OpenCV中提供了计算霍夫变换的库函数HoughLines和HoughLinesP,想知道怎样使用,请戳传送门



          圆形检测的过程很类似,只是参数方程有变化,而且参数空间增加了一个维度(圆心坐标x,y和半

    径r)。

          霍夫变换的一个好处就是不需要图像中出现完整的圆,只要落在一个圆上的像素数量足够多,就

    能正确识别。

          关于误差的问题:如果待检测像素没有严格落在同一个圆上,比如构成圆的圆弧彼此有些错位,

    如果依据参数点最多准则,只会识别出弧长最长的圆弧而忽略其他本来也属于同一个圆的圆弧。如果目

    标是检测不止一个圆,这种误差可能会使得程序依据同一个圆上的几个圆弧识别到几个不同的圆。解决

    这个问题一种方法是仍然采用参数点最多准则,但减小参数空间分割的份数,让错位圆弧的圆心落在同

    一个参数矩阵元上,但这样做会使检测到的圆心位置有比较大的误差。另一种方法是仍然把参数空间细

    密分割,用聚类算法寻找可能的圆心,因为错位圆弧的圆心彼此靠得很近而且计数值都很大,只要找到

    这些点的外接圆圆心就可以了。

          下面为了计算简便,我给出只检测一个半径为100的圆形的代码(要想采用聚类算法,只需修改第

    71-81行的代码块):
     

    #include "stdafx.h"
    #include "highgui.h"
    #include "cv.h"
    #include <math.h>
    
    #define X_MAX 400
    #define Y_MAX 400
    #define TO_BE_BLACK 40
    
    //radius of circles is known
    int houghTrans_r(IplImage *src, IplImage *dst, IplImage *tmp, float r, int xstep, int 
    
    ystep)
    {
    int width = src->width;
    int height = src->height;
    
    int channel = src->nChannels;
    int xmax = width%xstep ? width/xstep+1 : width/xstep;
    int ymax = height%ystep ? height/ystep+1 : height/ystep;
    
    int i,j,x,y;
    int para[X_MAX][Y_MAX] = {0};
    
    //i,j are in the pixel space
    //x,y are in the parameter space
    for(j=0; j<height; j++)
    {
    uchar* pin = (uchar*)(src->imageData + j*src->widthStep);
    for(i=0; i<width; i++)
    {
    //pixel is black
    if(pin[channel*i] < TO_BE_BLACK)
    {
    float temp;
    
    //calculate every probable y-cord based on x-cord
    for(x=0; x<xmax; x++)
    {
    temp = r*r - (i-x*xstep)*(i-x*xstep);
    temp = sqrt(temp);
    
    y = j - (int)temp;
    if(y>=0 && y<height){
    para[x][y/ystep]++;
    }
    
    y = j + (int)temp;
    if(y>=0 && y<height){
    para[x][y/ystep]++;
    }
    }
    }
    }
    }
    
    //find circle in parameter space
    int paramax=0,findx=-1,findy=-1;
    for(y=0; y<ymax; y++)
    {
    for(x=0; x<xmax; x++)
    {
    if(para[x][y] > paramax)
    {
    paramax=para[x][y];
    findx=x;
    findy=y;
    }
    }
    }
    
    //draw the parameter space image
    int ii,jj;
    for(y=0; y<ymax; y++)
    {
    uchar* pout = (uchar*)(tmp->imageData + y*tmp->widthStep);
    for(x=0; x<xmax; x++)
    {
    pout[channel*x]=para[x][y]*255/paramax;
    pout[channel*x+1]=para[x][y]*255/paramax;
    pout[channel*x+2]=para[x][y]*255/paramax;
    }
    }
    
    //draw the found circle
    if(findx>=0 && findy>=0)
    {
    for(j=0;j<height;j++)
    {
    uchar* pin=(uchar*)(src->imageData+j*src->widthStep);
    uchar* pout=(uchar*)(dst->imageData+j*dst->widthStep);
    for(i=0;i<width;i++)
    {
    pout[3*i]=128+pin[3*i]/2;
    pout[3*i+1]=128+pin[3*i+1]/2;
    pout[3*i+2]=128+pin[3*i+2]/2;
    }
    }
    cvCircle(dst,cvPoint(findx*xstep+xstep/2.0,findy*ystep
    
    +ystep/2.0),r,cvScalar(255,0,0),1,8,0);
    }
    
    return 1;
    }
    
    int main()
    {
    IplImage *srcImg=cvLoadImage("H:\circle_4.jpg");
    cvNamedWindow("Src",CV_WINDOW_AUTOSIZE);
    cvNamedWindow("Result",CV_WINDOW_AUTOSIZE);
    cvNamedWindow("Temp",CV_WINDOW_AUTOSIZE);
    
    IplImage *houghImg = cvCreateImage(cvGetSize(srcImg),IPL_DEPTH_8U,3);
    IplImage *houghTmp = cvCreateImage(cvGetSize(srcImg),IPL_DEPTH_8U,3);
    
    houghTrans_r(srcImg,houghImg,houghTmp,100.0,1,1);
    
    cvShowImage("Src",srcImg);
    cvShowImage("Temp",houghTmp);
    cvShowImage("Result",houghImg);
    
    cvWaitKey(0);
    cvReleaseImage(&srcImg);
    cvReleaseImage(&houghImg);
    
    cvDestroyWindow("Src");
    cvDestroyWindow("Result");
    return 0;
    }

     

          以下是检测示例:(左中右分别为原图像、参数空间图像和检测结果,检测结果用蓝色线绘制)


             由于固定半径r,所以参数就是圆心位置(x,y),绘制的点代表圆心的可能位置,颜色越浅,可

    能性越大。

            检测单独的圆

            在很乱的线中检测不完整的圆

            检测彼此错位的圆弧(参数划分扩大为5*5)
    ========

     

     

    opencv 检测直线、线段、圆、矩形

    http://blog.csdn.net/byxdaz/archive/2009/12/01/4912136.aspx


    检测直线:cvHoughLines,cvHoughLines2

    检测圆:cvHoughCircles

    检测矩形:opencv中没有对应的函数,下面有段代码可以检测矩形,是通过先找直线,然后找到直线平

    行与垂直的四根线。

    检测直线代码:

    /* This is a standalone program. Pass an image name as a first parameter of the program.

       Switch between standard and probabilistic Hough transform by changing "#if 1" to "#if 0" 

    and back */

    #include <cv.h>

    #include <highgui.h>

    #include <math.h>

    int main(int argc, char** argv)

    {
        const char* filename = argc >= 2 ? argv[1] : "pic1.png";

        IplImage* src = cvLoadImage( filename, 0 );

        IplImage* dst;

        IplImage* color_dst;

        CvMemStorage* storage = cvCreateMemStorage(0);

        CvSeq* lines = 0;

        int i;


        if( !src )

            return -1;
      
        dst = cvCreateImage( cvGetSize(src), 8, 1 );

        color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
       
        cvCanny( src, dst, 50, 200, 3 );

        cvCvtColor( dst, color_dst, CV_GRAY2BGR );

    #if 0

        lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 100, 0, 0 );
     
        for( i = 0; i < MIN(lines->total,100); i++ )

        {

            float* line = (float*)cvGetSeqElem(lines,i);

            float rho = line[0];

            float theta = line[1];

            CvPoint pt1, pt2;

            double a = cos(theta), b = sin(theta);

            double x0 = a*rho, y0 = b*rho;

            pt1.x = cvRound(x0 + 1000*(-b));

            pt1.y = cvRound(y0 + 1000*(a));

            pt2.x = cvRound(x0 - 1000*(-b));

            pt2.y = cvRound(y0 - 1000*(a));

            cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, CV_AA, 0 );

        }

    #else

        lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 50, 10 

    );

        for( i = 0; i < lines->total; i++ )

        {

            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);

            cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 );

        }

    #endif

        cvNamedWindow( "Source", 1 );

        cvShowImage( "Source", src );
     
        cvNamedWindow( "Hough", 1 );

        cvShowImage( "Hough", color_dst );

         cvWaitKey(0);

         return 0;

    }

    检测圆代码:

    #include <cv.h>
    #include <highgui.h>
    #include <math.h>

    int main(int argc, char** argv)
    {
        IplImage* img;
        if( argc == 2 && (img=cvLoadImage(argv[1], 1))!= 0)
        {
            IplImage* gray = cvCreateImage( cvGetSize(img), 8, 1 );

            CvMemStorage* storage = cvCreateMemStorage(0);

            cvCvtColor( img, gray, CV_BGR2GRAY );

            cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 ); // smooth it, otherwise a lot of false 

    circles may be detected

            CvSeq* circles = cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray-

    >height/4, 200, 100 );

            int i;

            for( i = 0; i < circles->total; i++ )

            {

                 float* p = (float*)cvGetSeqElem( circles, i );

                 cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(0,255,0), -1, 

    8, 0 );

                 cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB

    (255,0,0), 3, 8, 0 );

            }

            cvNamedWindow( "circles", 1 );

            cvShowImage( "circles", img );

        }

        return 0;

    }


    检测矩形代码:

    /*在程序里找寻矩形*/

    #ifdef _CH_

    #pragma package <opencv>

    #endif


     #ifndef _EiC

    #include "cv.h"

    #include "highgui.h"

    #include <stdio.h>

    #include <math.h>

    #include <string.h>

    #endif


    int thresh = 50;

    IplImage* img = 0;

    IplImage* img0 = 0;

    CvMemStorage* storage = 0;

    CvPoint pt[4];

    const char* wndname = "Square Detection Demo";

    // helper function:

    // finds a cosine of angle between vectors

    // from pt0->pt1 and from pt0->pt2

     double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )

    {   

        double dx1 = pt1->x - pt0->x;   

        double dy1 = pt1->y - pt0->y;   

        double dx2 = pt2->x - pt0->x;

        double dy2 = pt2->y - pt0->y;

        return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);

    }


    // returns sequence of squares detected on the image.

    // the sequence is stored in the specified memory storage

    CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )

    {

        CvSeq* contours;

        int i, c, l, N = 11;

        CvSize sz = cvSize( img->width & -2, img->height & -2 );

        IplImage* timg = cvCloneImage( img ); // make a copy of input image

        IplImage* gray = cvCreateImage( sz, 8, 1 );

        IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );

        IplImage* tgray;

        CvSeq* result;

        double s, t;

        // create empty sequence that will contain points -

        // 4 points per square (the square's vertices)

        CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );

        // select the maximum ROI in the image

        // with the width and height divisible by 2

        cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); 

        // down-scale and upscale the image to filter out the noise

        cvPyrDown( timg, pyr, 7 );

        cvPyrUp( pyr, timg, 7 );

        tgray = cvCreateImage( sz, 8, 1 );    

        // find squares in every color plane of the image

        for( c = 0; c < 3; c++ )

        {    

             // extract the c-th color plane

            cvSetImageCOI( timg, c+1 );

            cvCopy( timg, tgray, 0 ); 

           // try several threshold levels   

          for( l = 0; l < N; l++ )    
         {        

             // hack: use Canny instead of zero threshold level.      

            // Canny helps to catch squares with gradient shading      

             if( l == 0 )      
             {         

                 // apply Canny. Take the upper threshold from slider 

                   // and set the lower to 0 (which forces edges merging)

                     cvCanny( tgray, gray, 0, thresh, 5 );  

                  // dilate canny output to remove potential   

                 // holes between edge segments 

                    cvDilate( gray, gray, 0, 1 );        
              }    
             else  
             {      

                 // apply threshold if l!=0:

                    //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 

                   cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); 

               } 

             // find contours and store them all as a list

                cvFindContours( gray, storage, &contours, sizeof(CvContour),  

                            CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );  


             // test each contour

                while( contours )

                {

                    // approximate contour with accuracy proportional

                    // to the contour perimeter

                    result = cvApproxPoly( contours, sizeof(CvContour), storage,

                        CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );

                    // square contours should have 4 vertices after approximation

                    // relatively large area (to filter out noisy contours)

                    // and be convex.

                    // Note: absolute value of an area is used because

                    // area may be positive or negative - in accordance with the

                    // contour orientation

                    if( result->total == 4 &&

                        fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&

                        cvCheckContourConvexity(result) )
                    {

                        s = 0;

                        for( i = 0; i < 5; i++ )

                        {

                            // find minimum angle between joint 

                           // edges (maximum of cosine)

                            if( i >= 2 )

                            {

                                t = fabs(angle(

                                (CvPoint*)cvGetSeqElem( result, i ),

                                (CvPoint*)cvGetSeqElem( result, i-2 ),

                                (CvPoint*)cvGetSeqElem( result, i-1 )));

                                s = s > t ? s : t;

                            }

                        }
                                        
                    // if cosines of all angles are small 

                    // (all angles are ~90 degree) then write quandrange

                        // vertices to resultant sequence

                         if( s < 0.3 )

                            for( i = 0; i < 4; i++ ) 

                               cvSeqPush( squares, 


                                   (CvPoint*)cvGetSeqElem( result, i ));
                    }


                    // take the next contour 


                   contours = contours->h_next;


                }

            }

        }


        // release all the temporary images

        cvReleaseImage( &gray );

        cvReleaseImage( &pyr );

        cvReleaseImage( &tgray );

        cvReleaseImage( &timg );

        return squares;

    }


      // the function draws all the squares in the image

    void drawSquares( IplImage* img, CvSeq* squares )

    {   

        CvSeqReader reader;

        IplImage* cpy = cvCloneImage( img );

        int i;

            // initialize reader of the sequence


        cvStartReadSeq( squares, &reader, 0 );


            // read 4 sequence elements at a time (all vertices of a square)

        for( i = 0; i < squares->total; i += 4 )

        {

            CvPoint* rect = pt;

            int count = 4;


            // read 4 vertices

            memcpy( pt, reader.ptr, squares->elem_size );

            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

            memcpy( pt + 1, reader.ptr, squares->elem_size );

            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

            memcpy( pt + 2, reader.ptr, squares->elem_size );

            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

            memcpy( pt + 3, reader.ptr, squares->elem_size );

            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );


            // draw the square as a closed polyline

             cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );

        }


       // show the resultant image

        cvShowImage( wndname, cpy );

        cvReleaseImage( &cpy );



     
     void on_trackbar( int a )

    {

        if( img )

            drawSquares( img, findSquares4( img, storage ) );

    }


    char* names[] = { "pic1.png", "pic2.png", "pic3.png",

     

     

     

                      "pic4.png", "pic5.png", "pic6.png", 0 };

     

     

     


     int main(int argc, char** argv)

    {

        int i, c;

        // create memory storage that will contain all the dynamic data

        storage = cvCreateMemStorage(0);

         for( i = 0; names[i] != 0; i++ )

        {

            // load i-th image

            img0 = cvLoadImage( names[i], 1 );

            if( !img0 )

            {

                printf("Couldn't load %s/n", names[i] );

                continue;

            }

            img = cvCloneImage( img0 );


            // create window and a trackbar (slider) with parent "image" and set callback

            // (the slider regulates upper threshold, passed to Canny edge detector)

             cvNamedWindow( wndname, 1 );


            cvCreateTrackbar( "canny thresh", wndname, &thresh, 1000, on_trackbar );

     
            // force the image processing

            on_trackbar(0);

            // wait for key.

            // Also the function cvWaitKey takes care of event processing

            c = cvWaitKey(0);

            // release both images

            cvReleaseImage( &img );

            cvReleaseImage( &img0 );

            // clear memory storage - reset free space position

            cvClearMemStorage( storage );

            if( c == 27 )

                break;

        } 

           cvDestroyWindow( wndname ); 

           return 0;

    }


     #ifdef _EiC

    main(1,"squares.c");

    #endif

    其它参考博客:

    1、http://blog.csdn.net/superdont/article/details/6664254

    2、http://hi.baidu.com/%CE%C4%BF%A1%B5%C4%CF%A3%CD

    %FB/blog/item/3a5cb2079158b304738b65f2.html

    #include <cv.h>
    #include <highgui.h>
    #include <math.h>


    int main()
    {
        IplImage* src;
    if( (src=cvLoadImage("5.bmp", 1)) != 0)
        {
            IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
            IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
            CvMemStorage* storage = cvCreateMemStorage(0);//存储检测到线段,当然可以是N*1的矩阵


    数列,如果


    实际的直线数量多余N,那么最大可能数目的线段被返回
            CvSeq* lines = 0;
            int i;
    IplImage* src1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);


    cvCvtColor(src, src1, CV_BGR2GRAY); //把src转换成灰度图像保存在src1中,注意进行边缘检测一定





    换成灰度图
            cvCanny( src1, dst, 50, 200, 3 );//参数50,200的灰度变换


            cvCvtColor( dst, color_dst, CV_GRAY2BGR );
    #if 1
            lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 150, 0, 0 


    );//标准霍夫变


    换后两个参数为0,由于line_storage是内存空间,所以返回一个CvSeq序列结构的指针


            for( i = 0; i < lines->total; i++ )
            {
                float* line = (float*)cvGetSeqElem(lines,i);//用GetSeqElem得到直线
                float rho = line[0];
                float theta = line[1];//对于SHT和MSHT(标准变换)这里line[0],line[1]是rho(与像素


    相关单位的距


    离精度)和theta(弧度测量的角度精度)
                CvPoint pt1, pt2;
                double a = cos(theta), b = sin(theta);
                if( fabs(a) < 0.001 )
                {
                    pt1.x = pt2.x = cvRound(rho);
                    pt1.y = 0;
                    pt2.y = color_dst->height;
                }
                else if( fabs(b) < 0.001 )
                {
                    pt1.y = pt2.y = cvRound(rho);
                    pt1.x = 0;
                    pt2.x = color_dst->width;
                }
                else
                {
                    pt1.x = 0;
                    pt1.y = cvRound(rho/b);
                    pt2.x = cvRound(rho/a);
                    pt2.y = 0;
                }
                cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
            }
    #else
            lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 


    10 );
            for( i = 0; i < lines->total; i++ )
            {
                CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
                cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );
            }
    #endif
            cvNamedWindow( "Source", 1 );
            cvShowImage( "Source", src );


            cvNamedWindow( "Hough", 1 );
            cvShowImage( "Hough", color_dst );


            cvWaitKey(0);
        }
    }


    line_storage 
    检测到的线段存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数


    返回),或者是包含线段参数的特殊类型(见下面)的具有单行/单列的矩阵(CvMat*)。矩阵头为函数所


    修改,使得它的 cols/rows 将包含一组检测到的线段。如果 line_storage 是矩阵,而实际线段的数目

    超过矩阵尺寸,那么最大可能数目的线段被返回(线段没有按照长度、可信度或其它指标排序). 
    method 
    Hough 变换变量,是下面变量的其中之一: 
    CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是

    直线与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。因此,矩阵类型必须是 CV_32FC2 type. 
    CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高). 它返回

    线段分割而不是整个线段。每个分割用起点和终点来表示,所以矩阵(或创建的序列)类型是 

    CV_32SC4. 
    CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一


    致。 
    rho 
    与象素相关单位的距离精度 
    theta 
    弧度测量的角度精度 
    threshold 
    阈值参数。如果相应的累计值大于 threshold, 则函数返回的这个线段. 
    param1 
    第一个方法相关的参数: 
    对传统 Hough 变换,不使用(0). 
    对概率 Hough 变换,它是最小线段长度. 
    对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / 


    param1 ). 
    param2 
    第二个方法相关参数: 
    对传统 Hough 变换,不使用 (0). 
    对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直

    线上的两条碎线段之间的间隔小于param2时,将其合二为一。 
    对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 

    theta / param2).
    函数 cvHoughLines2 实现了用于线段检测的不同 Hough 变换方法. Example. 用 Hough transform 检


    测线段


    3、http://www.opencv.org.cn/index.php/Hough%E7%BA%BF%E6%AE%B5%E6%A3%80%E6%B5%8B

    ========

     

    opencv形状分析


    OpenCV支持大量的轮廓、边缘、边界的相关函数,相应的函数有moments、HuMoments、findContours、

    drawContours、approxPolyDP、arcLength、boundingRect、contourArea、convexHull、fitEllipse、

    fitLine、isContourConvex、minAreaRect、minEnclosingCircle、mathcShapes、pointPolygonTest。

    还有一些c版本的针对老版本的数据结构的函数比如cvApproxChains、cvConvexityDefects。这里先介绍

    一些我用过的函数,以后用到再陆续补充。

    OpenCV里支持很多边缘提取的办法,可是如何在一幅图像里得到轮廓区域的参数呢,这就需要用到

    findContours函数,这个函数的原型为:

    //C++:    
    void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray 

    hierarchy, int mode, int method, Point offset=Point())  
    void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int 

    method, Point offset=Point())  
    [cpp] view plain copy
    //C++:   
    void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray 

    hierarchy, int mode, int method, Point offset=Point())  
    void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int 

    method, Point offset=Point())  

    这里介绍下该函数的各个参数:
    输入图像image必须为一个2值单通道图像

    contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示

    hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] 

    ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有

    对应项,该值设置为负数。

    mode表示轮廓的检索模式

    CV_RETR_EXTERNAL表示只检测外轮廓

    CV_RETR_LIST检测的轮廓不建立等级关系

    CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内

    还有一个连通物体,这个物体的边界也在顶层。

    CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo


    method为轮廓的近似办法

    CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2)

    ,abs(y2-y1))==1

    CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例

    如一个矩形轮廓只需4个点来保存轮廓信息

    CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

    offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行

    分析时,这个参数还是很有用的。

    具体应用参考sample文件夹下面的squares.cpp这个demo

    findContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,

    findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做


    适当近似

    contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选

    findContours经常与drawContours配合使用,用来将轮廓绘制出来。其中第一个参数image表示目标图像

    ,第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,第三个参数contourIdx指明画

    第几个轮廓,如果该参数为负值,则画全部轮廓,第四个参数color为轮廓的颜色,第五个参数

    thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,第六个参数lineType为线型,第

    七个参数为轮廓结构信息,第八个参数为maxLevel

    得到了复杂轮廓往往不适合特征的检测,这里再介绍一个点集凸包络的提取函数convexHull,输入参数

    就可以是contours组中的一个轮廓,返回外凸包络的点集

    还可以得到轮廓的外包络矩形,使用函数boundingRect,如果想得到旋转的外包络矩形,使用函数

    minAreaRect,返回值为RotatedRect;也可以得到轮廓的外包络圆,对应的函数为minEnclosingCircle

    ;想得到轮廓的外包络椭圆,对应的函数为fitEllipse,返回值也是RotatedRect,可以用ellipse函数

    画出对应的椭圆

    如果想根据多边形的轮廓信息得到多边形的多阶矩,可以使用类moments,这个类可以得到多边形和光栅

    形状的3阶以内的所有矩,类内有变量m00,m10,m01,m20,m11,m02,m30,m21,m12,m03,比如多边

    形的质心为 x = m10 / m00,y = m01 / m00。

    如果想获得一点与多边形封闭轮廓的信息,可以调用pointPolygonTest函数,这个函数返回值为该点距

    离轮廓最近边界的距离,为正值为在轮廓内部,负值为在轮廓外部,0表示在边界上。
    ========

     

     

    实用OpenCV  图像中的形状

     


    形状是当我们看到物体时最开始的印象之一,这一章我们将赋予计算机这种能力。识别图像里的形状是

    通常是做决策时一个重要步骤。形状是由图像的轮廓形成的,所以理论上形状识别是通常在边缘或轮廓

    检测后的步骤。
    所以,我们将首先讨论从图像里提取轮廓,然后再开始讨论形状。将会包含:
    ?霍夫变换,可以使我们检测图像里的常规形状如线条和圆形。

    ?随机样本一致性(RANSAC),一个广泛使用的可以确定数据点来匹配特定模型的框架。我们将编写算法

    代码来检测图像里的椭圆。
    ?对象周围的绑定盒,绑定椭圆和凸形外壳的计算。

    ?形状匹配。

    轮廓
    轮廓和边缘有一个显著区别。边缘是图像亮度梯度的局部极大值集合。我们也看到,这些梯度极大值不

    全是在物体的轮廓上而且他们是非常有噪声的。Canny边缘有一点不同,更像轮廓一些,因为在梯度极大

    值提取后经过一些后处理步骤。轮廓,相对而言,是一系列相连的点,更可能落在物体的外框上。
    OpenCV的轮廓提取基于二值图像(像Canny边缘检测的输出或对Scharr边缘做阈值处理或者一张黑白图)

    然后提取边缘点连接的层次结构。组织层次使得位于数结构更高的轮廓更有可能是物体的轮廓,然而低

    位的轮廓更有可能是噪声边缘和“洞口”的轮廓以及噪声块。
    实现这些特性的函数叫findContours()然后它使用了由S.Suzuki和K.Abe在“数字二值图像的基于边界跟

    随的拓扑结构分析”一文中描述的算法来提取轮廓并排列层次结构。文中描述了决定层次结构的详细规

    则,简而言之呢,当一个轮廓围绕着另一个轮廓的时候被认为是那个轮廓的“父亲”。
    为了更实际地显示我们所说的层次结构呢,我们将编写一个程序,见例6-1,使用了我们最喜欢的工具,

    滑块,来选择要显示层次结构的级别值。注意该函数仅接受一个二值图像为输入。从普通图像得到二值

    图的方式有:
    ?通过threshold()或adaptiveThreshold()来阈值处理
    ?使用inRange()检查像素值边界
    ?Canny边缘
    ?Scharr边缘做阈值处理


    例 6-1 程序展现层次轮廓提取


    // Program to illustrate hierarchical contour extraction
    // Author: Samarth Manoj Brahmbhatt, University of Pennsylvania
    #include <opencv2 opencv.hpp="">
    #include <opencv2 highgui="" highgui.hpp="">
    #include <opencv2 imgproc="" imgproc.hpp="">
    using namespace std;
    using namespace cv;
    Mat img;
    vector<vector<point> > contours;
    vector<vec4i> heirarchy;
    int levels = 0;
    void on_trackbar(int, void *) {
      if(contours.empty()) return;
      Mat img_show = img.clone();
      // Draw contours of the level indicated by slider
      drawContours(img_show, contours, -1, Scalar(0, 0, 255), 3, 8, heirarchy, levels);
      imshow("Contours", img_show);
    }
    int main() {
      img = imread("circles.jpg");
      Mat img_b;
      cvtColor(img, img_b, CV_RGB2GRAY);
      Mat edges;
      Canny(img_b, edges, 50, 100);
      // Extract contours and heirarchy
      findContours(edges, contours, heirarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
      namedWindow("Contours");
      createTrackbar("levels", "Contours", &levels, 15, on_trackbar);
      // Initialize by drawing the top level contours (as 'levels' is initialized to 0)
      on_trackbar(0, 0);
      while(char(waitKey(1)) != 'q') {}
      return 0;
    }
    </vec4i></vector<point></opencv2></opencv2></opencv2>
    注意每个轮廓是一个STL向量里的点。所以,储存轮廓的数据结构是一个含点向量的向量。层次结构是一

    个含四整数向量的向量(注:即向量的元素也是向量)。对每个轮廓来说,它的层次结构位置表示为四

    个整数值:他们是轮廓向量基于0的索引分别指示 下一位置(同等级),上一个(同等级),父级,以

    及第一个子轮廓。假使其中任意一个不存在(比如,如果一个轮廓没有父轮廓),对应的整数值则为负

    值。同时注意drawContours()函数根据层次结构和绘制允许最大层次等级来通过绘制轮廓修改输入图片


    图6-1显示了一张简图上的不同等级的轮廓。

    \\
    \

    图6-1 不同等级的轮廓层次
    经常和findContours()一起使用的一个函数是approxPolyDP()。approxPolyDP()用另一条顶点较少的曲

    线来逼近一条曲线或者一个多边形,这样两条曲线之间的距离小于或等于指定的精度。同时也有使闭合

    逼近曲线的选项(那就是说,起始点和终止点相同)

    点-多边形测试
    我们先暂且来介绍一个有趣的特性:点-多边形测试。你也许猜到了,pointPolygonTest()函数判定一个

    点是否在一个多边形内。如果你开启 measureDist标签的话它也会返回该点到轮廓最近点的有符号欧式

    距离。如果点在曲线内,距离则为正,外则负,点在轮廓上则为零。如果标签关闭的话,相应的距离则

    被替换为+1,-1和0。
    让我们来做一个程序来演示点-多边形和闭合曲线逼近的新知识——一个寻找图像上用户点击点相近的最


    小闭合轮廓的程序。同时它也演示了轮廓层次的导引。代码见例6-2
    例6-2 寻找点击点围绕的最小轮廓

    <"http://www.2cto.com/kf/ware/vc/" target="_blank" 

    class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;">// Program to find the smallest contour 

    that surrounds the clicked point // Author: Samarth Manoj Brahmbhatt, University of 

    Pennsylvania #include #include #include using namespace std; using namespace cv; Mat 

    img_all_contours; vector > closed_contours; vector heirarchy; // Function to approximate 

    contours by closed contours vector > make_contours_closed(vector > contours) { vector > 

    closed_contours; closed_contours.resize(contours.size()); for(int i = 0; i < contours.size

    (); i++) approxPolyDP(contours[i], closed_contours[i], 0.1, true); return closed_contours; 

    } // Function to return the index of smallest contour in 'closed_contours' surrounding the 

    clicked point int smallest_contour(Point p, vector > contours, vector heirarchy) { int idx 

    = 0, prev_idx = -1; while(idx >= 0) { vector c = contours[idx]; // Point-polgon test double 

    d = pointPolygonTest(c, p, false); // If point is inside the contour, check its children 

    for an even smaller contour... if(d > 0) { prev_idx = idx; idx = heirarchy[idx][2]; } // 

    ...else, check the next contour on the same level else idx = heirarchy[idx][0]; } return 

    prev_idx; } void on_mouse(int event, int x, int y, int, void *) { if(event != 

    EVENT_LBUTTONDOWN) return; // Clicked point Point p(x, y); // Find index of smallest 

    enclosing contour int contour_show_idx = smallest_contour(p, closed_contours, heirarchy); 

    // If no such contour, user clicked outside all contours, hence clear image if

    (contour_show_idx < 0) { imshow("Contours", img_all_contours); return; } // Draw the 

    smallest contour using a thick red line vector > contour_show; contour_show.push_back

    (closed_contours[contour_show_idx]); if(!contour_show.empty()) { Mat img_show = 

    img_all_contours.clone(); drawContours(img_show, contour_show, -1, Scalar(0, 0, 255), 3); 

    imshow("Contours", img_show); } } int main() { Mat img = imread("circles.jpg"); 

    img_all_contours = img.clone(); Mat img_b; cvtColor(img, img_b, CV_RGB2GRAY); Mat edges; 

    Canny(img_b, edges, 50, 100); // Extract contours and heirarchy vector > contours; 

    findContours(edges, contours, heirarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); // Make 

    contours closed so point-polygon test is valid closed_contours = make_contours_closed

    (contours); // Draw all contours usign a thin green line drawContours(img_all_contours, 

    closed_contours, -1, Scalar(0, 255, 0)); imshow("Contours", img_all_contours); // Mouse 

    callback setMouseCallback("Contours", on_mouse); while(char(waitKey(1)) != 'q') {} return 

    0; } 假设 idx为轮廓在点向量的向量中的索引而hierarchy代表层次的话:
    ? hierarchy[idx][0] 返回同等级层次结构的下一个轮廓索引
    ? hierarchy[idx][1] 返回同等级层次结构的上一个轮廓索引
    ? hierarchy[idx][2] 返回第一个子轮廓的索引
    ? hierarchy[idx][3] 返回父轮廓的索引
    如果其中一个轮廓不存在,返回索引为负值。
    程序运行的截图如图6-2所示


    图 6-2 最小封闭轮廓的应用

    OpenCV也提供了一些函数检查其中的一些属性来帮助你过滤噪声图像的轮廓。如表6-1

    表6-1 OpenCV轮廓后处理函数

    函数 描述
    ArcLength() 查找轮廓长度
    ContourArea() 查找轮廓区域和方向
    BoundingRect() 计算轮廓的垂直边界矩形
    ConvexHull() 计算轮廓围绕的凸形壳
    IsContourConvex() 测试轮廓的凸性
    MinAreaRect() 计算围绕轮廓的最小旋转矩形
    MinEnclosingCircle() 查找围绕轮廓的最小区域圆形
    FitLine() 基于轮廓匹配一条线(最小二乘)
    ========

     

     

    opencv识别正方形(矩形)代码


    //正方形检测源码
    //载入数张包含各种形状的图片,检测出其中的正方形
    #include "cv.h"
    #include "highgui.h"
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <iostream>

    int thresh = 50;
    IplImage* img =NULL;
    IplImage* img0 = NULL;
    CvMemStorage* storage =NULL;
    const char * wndname = "正方形检测 demo";

    //angle函数用来返回(两个向量之间找到角度的余弦值)
    double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )
    {
     double dx1 = pt1->x - pt0->x;
     double dy1 = pt1->y - pt0->y;
     double dx2 = pt2->x - pt0->x;
     double dy2 = pt2->y - pt0->y;
     return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }

    // 返回图像中找到的所有轮廓序列,并且序列存储在内存存储器中

    CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )
    {
     CvSeq* contours;
     int i, c, l, N = 11;
     CvSize sz = cvSize( img->width & -2, img->height & -2 ); 
     
     IplImage* timg = cvCloneImage( img );
     IplImage* gray = cvCreateImage( sz, 8, 1 );
     IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );
     IplImage* tgray;
     CvSeq* result;
     double s, t;
     // 创建一个空序列用于存储轮廓角点
     CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );

     cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));
     // 过滤噪音
     cvPyrDown( timg, pyr, 7 );
     cvPyrUp( pyr, timg, 7 );
     tgray = cvCreateImage( sz, 8, 1 );

     // 红绿蓝3色分别尝试提取
     for( c = 0; c < 3; c++ )
     {
      // 提取 the c-th color plane
      cvSetImageCOI( timg, c+1 );
      cvCopy( timg, tgray, 0 );

      // 尝试各种阈值提取得到的(N=11)
      for( l = 0; l < N; l++ )
      {
       // apply Canny. Take the upper threshold from slider
       // Canny helps to catch squares with gradient shading  
       if( l == 0 )
       {
        cvCanny( tgray, gray, 0, thresh, 5 );
        //使用任意结构元素膨胀图像
        cvDilate( gray, gray, 0, 1 );
       }
       else
       {
        // apply threshold if l!=0:
        cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );
       }

       // 找到所有轮廓并且存储在序列中
       cvFindContours( gray, storage, &contours, sizeof(CvContour),
        CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );

       // 遍历找到的每个轮廓contours
       while( contours )
       {
         //用指定精度逼近多边形曲线
        result = cvApproxPoly( contours, sizeof(CvContour), storage,
         CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );                


        if( result->total == 4 &&
         fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 500 &&
         fabs(cvContourArea(result,CV_WHOLE_SEQ)) < 100000 &&
         cvCheckContourConvexity(result) )
        {
         s = 0;

         for( i = 0; i < 5; i++ )
         {
          // find minimum angle between joint edges (maximum of cosine)
          if( i >= 2 )
          {
           t = fabs(angle(
            (CvPoint*)cvGetSeqElem( result, i ),
            (CvPoint*)cvGetSeqElem( result, i-2 ),
            (CvPoint*)cvGetSeqElem( result, i-1 )));
           s = s > t ? s : t;
          }
         }

         // if 余弦值 足够小,可以认定角度为90度直角
         //cos0.1=83度,能较好的趋近直角
         if( s < 0.1 )  
          for( i = 0; i < 4; i++ )
           cvSeqPush( squares,
           (CvPoint*)cvGetSeqElem( result, i ));
        }

        // 继续查找下一个轮廓
        contours = contours->h_next;
       }
      }
     }
     cvReleaseImage( &gray );
     cvReleaseImage( &pyr );
     cvReleaseImage( &tgray );
     cvReleaseImage( &timg );


     return squares;
    }

    //drawSquares函数用来画出在图像中找到的所有正方形轮廓
    void drawSquares( IplImage* img, CvSeq* squares )
    {
     CvSeqReader reader;
     IplImage* cpy = cvCloneImage( img );
     int i;
     cvStartReadSeq( squares, &reader, 0 );

     // read 4 sequence elements at a time (all vertices of a square)
     for( i = 0; i < squares->total; i += 4 )
     {
      CvPoint pt[4], *rect = pt;
      int count = 4;

      // read 4 vertices
      CV_READ_SEQ_ELEM( pt[0], reader );
      CV_READ_SEQ_ELEM( pt[1], reader );
      CV_READ_SEQ_ELEM( pt[2], reader );
      CV_READ_SEQ_ELEM( pt[3], reader );

      // draw the square as a closed polyline
      cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 2, CV_AA, 0 );
     }

     cvShowImage( wndname, cpy );
     cvReleaseImage( &cpy );
    }

    char* names[] = { "pic1.png", "pic2.png", "pic3.png",
         "pic4.png", "pic5.png", "pic6.png","pic7.png","pic8.png",
         "pic9.png","pic10.png","pic11.png","pic12.png", 0 };

    int main(int argc, char** argv)
    {
     int i, c;
     storage = cvCreateMemStorage(0);

     for( i = 0; names[i] != 0; i++ )
     {
      img0 = cvLoadImage( names[i], 1 );
      if( !img0 )
      {
       cout<<"不能载入"<<names[i]<<"继续下一张图片"<<endl;
       continue;
      }
      img = cvCloneImage( img0 );
      cvNamedWindow( wndname, 1 );

      // find and draw the squares
      drawSquares( img, findSquares4( img, storage ) );

      c = cvWaitKey(0);
      
      cvReleaseImage( &img );
      cvReleaseImage( &img0 );

      cvClearMemStorage( storage );

      if( (char)c == 27 )
       break;
     }

     cvDestroyWindow( wndname );
     return 0;
    }

    ========

     

     

    OpenCV入门之线段检测


    线段检测主要运用Hough变换,Hough变换是图像处理中从图像中识别几何形状的基本方法之一,应用很


    广泛,也有很多改进算法。主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等)


    。最基本的霍夫变换是从黑白图像中检测直线(线段)。
    在OpenCV编程中,实现线段检测主要使用cvHoughLines2函数。
    函数原型:
    CvSeq* cvHoughLines2(
      CvArr* image,
      void* line_storage,
      int method,
      double rho,
      double theta,
      int threshold,
      double param1=0, double param2=0
    );

    参数说明:
    第一个参数表示输入图像,必须为二值图像(黑白图)。
    第二个参数表示存储容器,可以传入CvMemStorage类型的指针。
    第三个参数表示变换变量,可以取下面的值:
      CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 

    是线段与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。
      CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高)。它返

    回线段分割而不是整个线段。每个分割用起点和终点来表示。
      CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的

    一致。
    第四个参数表示与象素相关单位的距离精度。
    第五个参数表示弧度测量的角度精度。
    第六个参数表示检测线段的最大条数,如果已经检测这么多条线段,函数返回。
    第七个参数与第三个参数有关,其意义如下:
      对传统 Hough 变换,不使用(0).
      对概率 Hough 变换,它是最小线段长度.
      对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / 

    param1 ).
    第八个参数与第三个参数有关,其意义如下:
      对传统 Hough 变换,不使用 (0).
      对概率 Hough 变换,这个参数表示在同一条线段上进行碎线段连接的最大间隔值(gap), 即当同一条

    线段上的两条碎线段之间的间隔小于param2时,将其合二为一。
      对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 

    theta / param2)。

    示例程序:
    hough.cpp


     #include <opencv2/core/core.hpp>
    #include <opencv2/opencv.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>


    using namespace std;


    int main (int argc, char **argv)  
    {     
    const char *pstrWindowsSrcTitle = "initial";
    const char *pstrWindowsLineName = "hough";


    IplImage *pSrcImage = cvLoadImage("hough.jpg", CV_LOAD_IMAGE_UNCHANGED);


    IplImage *pGrayImage =  cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);  
    cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);


    IplImage *pCannyImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);  
    cvCanny(pGrayImage, pCannyImage, 30, 90);


    CvMemStorage *pcvMStorage = cvCreateMemStorage();  
    double fRho = 1;  
    double fTheta = CV_PI / 180;  
    int nMaxLineNumber = 50; //最多检测条直线
    double fMinLineLen = 50; //最小线段长度
    double fMinLineGap = 10; //最小线段间隔
    CvSeq *pcvSeqLines = cvHoughLines2(pCannyImage, pcvMStorage, CV_HOUGH_PROBABILISTIC, fRho, 


    fTheta, nMaxLineNumber, fMinLineLen, fMinLineGap);


    IplImage *pColorImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);
    cvCvtColor(pCannyImage, pColorImage, CV_GRAY2BGR);
    int i;
    for(i = 0; i < pcvSeqLines->total; i++)  
    {  
    CvPoint* line = (CvPoint*)cvGetSeqElem(pcvSeqLines, i);  
    cvLine(pColorImage, line[0], line[1], CV_RGB(255,0,0), 2);
      }


    cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);  
    cvShowImage(pstrWindowsSrcTitle, pSrcImage);  
    cvNamedWindow(pstrWindowsLineName, CV_WINDOW_AUTOSIZE);  
    cvShowImage(pstrWindowsLineName, pColorImage);  
      
    cvWaitKey(0);  
      
    cvReleaseMemStorage(&pcvMStorage);  
    cvDestroyWindow(pstrWindowsSrcTitle);  
    cvDestroyWindow(pstrWindowsLineName);  
    cvReleaseImage(&pSrcImage);  
    cvReleaseImage(&pGrayImage);  
    cvReleaseImage(&pCannyImage);  
    cvReleaseImage(&pColorImage);  
    return 0;  
    }


    makefile:


     INCLUDE = $(shell pkg-config --cflags opencv)  
    LIBS = $(shell pkg-config --libs opencv)  
    SOURCES = hough.cpp  
    # 目标文件  
    OBJECTS = $(SOURCES:.cpp=.o)  
    # 可执行文件  
    TARGET = hough  
    $(TARGET):$(OBJECTS)  
    g++ -o $(TARGET) $(OBJECTS) -I $(INCLUDE) $(LIBS)  
    $(OBJECTS):$(SOURCES)  
    g++ -c $(SOURCES)  
    clean:  
    rm $(OBJECTS) $(TARGET)  
    # 编译规则 $@代表目标文件 $< 代表第一个依赖文件  
    %.o:%.cpp  
    g++ -I $(INCLUDE) -o $@ -c $<

    所在文件夹上已有hough.jpg图片,make后执行./hough hough.jpg

    ========

     

    展开全文
  • opencv 实现一幅图片上物体形状识别 例如一幅图片有圆形 三角形 五角星等形状 怎么识别出来并获取他们各自的数量啊。基本思路是什么
  • OpenCV识别形状

    千次阅读 2019-03-27 20:29:16
    其中遇到的问题主要是识别轮廓时矩形内部的形状导致轮廓不闭合。 1. 对输入灰度图片进行高斯滤波 2. 做灰度直方图,提取阈值,做二值化处理 3. 提取图片轮廓 4. 识别图片中的矩形 5. 提取图片中的矩形 常用函数 ...
  • 在我们学习了膨胀腐蚀和基于膨胀腐蚀的变化之后,我比较喜欢的一个是击中击不中,因为喜欢所以就要...击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。它的原理就是使用腐蚀;如果要在一幅图像A上找
  •  图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints)、特征点(feature points) 被大量用于解决物体识别,图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察...
  • 在为此,我定义了背景色,然后遍历图片以分割图像。以下是我的代码,以便更好地理解:MAXIMUM_COLOR_TRANSITION_DELTA = 100 # 0 - 765def expand_segment_recursive(image, unexplored_foreground,...
  • 思路先先识别三角形,就先转成二值图像, 然后使用轮廓发现findContours相关函数,提取与绘制轮廓,最后用approxPolyDP对其进行轮廓逼近,然后对三角形找到中心点 ,需要用moments计算一阶几何距得到指定轮廓的中心...
  • opencv之基本形状识别

    千次阅读 多人点赞 2019-07-11 22:51:58
    文章目录openc之基本形状识别各种博客上的现有方法新方法——从信号的角度分析实验结果通过上面这些图可以得到图下结论: openc之基本形状识别 各种博客上的现有方法 ...笔者通过阅读其代码,将其思路总结如下: ...
  • OpenCV图像去噪

    千次阅读 2017-02-15 19:55:04
    OpenCV图像去噪
  • OPENCV实例:识别特定颜色的物体

    千次阅读 2019-04-12 10:26:32
    步骤: 1先读取视频(or图片)文件 2将图像转换为hsv 3通过判断hsv值范围识别颜色 hsv范围颜色对应:... 示例:识别视频中的黄色区域,并变成白色显示 ...opencv2\opencv.hpp...
  • 本文主要介绍一些涉及到的编程思想。 至于源代码,这个程序功能本身并没有什么现实意义,而且...在进行图像识别工作的时候,最重要的就是找到要识别的目标区别于其它图形的特征。而且该特征对于识别目标具有稳定性....
  • opencv 图像去噪学习总结

    万次阅读 2016-03-12 20:27:27
    OpenCV图像处理篇之图像平滑 图像平滑算法 程序分析及结果 图像平滑算法 图像平滑与图像模糊是同一概念,主要用于图像的去噪。平滑要使用滤波器,为不改变图像的相位信息, 一般使用线性滤波器,其统一形式如下: ...
  • OpenCV图像直方图

    千次阅读 2019-03-28 08:28:53
    OpenCV图像直方图 微信公众号:幼儿园的学霸 个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言; 灰度直方图(Histogram)是数字图像处理中最简单、最有用的工具之一,它概括了一幅图像的灰度...
  • OpenCV 图像处理编程学习笔记

    千次阅读 2018-07-28 11:09:47
    OpenCV编程实例代码》各章重点知识点简述 第一章 OpenCv环境配置 主要讲解了 OpenCV 的各种开发环境的配置,其中以Sublime 作为主要的配置环境的介绍,这里我们主要使用 VScode 进行开发。 第二章 ...
  • 霍夫变换是图像处理中一种特征提取技术, 该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换的结果; 目前霍夫变换扩展到任意形状物体的识别, 多为圆和椭圆; 霍夫变换...
  • OPENCV图像处理基础

    2020-06-28 16:45:54
    OPENCV图像处理基础1.图像处理基础1.1 数字图像1.1.1 数字图像概念:1.1.2 数字图像起源:1.1.3 常见成像方式:1.1.4 数字图像的应用:1.1.5 Opencv介绍:1.2 图像属性1.2.1 图像格式:1.2.2 图像尺寸:1.2.3 图像...
  • opencv图像轮廓

    2015-03-24 16:15:33
    openCV中一般用序列来存储轮廓信息.序列中的每一个元素是曲线中一个点的位置.关于序列表示的轮廓细节将在后面讨论,现在只要简单把轮廓想象为使用CvSeq表示的一系列的点就可以了. 函数cvFindContours()从二值...
  • 霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像识别几何形状的基本方法之一,应用很广泛,也有很多改进 ... 用 Python 和 OpenCV 检测图片上的条形码 用 Python 和 OpenCV 检测图片上的的条形码 这篇博文的...
  • OpenCV车牌识别

    千次阅读 2020-06-08 14:43:30
    最近一直在学习图像处理,想着找个实践的例子,这样让自己学习起来更加有激情,于是就找了车牌识别的例子,并把它写下来当作学习总结吧。       近年来,汽车车牌识别(License Plate Recogniti
  • OpenCV图像的轮廓的匹配

    千次阅读 2019-01-25 13:39:00
    OpenCV图像的轮廓的匹配
  • QT+opencv进行图像圆的识别,且对圆进行颜色识别 效果图 基本步骤 一、 环境 windows版本: win10 x64 Opencv版本: 3.4.5 QT版本:5.12 二、Opencv下载 官网地址opencv下载地址 下载完成后电机安装就可以了 三、QT...
  • OpenCV图像处理学习十二——图像形状特征之HOG特征一、图像特征理解1.1 颜色特征1.2 纹理特征1.3 形状特征1.4 空间关系特征二、形状特征描述2.1 HOG特征2.1.1 基本概念2.1.2 HOG实现过程2.1.3 代码实现 ...
  • 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像识别几何形状的基本方法之一,应用很广泛,也有很多改进算法。主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等)。最基本的霍夫变换是...
  • OpenCV图像的轮廓与链码

    千次阅读 2017-04-22 11:21:58
    OpenCV中一般用序列来存储轮廓信息.序列中的每一个元素是曲线中一个点的位置.关于序列表示的轮廓细节将在后面讨论,现在只要简单把轮廓想象为使用CvSeq表示的一系列的点就可以了. 函数cvFindContours()从二值图像...
  • 使用OpenCV和Python从图像中提取形状

    千次阅读 2020-08-10 11:16:02
    Welcome to the first post in this series of blogs on extracting features ... 欢迎使用本系列博客的第一篇有关使用OpenCV和Python从图像中提取特征的文章。 Feature extraction from images and videos is a...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,574
精华内容 1,029
关键字:

opencv图像识别特定形状