• 【图像处理】openCV中生成掩膜区域的方式以及Points的规则


    openCV中生成掩膜区域的方式以及Points的规则

    背景描述

    在上一篇文章使用openCV生成用户的ROI图片的需求,我们是自定义的mask的区域边界点,其实这些个边界点是有讲究了,上一篇没有讲到这一点,本文主要介绍openCV中的区域边界点的生成原则

    生成mask的思路

    在这里插入图片描述

    区域生成点(Point)的规则

    我们知道了mask的生成方法,首先需要给出这个区域的边界点Point,再根据这些点生成对应的区域。

    先说结论:点的顺序必须是一个方向的,顺时针或逆时针,最后一个点会默认连接到起点。

    例子如下:

    		List<Point> list = new ArrayList<>();
            list.add(new Point(50, 50));
            list.add(new Point(200, 50));
            list.add(new Point(200, 200));
            list.add(new Point(50, 200));
            
    		// 构建掩膜mask
            List<MatOfPoint> maskArea = new ArrayList<>();
            MatOfPoint maskPoints = new MatOfPoint();
            maskPoints.fromList(list);//list转移给MatOfPoint
            maskArea.add(maskPoints);//加入到区域中
    
            Mat mask;
            mask = new Mat(new Size(img.width(), img.height()), CvType.CV_8UC3, new Scalar(0, 0, 0));//定义成黑色
            Imgproc.fillPoly(mask, maskArea, new Scalar(255, 255, 255));//填充多边形,生成mask,定义成白色
            // 保存mask图片
            Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\mask.tiff", mask);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这个例子中,point的顺序是顺时针的,能够成功得到一个长方形
    在这里插入图片描述
    如果将点的顺序变为如下方式,那么效果就会很奇怪。

            list.add(new Point(50, 50));
            list.add(new Point(200, 50));
            list.add(new Point(50, 200));
            list.add(new Point(200, 200));
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    究其原因,其底层的生成策略是按照list中点的顺序去构建一个图形,相当于就是一笔按顺序将所有点连接起来。

    如果在具体的业务需求中,我们不可能让上面这种情况出现的,也就是说,我们需要将前端传入的这些点进行重新排序,使得所有点的顺序是按照顺时针(或逆时针),具体方法请看openCV中生成掩膜区域的参数(Point)处理:凸包算法

    生成单区域掩膜

    之前的文章已经介绍了。openCV生成用户的ROI图片的需求中

    生成多区域掩膜

    一个mask中可以拥有多个区域,同时openCV的API中也支持这一点。具体的,一个List就是代码一个mask的区域,可以向里面添加多个MatOfPoint,其中每一个MatOfPoint就是一块区域。

    核心代码如下:

            // 构建掩膜mask
            List<MatOfPoint> maskArea = new ArrayList<>();
            MatOfPoint maskPoints = new MatOfPoint();//区域1
            MatOfPoint maskPoints2 = new MatOfPoint();//区域2
            maskPoints.fromList(list);//将point的list转移生成MatOfPoint的区域1
            maskPoints2.fromList(list2);//将point的list转移生成MatOfPoint的区域1
    
    		//将两个区域分别加到mask中
            maskArea.add(maskPoints);
            maskArea.add(maskPoints2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    完整代码如下:

    package com.example.phenocam.test;
    
    import org.junit.Test;
    import org.opencv.core.*;
    import org.opencv.imgcodecs.Imgcodecs;
    import org.opencv.imgproc.Imgproc;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @description:
     * @author: ZW
     * @email:
     * @create: 2022-07-21 10:57
     **/
    
    public class MyTest {
        @Test
        public void tes(){
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
            Mat img = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\20220721133904.jpg");
    
            //定义mask的区域边界点,这个Point是openCV包下定义的
            List<Point> list = new ArrayList<>();
            list.add(new Point(442, 139));//1
            list.add(new Point(426, 220));//2
            list.add(new Point(442, 139+173));//3
            list.add(new Point(542, 139+173));//4
            list.add(new Point(552+16, 220));//5
            list.add(new Point(552, 139));//6
    
            List<Point> list2 = new ArrayList<>();
            list2.add(new Point(473, 337));
            list2.add(new Point(472, 427));
            list2.add(new Point(417, 470));
            list2.add(new Point(382, 615));
            list2.add(new Point(639, 615));
            list2.add(new Point(588, 489));
            list2.add(new Point(544, 449));
            list2.add(new Point(565, 337));
    
    
            // 构建掩膜mask
            List<MatOfPoint> maskArea = new ArrayList<>();
            MatOfPoint maskPoints = new MatOfPoint();
            MatOfPoint maskPoints2 = new MatOfPoint();
            maskPoints.fromList(list);
            maskPoints2.fromList(list2);
    
            maskArea.add(maskPoints);
            maskArea.add(maskPoints2);
    
            Mat mask;
            mask = new Mat(new Size(img.width(), img.height()), CvType.CV_8UC3, new Scalar(0, 0, 0));//定义成黑色
            Imgproc.fillPoly(mask, maskArea, new Scalar(255, 255, 255));//填充多边形,生成mask,定义成白色
            // 保存mask图片
            Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\mask.tiff", mask);
    
            //根据mask将原图片img复制生成ROI图片dist
            Mat dist = new Mat(new Size(img.width(), img.height()), CvType.CV_8UC3, new Scalar(0, 0, 0));
            img.copyTo(dist, mask);
            Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\dist.tiff", dist);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    效果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    基于原子变量的内存模型优化
    可用性测试的理解
    .NET 7 预览版2 的亮点之 NativeAOT 正式合并入 .NET 主线
    Java8(JDK1.8)新特性
    node项目调试
    常见的作物模型有哪些?DSSAT模型、APSIM模型、WOFOST模型与PCSE模型等应用
    Exadata想要补装Oracle 11g的注意事项
    在 Linux 中,可以使用分号 (;) 或者 && 运算符来执行多条命令
    idea意外退出mac
    linux之基础shell脚本编程4 字符串操作,变量赋值,配置用户环境
  • 原文地址:https://blog.csdn.net/Supreme7/article/details/125907737