android opencv画轮廓,计算机视觉 OpenCV Android | 基本特征检测 之 轮廓分析
(0)轮廓分析概述及作用通过将Canny边缘提取或者二值化结果作为输入图像来实现轮廓发现与绘制,可是这些并不是我们想要的最终结果,我们一般根据获取到的轮廓求出它们的外接矩形或者最小外接矩形,并计算外接矩形的横纵比例、轮廓面积、周长等数据,然后使用这些数据实现特定几何形状轮廓的查找与过滤,为后续的处理与分析剔除不正确的区域而保留候选对象。(1)边界框最常见的获取轮廓的外接矩形是边界框,获取每个轮廓的
(0)轮廓分析概述及作用
通过将Canny边缘提取或者二值化结果作为输入图像来实现轮廓发现与绘制,
可是这些并不是我们想要的最终结果,
我们一般根据获取到的轮廓求出它们的外接矩形或者最小外接矩形,
并计算外接矩形的横纵比例、轮廓面积、周长等数据,
然后使用这些数据实现特定几何形状轮廓的查找与过滤,
为后续的处理与分析剔除不正确的区域而保留候选对象。
(1)边界框
最常见的获取轮廓的外接矩形是边界框,
获取每个轮廓的边界框,
通过它可以得到与各个轮廓相对应的高度与宽度,
并能通过它计算出轮廓的纵横比。
通过轮廓点集合得到轮廓边界框的API如下:
boundingRect(MatOfPoint points)
其中,points是轮廓所有点的集合对象。注意其数据类型。
调用该API会返回一个Rect对象实例,它是OpenCV关于矩形的数据结构,
从中可以得到外界矩形(边界框)的宽高,
然后就可以计算出轮廓的横纵比了。
这种情况下得到的边界框不一定满足条件,有时候我们还需要获取轮廓的最小边界框。
(2)最小边界框
与上面边界框不同的是,
获取到的最小边界框有时候不是一个水平或者垂直的矩形,
而是一个旋转了一定角度的矩形,
但是最小外接矩形(最小边界框)能够更加真实地反映出轮廓的几何结构大小,
而横纵比结果更能反映出轮廓的真实几何特征,
所以有些时候我们计算的经常是最小外接矩形,
相关API函数如下:
RotatedRect minAreaRect(MatOfPoint2f points)
其中,points是轮廓的所有点的集合对象。注意其数据类型。
调用该API会返回一个RotatedRect对象实例,
它是OpenCV关于旋转矩形的数据结构,
其包含了旋转角度,矩形的宽、高及四个顶点等信息,
通过相关的API都可以查询获得,
绘制旋转矩形对象的时候,
首先需要得到四个顶点,
然后通过OpenCV绘制直线的API来完成旋转矩形的绘制。
(3)面积与周长
轮廓分析中包含了轮廓大小的度量,
这些度量最常见的就是计算轮廓的面积大小与长度大小,
这些数据对分析轮廓与过滤掉一些不符合条件的轮廓十分有用。
计算轮廓面积的API如下:
contourArea(Mat contour, boolean oriented)
contour:轮廓的所有点的集合对象。
oriented:表示轮廓的方向,当oriented = true时返回的面积是一个有符号值,默认为false,返回的是绝对值。
计算轮廓周长的API如下:
arcLength(MatOfPoint2f curve, boolean closed)
curve:轮廓的所有点的集合对象。注意数据类型。
closed:表示是否为闭合曲线,默认是true。
完整的发现获取轮廓、外接轮廓、最小外接轮廓、横纵比、面积与长度的代码演示如下:
private void measureContours(Mat src, Mat dst) {
Mat gray= new Mat();
Mat binary = new Mat();
// 二值
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
// 轮廓发现
List contours = new ArrayList();
Mat hierarchy = new Mat();
Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
// 测量轮廓
dst.create(src.size(), src.type());
for(int i=0; i
Rect rect = Imgproc.boundingRect(contours.get(i));
double w = rect.width;
double h = rect.height;
double rate = Math.min(w, h)/Math.max(w, h);
Log.i("Bound Rect", "rate:" + rate);//一个轮廓元素打印一次
RotatedRect minRect = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(i).toArray()));
w = minRect.size.width;
h = minRect.size.height;
rate = Math.min(w, h)/Math.max(w, h);
Log.i("Min Bound Rect", "rate:" + rate);
double area = Imgproc.contourArea(contours.get(i), false);
double arclen = Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true);
Log.i("contourArea", "area:" + rate);
Log.i("arcLength", "arcLength:" + arclen);
Imgproc.drawContours(dst, contours, i, new Scalar(0, 0, 255), 1);
}
// 释放内存
gray.release();
binary.release();
}
运行结果(左侧是原图,右侧是轮廓发现与绘制,计算结果参见logcat):
上述的代码是求取图像的全部轮廓,
修改上述程序,把返回轮廓改为返回最外层轮廓RETR_EXTERNAL,
同时修改阈值化方法,将其改为THRESH_BINARY_INV,
则运行结果如下:
感兴趣的小伙伴可以进一步细化该方法,
将计算得到的轮廓几何属性值如长度、面积等
通过putText函数显示到输出的图像上
参考材料
更多推荐
所有评论(0)