Java+opencv3.2.0之删除最小连通区域

吐槽一下,在网上查了半天opencv3关于删除最小连通区域的方法,结果还是没找到,就自己写了一个,效果还可以,就发出来和大家分享一下。

思路:
1、遍历所有像素点
2、每遍历到一个黑点就去判断是否为连通区域起始点,若是则添加到待检测像素点集合中
3、遍历待检测像素点集合,检测待检测像素点周围(上下左右)的像素点,若是黑点,则添加到待检测像素点集合中,并把当前待检测像素点添加到已检测点集合。若待检测点集合中像素点数小于某个阈值时,就认为这些待检测点区域为最小连通区域。
4、查找到最小连通区域后把已检测点集合中的像素点设置成白点。

代码:

/**
     * 判断是否为连通区域起始点(有点问题,有待优化)
     * @param i 待检验点的横坐标
     * @param j 待检验点的纵坐标
     * @param srcImage 源图像
     * @return true表示是连通区域起始点,false则反之
     */
    public boolean isStart(int i, int j, Mat srcImage){
        int before = j - 1;
        int top = i - 1;

        if((before<0||srcImage.get(i, before)[0] == 255.0) && (top<0 || srcImage.get(top, j)[0] == 255.0)){
            return true;
        }
        return false;
    }

public Mat deleteMinConnectedArea(Mat srcImage,double minarea){

        int iw = srcImage.width(); //横向
        int ih = srcImage.height(); //纵向

        System.out.println("宽和高:"+ iw +" "+ ih);

        for (int i = 0; i < ih; i++) {
            for (int j = 0; j < iw; j++) {
                double[] colors = srcImage.get(i, j);
                if(colors[0] < 255.0 && isStart(i, j, srcImage)){
                    List<Point> checkPoint = new ArrayList<Point>();
                    List<Point> checkedPoint = new ArrayList<Point>();
                    checkPoint.add(new Point(i, j));
                    ergodic(srcImage, checkPoint, checkedPoint, (int) minarea);
                }
            }
        }

        return srcImage;
    }

/**
     * 连通像素计数
     * @param i 第一个检测到的像素为0的横坐标
     * @param j 第一个检测到的像素为0的纵坐标
     * @param iw 源图像像素列数
     * @param ih 源图像像素行数
     * @param srcImage 源图像
     * @param sp 待检测像素点
     * @param lp 已检测像素点
     */
    public void ergodic(Mat srcImage, List<Point> sp, List<Point> lp, int minArea ){


        for (int k = 0; k < sp.size(); k++) {
            check((int) sp.get(k).x, (int) sp.get(k).y, sp, lp, srcImage);

            if(sp.size() >= minArea){
                lp.removeAll(lp);
                break;
            }
        }

        if(lp.size() < minArea){
            for (Point point : lp) {
                srcImage.put((int) point.x, (int) point.y, 255.0);
            }
        }

    }

/**
     * 像素点判断是否已检测过
     * @param i 待检验是否已检测像素点横坐标
     * @param j 待检验是否已检测像素点纵坐标
     * @param lp 已检测点集合
     * @return 检测结果  false表示未检测,true表示已检测
     */
    public boolean isExist(int i, int j, List<Point> lp){
        if(lp.size() == 0){
            return false;
        }

        for (Point point : lp) {
            if(point.x == i && point.y == j ){
                return true;
            }
        }

        return false;
    }

/**
     * 像素点判断是否已被发现(存储在待检测集合)
     * @param i 待检验是否已检测像素点横坐标
     * @param j 待检验是否已检测像素点纵坐标
     * @param sp 已检测点集合
     * @return 检测结果  false表示未检测,true表示已检测
     */
    public boolean isFind(int i, int j, List<Point> sp){
        if(sp.size() == 0){
            return false;
        }

        for (Point point : sp) {
            if(point.x == i && point.y == j){
                return true;
            }
        }

        return false;
    }

/**
     * 检测当前像素点上下左右的像素,并把当前像素点添加到已检测集合
     * @param i 检测当前像素点横坐标
     * @param j 检测当前像素点纵坐标
     * @param sp 待检测点集合
     * @param lp 已检测点集合
     * @param srcImage 源图像
     */
    public void check(int i, int j, List<Point> sp, List<Point> lp, Mat srcImage){
        int before = j - 1;
        int after = j + 1;
        int top = i - 1;
        int bottom = i + 1;

        if(before >= 0 && srcImage.get(i, before)[0] == 0.0){
            if(!isExist(i, before, lp) && !isFind(i, before, sp)){
                sp.add(new Point(i, before));
            }
        }

        if(after < srcImage.width() && srcImage.get(i, after)[0] == 0.0){
            if(!isExist(i, after, lp) && !isFind(i, after, sp)){
                sp.add(new Point(i, after));
            }
        }

        if(top >= 0 && srcImage.get(top, j)[0] == 0.0){
            if(!isExist(top, j, lp) && !isFind(top, j, sp)){
                sp.add(new Point(top, j));
            }
        }
        if(bottom < srcImage.height() && srcImage.get(bottom, j)[0] == 0.0){
            if(!isExist(bottom, j, lp) && !isFind(bottom, j, sp)){
                sp.add(new Point(bottom, j));
            }
        }

        lp.add(new Point(i,j));
    }

public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        Mat mat = Imgcodecs.imread("F:\\20170801161034.png");

        Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2GRAY); 
        Imgproc.adaptiveThreshold(mat, mat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 9, 0);



        Mat dst = new DeleteMinArea().deleteMinConnectedArea(mat,50);
        Imgcodecs.imwrite("F:\\31.jpg", dst);
    }

源图片:
这里写图片描述

结果图片:
这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值