【问题标题】:OpenCV - Remove wrong contoursOpenCV - 删除错误的轮廓
【发布时间】:2019-03-20 01:50:37
【问题描述】:

我有一个关于 OpenCV 和寻找特定形状的简短问题。在我的电脑上,我有一些形状的图片,但我只想要矩形的轮廓:

输入文件:

我的输出应该是:

我的输出实际上是:


我做了什么:

  1. 打开我的图像并将其转换为 OpenCV Mat。
  2. 做了一些图像处理[灰度,模糊]
  3. 用 Canny 找到边缘
  4. 使用“findContours”找到轮廓
  5. 使用“boundingRect”在我的轮廓周围绘制矩形

这就是我坚持的地方。我不知道如何消除错误的轮廓。我尝试迭代我的轮廓并删除不正确的轮廓。但我不知道如何找到错误的轮廓。有没有我必须使用的公式或某事。像这样?我发现了一些带有“arcLength”的东西,但我不明白这一点。


这是我的代码:

package main;

import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;


import helper.ImageProcHelper;


public class Main {


    public static void main(String[] args) throws Exception {

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        File file = new File("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\pic4.png");

        Mat mat = new Mat(CvType.CV_8UC4);
        Mat procMat = new Mat();
        Mat hierarchy = new Mat();
        Scalar color = new Scalar(0,0,255);
        List<MatOfPoint> contours = new ArrayList<>();

        try {
            BufferedImage picture = ImageIO.read(file);
            BufferedImage image = new BufferedImage(picture.getWidth(), picture.getHeight(), 5);
            image.getGraphics().drawImage(picture, 0, 0, null);

            System.out.println(image.getType());
            mat = ImageProcHelper.ImageToMat(image);

            Imgproc.cvtColor(mat, procMat, Imgproc.COLOR_RGBA2GRAY);
            Imgproc.blur(procMat, procMat, new Size(3,3));
            Imgproc.Canny(procMat, procMat, 127, 255);

            //Konturen finden           
            Imgproc.findContours(procMat, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);

            MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()];
            Rect[] boundRect = new Rect[contours.size()];           


            for(int i = 0; i < contours.size(); i++) {
                contoursPoly[i] = new MatOfPoint2f();
                Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 0.1,  true);
                boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contours.get(i).toArray()));     
            }


            for (int i = 0; i < contours.size(); i++) {
                Imgproc.rectangle(mat, boundRect[i].tl(), boundRect[i].br(), color, 1);
            }

            image = ImageProcHelper.MatToImage(mat);
            ImageIO.write((RenderedImage)image, "png", new File ("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\output.png"));


        } catch (IOException e) {
            System.out.println("Error");
        }   
    }
}

这个项目的重点是什么:

我有一台网络摄像机正在播放视频。在这个项目中,我想在流中找到所有二维码,裁剪它们并将它们传递给解码器(例如 ZXing)。我只用 ZXing 试过这个,但我在角度、尺寸等方面遇到了问题。这就是为什么我想使用 OpenCV 来查找代码并操纵它们以减少从 IP 摄像机到解码器的流量并(也许)增加命中率。

二维码示例:

这应该是我的输出:

这是我的输出:


非常感谢您的帮助。

【问题讨论】:

  • 顶部的问题是由于处理了外部和内部轮廓。在我看来,您只应该关心外部的。 |第二种情况是你得到多个轮廓并单独处理它们——这就是你得到这么多不同框的原因。您似乎想要的是找到一个适合所有这些的边界框 - 简单的方法是将所有轮廓中的所有顶点放入一个列表中并为此找到一个边界矩形。

标签: java opencv qr-code opencv-contour opencv-drawcontour


【解决方案1】:

我没有足够的声誉来发表评论,但您似乎缺少的是检查每个轮廓的侧面。在您的代码中,您需要使用 contoursPoly[i].size() 来区分不同的形状。您的代码最终需要看起来像这样:

package main;

import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;


import helper.ImageProcHelper;


public class Main {


    public static void main(String[] args) throws Exception {

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        File file = new File("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\pic4.png");

        Mat mat = new Mat(CvType.CV_8UC4);
        Mat procMat = new Mat();
        Mat hierarchy = new Mat();
        Scalar color = new Scalar(0,0,255);
        List<MatOfPoint> contours = new ArrayList<>();

        try {
            BufferedImage picture = ImageIO.read(file);
            BufferedImage image = new BufferedImage(picture.getWidth(), picture.getHeight(), 5);
            image.getGraphics().drawImage(picture, 0, 0, null);

            System.out.println(image.getType());
            mat = ImageProcHelper.ImageToMat(image);

            Imgproc.cvtColor(mat, procMat, Imgproc.COLOR_RGBA2GRAY);
            Imgproc.blur(procMat, procMat, new Size(3,3));
            Imgproc.Canny(procMat, procMat, 127, 255);

            //Konturen finden           
            Imgproc.findContours(procMat, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);

            MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()];
            Rect[] boundRect = new Rect[contours.size()];           


            for(int i = 0; i < contours.size(); i++) {
                contoursPoly[i] = new MatOfPoint2f();
                Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 0.1,  true);
                boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contours.get(i).toArray()));  
            }


            for (int i = 0; i < contours.size(); i++) {
                if (contoursPoly[i].size()>15){
                    Imgproc.rectangle(mat, boundRect[i].tl(), boundRect[i].br(), color, 1);
                }
            }

            image = ImageProcHelper.MatToImage(mat);
            ImageIO.write((RenderedImage)image, "png", new File ("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\output.png"));


        } catch (IOException e) {
            System.out.println("Error");
        }   
    }
}

我没有使用 OpenCV 设置 Java,所以我无法测试这段代码,但这个想法来自 link。您可能不得不弄乱“15”来区分矩形和圆形。

【讨论】:

    猜你喜欢
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 2022-01-23
    • 2019-07-05
    • 1970-01-01
    • 2017-06-27
    • 2014-08-23
    相关资源
    最近更新 更多