封闭连续区域的面积和周长计算【2】--面积与周长
2013-12-13 09:24
507 查看
上次本来想介绍怎么计算封闭连续区域的面积和周长,结果不小心说成了sobel算子的介绍,这次真的介绍如何计算面积和周长。这里试验用到三幅图片,test1,test2,test3.test4如下图所示:
图1 实际场景中图片
图2 人造数据集,场景包含多个物体
图3 人造数据集,边界棱角较多
图4 假想图像
注意,这里已经将物体从背景中分离开,即背景为0,前景在计算中会被设置为255,即黑色代表背景,白色代表物体,分离的办法很多,暂不解释,不然又要走题了。
首先介绍的是脚趾头法,为什么叫脚趾头法呢,因为用脚趾头都能想到这个方法,就是直接统计像素点,对于周长就计算边界像素点个数,面积就计算整个物体包含像素点个数。对图片test1和test3计算结果如表1所示。
代码如下,注意这里使用的是VS208+OpenCV 2.4 环境:
int main( int argc, char**
argv )
{
Mat image,image_gray,image_edge,image_bin; //
image=cv::imread("test3.bmp",1);
cvtColor( image, image_gray, CV_BGR2GRAY );//变成灰度图
threshold(image_gray,image_bin,10,255,THRESH_BINARY);//二值化图像
int start;
double timeConsume;
// 统计像素点个数,慢速
double circle=0;
double area=0;
start=GetTickCount();
Canny(image_bin,image_edge,100,200,3);
image_bin.convertTo(image_bin,CV_64FC1);
image_edge.convertTo(image_edge,CV_64FC1);
for(int p=0;p<image_bin.rows;p++)
for(int q=0;q<image_bin.cols;q++)
{ {
if(image_edge.at<double>(p,q)>0)
circle++;
if(image_bin.at<double>(p,q)>0)
area++;
}
}
timeConsume=(GetTickCount()-start)*1.0/1000;//
test 0.171 test3 1.782
return 0;
}
看起来很简单,如其名字,但是现在用的是效率很高的C/C++尚且需要那么长时间,想想其他编译器吧,只能说这个算法效率太差!算法的总结如表2所述。
接着头脑法,本质还是统计像素点,但用大脑对统计的方法做出了改进,使之效率飞升,在计算中我们常常用到像素点的统计,但是没有引起重视,本质原因就是统计像素点我们一般直接在matlab中敲命令add即可,真方便,可惜离开了matlab命令就用不上去了。所以用大脑考虑从这一点出发,设计快速统计的方法,计算结果如表1.
代码如下:
// //统计像素点个数,快速
////////canny算子来提取边界
// start=GetTickCount();
// Canny(image_bin,image_edge,100,200,3);
//image_edge.convertTo(image_edge,CV_64FC1);
//image_edge=addmatrix(image_edge);
//image_edge=addmatrix(image_edge.t());
//double circle=image_edge.at<double>(0,0)/255;
//image_bin.convertTo(image_bin,CV_64FC1);
//image_bin=addmatrix(image_bin);
//image_bin=addmatrix(image_bin.t());
//double area=image_bin.at<double>(0,0)/255;
//timeConsume=(GetTickCount()-start)*1.0/1000;
//addmatrix为我自己写的函数,但根据函数格式,应该能猜到算法
如表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所示。
这里提到了OPenCV自带轮廓相关的函数,顺便给出绘制轮廓的相关代码如下
////绘制出轮廓
//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, CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE );
//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
图1 实际场景中图片
图2 人造数据集,场景包含多个物体
图3 人造数据集,边界棱角较多
图4 假想图像
注意,这里已经将物体从背景中分离开,即背景为0,前景在计算中会被设置为255,即黑色代表背景,白色代表物体,分离的办法很多,暂不解释,不然又要走题了。
首先介绍的是脚趾头法,为什么叫脚趾头法呢,因为用脚趾头都能想到这个方法,就是直接统计像素点,对于周长就计算边界像素点个数,面积就计算整个物体包含像素点个数。对图片test1和test3计算结果如表1所示。
代码如下,注意这里使用的是VS208+OpenCV 2.4 环境:
int main( int argc, char**
argv )
{
Mat image,image_gray,image_edge,image_bin; //
image=cv::imread("test3.bmp",1);
cvtColor( image, image_gray, CV_BGR2GRAY );//变成灰度图
threshold(image_gray,image_bin,10,255,THRESH_BINARY);//二值化图像
int start;
double timeConsume;
// 统计像素点个数,慢速
double circle=0;
double area=0;
start=GetTickCount();
Canny(image_bin,image_edge,100,200,3);
image_bin.convertTo(image_bin,CV_64FC1);
image_edge.convertTo(image_edge,CV_64FC1);
for(int p=0;p<image_bin.rows;p++)
for(int q=0;q<image_bin.cols;q++)
{ {
if(image_edge.at<double>(p,q)>0)
circle++;
if(image_bin.at<double>(p,q)>0)
area++;
}
}
timeConsume=(GetTickCount()-start)*1.0/1000;//
test 0.171 test3 1.782
return 0;
}
看起来很简单,如其名字,但是现在用的是效率很高的C/C++尚且需要那么长时间,想想其他编译器吧,只能说这个算法效率太差!算法的总结如表2所述。
接着头脑法,本质还是统计像素点,但用大脑对统计的方法做出了改进,使之效率飞升,在计算中我们常常用到像素点的统计,但是没有引起重视,本质原因就是统计像素点我们一般直接在matlab中敲命令add即可,真方便,可惜离开了matlab命令就用不上去了。所以用大脑考虑从这一点出发,设计快速统计的方法,计算结果如表1.
代码如下:
// //统计像素点个数,快速
////////canny算子来提取边界
// start=GetTickCount();
// Canny(image_bin,image_edge,100,200,3);
//image_edge.convertTo(image_edge,CV_64FC1);
//image_edge=addmatrix(image_edge);
//image_edge=addmatrix(image_edge.t());
//double circle=image_edge.at<double>(0,0)/255;
//image_bin.convertTo(image_bin,CV_64FC1);
//image_bin=addmatrix(image_bin);
//image_bin=addmatrix(image_bin.t());
//double area=image_bin.at<double>(0,0)/255;
//timeConsume=(GetTickCount()-start)*1.0/1000;
//addmatrix为我自己写的函数,但根据函数格式,应该能猜到算法
如表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所示。
这里提到了OPenCV自带轮廓相关的函数,顺便给出绘制轮廓的相关代码如下
////绘制出轮廓
//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, CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE );
//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
相关文章推荐
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续7)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续1)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续9)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续8)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续4)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续3)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续5)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(完)
- AutoLISP自动计算封闭区域面积
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续2)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续6)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(待续)
- 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集
- d003: 计算矩形的周长和面积
- 计算半径为5.3的圆的周长和面积
- 定义一个图形类及其子类(三角形类和矩形类),分别计算其面积和周长。(第十周)
- 十五周任务1:窗口启蒙(计算三角形周长和面积)
- 3-4 计算长方形的周长和面积
- 第四周项目二计算长方形周长和面积