findContours函数说明
https://blog.csdn.net/marooon/article/details/81332487
https://blog.csdn.net/tanmx219/article/details/84973542
RETR_TREE:检测所有轮廓,并且所有轮廓建立一个树结构
坐标系说明
以屏幕左上角为坐标原点,左右为X轴,上下为Y轴,其中自左向右X坐标逐渐增大,自上向下Y坐标逐渐增大,如下图所示。
坐标系说明图
测试代码
//读入图片
Mat src = Imgcodecs.imread("F:\\opencvPhoto\\photo\\pppp.jpg");
//灰度化
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
//二值化
Imgproc.threshold(src, src, 120, 255, Imgproc.THRESH_BINARY);
//findContours测试
List<MatOfPoint> contours=new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(src, contours, hierarchy, Imgproc.RETR_TREE , Imgproc.CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++) {
Mat temp = new Mat(src.size(), CvType.CV_8U, new Scalar(0));
Imgproc.drawContours(temp, contours, i, new Scalar(255), -1);
//ds[0]->同层级的下一个轮廓(不存在为-1)
//ds[1]->同层级的上一个轮廓(不存在为-1)
//ds[2]->第一个子轮廓(不存在为-1)
//ds[3]->父轮廓(不存在为-1)
double[] ds = hierarchy.get(0, i);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(i); //轮廓标记
stringBuilder.append("="); //分割符
stringBuilder.append(ds[0]); //同层级的下一个轮廓
stringBuilder.append("="); //分割符
stringBuilder.append(ds[1]); //同层级的上一个轮廓
stringBuilder.append("="); //分割符
stringBuilder.append(ds[2]); //第一个子轮廓
stringBuilder.append("="); //分割符
stringBuilder.append(ds[3]); //父轮廓
stringBuilder.append(".jpg");
Imgcodecs.imwrite("F:\\opencvPhoto\\result\\" + stringBuilder, temp);
}
图片测试
1. 不同轮廓等级
图片1
图片1结果
规律
在不同轮廓等级情况下,轮廓顺序为从外到里
2. 同等级轮廓
图片2
图片2说明:将图片2内矩形从左到右依次标号为0-4,其中0号矩形(最左端矩形)和4号矩形(最右端矩形)最高像素点Y坐标相同
图片2结果
图片2结果说明:轮廓输出顺序为1,2,4,0,3
规律
在同轮廓等级下轮廓根据轮廓最上像素点Y坐标从大到小排序(图片的从下到上),若存在Y坐标相同情况下根据X坐标从大到小排序(图片的从右到左)
图片3
图片3结果
规律
只有将内部轮廓全部找出才继续进行同级轮廓查找
结论
- 不同层级的轮廓顺序从里到外
- 同级轮廓根据轮廓最上像素点Y坐标从大到小排序(图片的从下到上),若存在Y坐标相同情况下根据X坐标从大到小排序(图片的从右到左)
- 若一个轮廓内有子轮廓,回先查找该轮廓的所有子轮廓后才会继续同级轮廓的查找。(有点像深搜)
- RETR_TREE是分层的所以同层级的下一个轮廓(ds[0]),同层级的上一个轮廓(ds[1])需要注意是否为同级轮廓