上次本来想介绍怎么计算封闭连续区域的面积和周长,结果不小心说成了sobel算子的介绍,这次真的介绍如何计算面积和周长。这里试验用到三幅图片,test1,test2,test3.test4如下图所示:
注意,这里已经将物体从背景中分离开,即背景为0,前景在计算中会被设置为255,即黑色代表背景,白色代表物体,分离的办法很多,暂不解释,不然又要走题了。
首先介绍的是脚趾头法,为什么叫脚趾头法呢,因为用脚趾头都能想到这个方法,就是直接统计像素点,对于周长就计算边界像素点个数,面积就计算整个物体包含像素点个数。对图片test1和test3计算结果如表1所示。
代码如下,注意这里使用的是VS208+OpenCV 2.4 环境:
int main( int argc, char** argv )
{
}
代码如下:
如表1所示效率得到了极大提高,然而本质的缺陷没有得到解决, 对该算法的分析如表2所述。
代码如下:
…………..
…………..
(等待添加)
…………..
…………..
此时效率得到了更大的提高,毕竟只计算了边界像素点,对其详细分析如表2所述。
和大家经验一样,很多好的算法OpenCV里面已经自带了,这些工具包的目的是方便大家使用,但是使用多了就会发现很多很常用的算法其实都根本不懂,时间长了之后很容易忘掉。但这里还是介绍下OpenCV自带的链码方法,名字叫眼睛法,因为用眼睛看就行了,这种方法。计算结果如表1所示
代码如下:
//自带函数计算
start=GetTickCount();
vector<vector<Point> > contours;
findContours(image_bin, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); double Leafarea=contourArea(contours[0]);
double Leaflength=arcLength(contours[0],1);
timeConsume=(GetTickCount()-start)*1.0/1000;
此时效率大大提高,时间消耗已经接近0,具体分析如表2所示。
绘制出轮廓
//image=cv::imread("test2.bmp",1);
//cvtColor( image, image_gray, CV_BGR2GRAY );//变成灰度图
//Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC3);
//vector<Vec4i> hierarchy;
//findContours( image_gray, contours, hierarchy,
//int idx = 0;
//for( ; idx >=0; idx = hierarchy[idx][0] )//画出所有的轮廓,idx为索引
//{
//Scalar color( rand()&255, rand()&255, rand()&255 );
//drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
//}
//namedWindow( "Components", 1 );
//imshow( "Components", dst );
//waitKey(0);
从表1细心的可以发现,用像素点统计的方法和链码的方法在计算面积上差异比较大,在test1测试中差异所占比例为(386607-385016)/386607=0.41%,在test3测试中差异所占比例为(82376-81428)/82376=1.15%.
假设像素点为矩形,放大像素点如图4所示,有个物体覆盖了三个像素带,按照统计像素点个数的方法面积计算为3. 而用链码计算面积则为2*2/2=2,此时明白统计像素点仅仅是统计像素点个数而不是计算面积,用像素点个数来逼近面积,当边角比较多的时候这种差异会更加明显。
源自:http://blog.sina.com.cn/s/blog_c144a0e40101aa9s.html