通过轮廓的圆度分析实现孔洞提取
最近有网友咨询相关算法问题,我给了一些帮助,觉得比较典型,在经过他允许后将相关资料和思路进行整理,放出来大家共同学习!
一、问题:
图中这个孔是两个半圆加直线组成的,不同于普通的圆和椭圆,所以用hough变换检测效果不好, 有没有什么方法可以把那个孔的轮廓给提取出来?
二、分析和解体:
如果对hough的原理和使用比较了解的话(可以翻看《学习OpenCV》),就知道想利用houghcircle取出这样的轮廓使不可能的,此类问题首先是要把关键区域强化出来,然后可以考虑轮廓分析的方法。
如果对hough的原理和使用比较了解的话(可以翻看《学习OpenCV》),就知道想利用houghcircle取出这样的轮廓使不可能的,此类问题首先是要把关键区域强化出来,然后可以考虑轮廓分析的方法。
基于基础算法,做到目前程度。取这样一个洞的图像,很容易被阴影干扰,需要在图片采集的时候有所注意。
connection图
connection图
# include "stdafx.h" # include "opencv2/core/core.hpp" # include "opencv2/highgui/highgui.hpp" # include "opencv2/imgproc/imgproc.hpp" # include <iostream > # include <stdio.h > # include <stdlib.h > # include <math.h > # include "GOCVHelper.h" using namespace cv; using namespace std; using namespace GO; RNG rng2( 12345); //根据轮廓的圆的特性进行选择 vector <VP > selectShapeCircularity(Mat src,Mat & draw,vector <VP > contours, float minvalue, float maxvalue); vector <VP > selectShapeCircularity(vector <VP > contours, float minvalue, float maxvalue); //计算轮廓的圆的特性 float calculateCircularity(VP contour); //根据轮廓的圆的特性进行选择 vector <VP > selectShapeCircularity(Mat src,Mat & draw,vector <VP > contours, float minvalue, float maxvalue){ vector <VP > result_contours; draw = Mat : :zeros(src.rows,src.cols,CV_8UC3); for ( int i = 0;i <contours.size();i ++){ float fcompare = calculateCircularity(contours[i]); if (fcompare > =minvalue && fcompare < =maxvalue) result_contours.push_back(contours[i]); } for ( int i = 0;i <result_contours.size();i ++){ Scalar color = Scalar(rng2.uniform( 0, 255),rng2.uniform( 0, 255),rng2.uniform( 0, 255)); drawContours(draw,result_contours,i,color, - 1); } return result_contours; } vector <VP > selectShapeCircularity(vector <VP > contours, float minvalue, float maxvalue){ vector <VP > result_contours; for ( int i = 0;i <contours.size();i ++){ float fcompare = calculateCircularity(contours[i]); if (fcompare > =minvalue && fcompare < =maxvalue) result_contours.push_back(contours[i]); } return result_contours; } //计算轮廓的圆的特性 float calculateCircularity(VP contour){ Point2f center; float radius = 0; minEnclosingCircle((Mat)contour,center,radius); //以最小外接圆半径作为数学期望,计算轮廓上各点到圆心距离的标准差 float fsum = 0; float fcompare = 0; for ( int i = 0;i <contour.size();i ++){ Point2f ptmp = contour[i]; float fdistenct = sqrt(( float)((ptmp.x - center.x) *(ptmp.x - center.x) +(ptmp.y - center.y) *(ptmp.y -center.y))); float fdiff = abs(fdistenct - radius); fsum = fsum + fdiff; } fcompare = fsum /( float)contour.size(); return fcompare; } int _tmain( int argc, _TCHAR * argv[]) { //读入灰度的手部图像 Mat src = imread( "e:/sandbox/kong.jpg"); Mat dst = src.clone(); Mat tmp; Mat draw; vector <VP > contours; vector <VP > results; vector <Mat > planes; cvtColor(src,src,COLOR_BGR2HSV); split(src,planes); //v通道 tmp = planes[ 2].clone(); //去除毛刺 GaussianBlur(tmp,tmp,Size( 3, 3), 0); //阈值处理 threshold(tmp,tmp, 100, 255,THRESH_OTSU); //反向 bitwise_not(tmp,tmp); //形态学 erode(tmp,tmp,Mat()); dilate(tmp,tmp,Mat()); //绘制联通区域 contours = GO : :connection2(tmp,draw); //轮廓分析(圆特性) results = selectShapeCircularity(tmp,draw,contours, 100, 500); //原图绘制 drawContours(dst,results, 0,Scalar( 0, 0, 255), 3); imshow( "result",dst); waitKey(); return 0; }
所用gocvhelpe可以在我的github https://github.com/jsxyhelu 上找到,我的博客地址为jsxyhelu.cnblogs.com