24.java openCV4.x 入门-Imgproc之轮廓凸包与凹陷检测(形状识别)
| 专栏简介 | ||
💒个人主页 | 📖心灵鸡汤📖 我们唯一拥有的就是今天,唯一能把握的也是今天 建议把本文当作笔记来看,据说专栏目录里面有相应视频🤫 | 📰专栏目录 |
Imgproc之轮廓凸包与凸起缺陷检测
- 一、凸包检测
- 1.凸轮廓检测
- 2.凸包寻找
- 二、凸包凹陷检测
一、凸包检测
1.凸轮廓检测
凸轮廓是指在轮廓上的任意两点之间的直线段都位于轮廓内部。这个方法可以用于检查轮廓的凸性质,以便在图像处理中进行相应的操作,比如在计算凸包时进行预处理
| isContourConvex(MatOfPoint contour) | |
| 参数: | |
| contour | 一个 MatOfPoint 类型的对象,表示输入的轮廓 |
2.凸包寻找
convexHull用于找到输入点集的凸包
| convexHull(MatOfPoint points, MatOfInt hull, boolean clockwise) | |
| 参数: | |
| points | 一个包含点集的 MatOfPoint 对象 |
| hull | 输出的凸包。它可以是以下两种形式之一 1.整数向量,包含凸包点的索引。在这种情况下,凸包元素是原始数组中凸包点的0-based索引(因为凸包点集合是原始点集的一个子集) 2.点向量。在这种情况下,hull元素是凸包点本身 |
| clockwise | 方向标志。如果为true,则输出凸包按顺时针方向排列。否则,按逆时针方向排列。假设的坐标系中,X轴指向右侧,Y轴指向上方 |
示例一、
MatOfPoint matOfPoint = new MatOfPoint();//随机设置点集matOfPoint.fromArray(new Point(1,2),//0new Point(2,1), //1new Point(4,2),//2new Point(4,4),//3new Point(2,3)//4);//定义输出凸包MatOfInt hull = new MatOfInt();//查找凸包Imgproc.convexHull(matOfPoint,hull,false);//打印结果System.out.println("点集数据:\n " + matOfPoint.dump());System.out.println("凸包数据:\n " + hull.dump());System.out.println("凸包对应点集数据:" );List points = matOfPoint.toList();hull.toList().forEach(hu->{System.out.println(hu+">>"+ points.get(hu));});
结果:

由上图可以看出,存储顺序似乎与描述不符。这是由于我们是按照坐标系x在右,y在下的原因。(了解即可)
示例二、
// 加载图像灰度化Mat src = Imgcodecs.imread(FileUtil.resPath+"imgproc/convex_hull_hand.jpeg");// 转换为灰度图Mat gray = new Mat();Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);// 二值化Mat dst = new Mat();Imgproc.threshold(gray, dst, 50, 255, Imgproc.THRESH_BINARY);// 寻找轮廓List contours = new ArrayList<>();Mat hierarchy = new Mat();//查找轮廓,仅检索外部轮廓,仅保留端点Imgproc.findContours(dst, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);// 创建一个空白的列表,用于存储所有的凸包点//获取轮廓的凸包contours.forEach(contour->{List pts =new ArrayList<>();//点集List points = contour.toList();MatOfInt hull = new MatOfInt();//获取凸包Imgproc.convexHull(contour,hull,false);//将凸包转换为坐标// 将凸包的索引转换为点坐标MatOfPoint hullPoints = new MatOfPoint();hullPoints.create((int) hull.size().height, 1, CvType.CV_32SC2);for (int j = 0; j < hull.size().height; j++) {int index = (int) hull.get(j, 0)[0];double[] point = new double[]{contour.get(index, 0)[0],contour.get(index, 0)[1]};hullPoints.put(j, 0, point);}pts.add(hullPoints);//绘制凸包线段Imgproc.polylines(src,pts,true,new Scalar(0,255,0),2);});Imgcodecs.imwrite(FileUtil.resPath+"imgproc/polylines_hand_result.jpg",src);
结果:
![]() | ![]() |
|---|---|
| convex_hull_hand.jpeg | polylines_hand_result.jpg |
二、凸包凹陷检测
查找轮廓的凸起缺陷。
| convexityDefects(MatOfPoint contour, MatOfInt convexhull, MatOfInt4 convexityDefects) | |
| 参数: | |
| contour | 输入的轮廓,通常是一个点的数组 |
| convexhull | 使用convexHull方法获得的凸包,其中应包含构成凸包的轮廓点的索引 |
| convexityDefects | 每个凸起缺陷都表示为4个元素的整数向量(也称为Vec4i):(起始索引,结束索引,最远点的索引,fixpt_depth),其中索引是原始轮廓中凸起缺陷开始、结束和最远点的0基索引,而fixpt_depth是固定点近似(具有8位小数)最远轮廓点与凸包之间的距离。也就是说,要获得深度的浮点值,需要将fixpt_depth除以256.0 |
示例一、
MatOfPoint matOfPoint = new MatOfPoint();//设置点集matOfPoint.fromArray(new Point(1,2),//0new Point(2,2),new Point(2,1), //1new Point(3,2),new Point(4,2),//2new Point(4,4),//3new Point(3,3),new Point(2,3)//4);//定义输出凸包MatOfInt hull = new MatOfInt();//查找凸包Imgproc.convexHull(matOfPoint,hull,false);//打印结果System.out.println("点集数据:\n " + matOfPoint.dump());System.out.println("凸包数据:\n " + hull.dump());System.out.println("凸包对应点集数据:" );hull.toList().forEach(hu -> {Point point = matOfPoint.toList().get(hu);System.out.println("point = " + point);});//执行凸包缺陷检测MatOfInt4 matOfInt4 = new MatOfInt4();Imgproc.convexityDefects(matOfPoint,hull,matOfInt4);//打印结果System.out.println("凸包缺陷数据:\n " + matOfInt4.dump());System.out.println("凸包缺陷对应点集合数据:");List integers = matOfInt4.toList();int size = integers.size()/4;for (int i = 0; i < size; i++) {//起始索引int startIndex = integers.get(i*4);//结束索引int endIndex = integers.get(i*4+1);//最远索引int farstIndex = integers.get(i*4+2);//距离int fixptDepth = integers.get(i*4+3);double depth =(double) fixptDepth/256.0;//举例System.out.println("depth = " + depth);//凸起缺陷坐标Point point = matOfPoint.toList().get(farstIndex);System.out.println("point = " + point);}

// 加载图像Mat src = Imgcodecs.imread(FileUtil.resPath+"imgproc/convex_hull_hand.jpeg");// 转换为灰度图Mat gray = new Mat();Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);// 二值化Mat binary = new Mat();Imgproc.threshold(gray, binary, 50, 255, Imgproc.THRESH_BINARY);// 寻找轮廓List contours = new ArrayList<>();Mat hierarchy = new Mat();Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);// 创建一个空白的图像,用于绘制凸包Mat dst = Mat.zeros(src.size(), src.type());// 遍历每个轮廓for (int i = 0; i < contours.size(); i++) {MatOfPoint matOfPoint = contours.get(i);// 计算轮廓的凸包MatOfInt hull = new MatOfInt();Imgproc.convexHull(contours.get(i), hull, false);// 将凸包的索引转换为点坐标MatOfPoint hullPoints = new MatOfPoint();hullPoints.create((int) hull.size().height, 1, CvType.CV_32SC2);for (int j = 0; j < hull.size().height; j++) {int index = (int) hull.get(j, 0)[0];double[] point = new double[]{contours.get(i).get(index, 0)[0], contours.get(i).get(index, 0)[1]};hullPoints.put(j, 0, point);}// 绘制凸包Scalar color = new Scalar(0, 255, 0); // 绿色Imgproc.drawContours(dst, contours, i, color, 2); // 绘制轮廓List pts = new ArrayList();pts.add(hullPoints);Imgproc.polylines(src, pts, true, color, 2); // 绘制凸包//执行凸包缺陷检测MatOfInt4 matOfInt4 = new MatOfInt4();Imgproc.convexityDefects(matOfPoint,hull,matOfInt4);List integers = matOfInt4.toList();int size = integers.size()/4;int index =0;for (int r = 0; r <size; r++) {//起始索引int startIndex = integers.get(r*4);//结束索引int endIndex = integers.get(r*4+1);//最远索引int farstIndex = integers.get(r*4+2);//距离int fixptDepth = integers.get(r*4+3);double depth =(double) fixptDepth/256.0;//过滤if (depth> 15){//凸起缺陷坐标Point point = matOfPoint.toList().get(farstIndex);//凸起缺陷点绘制Imgproc.circle(src,point,10,new Scalar(0,0,255),2);index++;}}System.out.println("过滤后凸起缺陷个数:"+index);// 保存结果图像Imgcodecs.imwrite(FileUtil.resPath+"imgproc/convex_defects_result.png", src);}
结果:
![]() | ![]() |
|---|---|
| convex_hull_hand.jpeg | convex_defects_result.jpeg |
此方法除了用于手势识别。还可以通过分析凹陷的位置和形状,推断物体的形状和轮廓。
| 万水千山总是情,本栏完全公开免费。点赞+收藏过30,瞬更下一篇 | |
| 上一篇:Imgproc之轮廓提取与绘制 | 下一篇:Imgproc之点集最小面积外接 |



