在Java OpenCV中填写并检测轮廓矩形

时间:2013-09-02 22:34:47

标签: java opencv computer-vision

我有一个初始起始图像通过一些看起来像这样的处理

enter image description here

我想要做的是填写轮廓,使它看起来像这样

enter image description here

并找到两个(或更多)方块的最佳拟合平行四边形,这样可以让我得到这四条边界线中的每一条

enter image description here

如果有人能指出正确的功能会有所帮助,但我找不到任何有用的东西。我尝试了许多扭曲的矩形校正器,但却无法使它们起作用。

Heres当前源代码

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package javacvtesting;
import java.awt.FlowLayout;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
/**
 *
 * @author Arhowk
 */
public class JavaCVTesting {

    /**
     * @param args the command line arguments
     *//*
  */



    public static BufferedImage convert(Mat m){
        Mat image_tmp = m;

        MatOfByte matOfByte = new MatOfByte();

        Highgui.imencode(".png", image_tmp, matOfByte); 

        byte[] byteArray = matOfByte.toArray();
        BufferedImage bufImage = null;

        try {

            InputStream in = new ByteArrayInputStream(byteArray);
            bufImage = ImageIO.read(in);

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            return bufImage;
        }
    }
    public static Mat convert(BufferedImage i){
        BufferedImage image = i;
        byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        Mat mat = new Mat(image.getHeight(),image.getWidth(), CvType.CV_8UC3);
        mat.put(0, 0, data);
        return mat;
    }
    public static void show(BufferedImage i){
        JFrame frame = new JFrame();
        frame.getContentPane().setLayout(new FlowLayout());
        frame.getContentPane().add(new JLabel(new ImageIcon(i)));
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat src = Highgui.imread("D:\\0_image.png");
        Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2HSV);
        Mat dest = new Mat();
      // Mat dest = new Mat(src.width(), src.height(), src.type());
        Core.inRange(src, new Scalar(58,125,0), new Scalar(256,256,256), dest);

        Mat erode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3));
        Mat dilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
        Imgproc.erode(dest, dest, erode);
        Imgproc.erode(dest, dest, erode);

        Imgproc.dilate(dest, dest, dilate);
        Imgproc.dilate(dest, dest, dilate);

        List<MatOfPoint> contours = new ArrayList<>();

        Imgproc.findContours(dest, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
        Imgproc.drawContours(dest, contours, -1, new Scalar(255,255,0));

        Panel p = new Panel();
        p.setImage(convert(dest));
        p.show();
    }
}

2 个答案:

答案 0 :(得分:8)

  • 要确定外部轮廓,可以使用模式RETR_EXTERNAL的findContours:

    List<MatOfPoint> contours = new ArrayList<>();
    Mat dest = Mat.zeros(mat.size(), CvType.CV_8UC3);
    Scalar white = new Scalar(255, 255, 255));
    
    // Find contours
    Imgproc.findContours(image, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
    
    // Draw contours in dest Mat
    Imgproc.drawContours(dest, contours, -1, white);
    

    保存获得的垫子你会得到: enter image description here

  • 填写所获得的轮廓:

    for (MatOfPoint contour: contours) 
        Imgproc.fillPoly(dest, Arrays.asList(contour), white);
    

    保存新产生的Mat你会得到这个: enter image description here

  • 为每个轮廓找到最合适的矩形:

    Scalar green = new Scalar(81, 190, 0);
    for (MatOfPoint contour: contours) {
        RotatedRect rotatedRect = Imgproc.minAreaRect(new MatOfPoint2f(contour.toArray()));
        drawRotatedRect(dest, rotatedRect, green, 4);
    }
    
    public static void drawRotatedRect(Mat image, RotatedRect rotatedRect, Scalar color, int thickness) {
        Point[] vertices = new Point[4];
        rotatedRect.points(vertices);
        MatOfPoint points = new MatOfPoint(vertices);
        Imgproc.drawContours(image, Arrays.asList(points), -1, color, thickness);
    }
    

最后你得到这个结果图像: enter image description here

答案 1 :(得分:-1)

听起来像你想要floodfill()

相关问题