首先基于前面的工作,通过调整已经很好的把指甲边缘显示出来了,不曾想我却从那时开始走上了弯路,使用matlab去处理静态图片,以获得更好的指甲和特征提取效果,结果就是,效果不理想(光照影响)并且用到摄像头上来一点都不实用。辛辛苦苦的研究了n多的图像处理算法,几乎把边缘提取的算法全部过了一遍,阅读了不下100篇论文,还折腾出B样条曲线拟合进行边缘连接,现在想想太可笑了,其实OpenCV现有的图像处理方法已经可以满足我提取指甲的要求了,只不过我需要进行合理的组合搭配,从而实现我想要的效果。
总有那么一句话叫:摸着石头过河。我今天算是体会到了,不过中间老板还让写创业计划,总之,该回归正道了!
接着之前的canny提取的边缘,我想进一步提取出指甲,把其他背景都省略,这样就只留下指甲了,从而进一步提取特征。首先我想到的是findContours函数及其轮廓操作
//! retrieves contours and the hierarchical information from black-n-white image.
CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset=Point());
//! retrieves contours from black-n-white image.
CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours,
int mode, int method, Point offset=Point());
其中image为输入的 binary image,输出是一个向量数组,每个向量是Points类型的指针向量数组。这个数组会用做后面的轮廓处理。
mode代表提取轮廓的类型, 可以是以下几种类型 //CV_RETR_LIST, // retrieve all contours
//CV_RETR_EXTERNAL, // retrieve the external contours
//CV_RETR_TREE, // retrieve all contours in tree format
//CV_RETR_CCOMP is similar but limits the hierarchy at two levels.建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
method代表轮廓点的类型,可以有 //CV_CHAIN_APPROX_NONE // all pixels of each contours存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
//CV_CHAIN_APPROX_SIMPLE //only the end points would be included for horizontal,vertical, or diagonal contours. 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
最后一个不用管先,然后就是一个OutputArray hierarchy代表分层结构,hierarchy, // hierarchical representation
接下来用 cv::Mat result(image.size(),CV_8U,cv::Scalar(255));
cv::drawContours(result,contours,
-1, // draw all contours
cv::Scalar(0), // in black
2); // with a thickness of 2
出来的效果还不错,利用黑背景,能将指甲分离出来,但是接下来的分离过程除了错误。就是在我将多余的或者不符合要求的轮廓去除过程中报错了
// Eliminate too short or too long contours
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
std::vector >::const_iterator itc = contours.begin();
while (itc!=contours.end())
{
if (itc->size() < cmin || itc->size() > cmax)
itc=contours.erase(itc);
else
++itc;
}
错误如下:错误:no matching function for call to 'std::vector > >::erase(std::vector > >::const_iterator&)',我理解的意思是这里erase函数用的不对,但是我是照着OpenCVcookbook做的,网上也搜了很多,都是这样写的,感觉不同于他们的是我的实在QT中编写,用OpenCV2.3.1,不知到为什么会报错,
然后就找他的定义,感觉用得也没错:
iterator
erase(iterator __position)
{
if (__position + 1 != end())
std::copy(__position + 1, end(), __position);
--this->_M_impl._M_finish;
return __position;
}
iterator
erase(iterator __first, iterator __last)
{
_M_erase_at_end(std::copy(__last, end(), __first));
return __first;
}
后来仔细看了,iterator和const_iterator不一样, typedef __gnu_cxx::__normal_iterator iterator; typedef __gnu_cxx::__normal_iterator const_iterator;
而我抄袭的程序里面都是const_iterator,该过来之后就可以了。
现在的问题是,我该怎么取适当的值,使得只有指甲的轮廓保留下来,其余的省去。还是一步一步来吧,先把轮廓查找的过程搞清楚。
findContours经常与drawContours配合使用,用来将轮廓绘制出来。其中第一个参数image表示目标图像,第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,第四个参数color为轮廓的颜色,第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,第六个参数lineType为线型,第七个参数为轮廓结构信息,第八个参数为maxLevel。
评论
查看更多