简体   繁体   English

Java OpenCV - 使用霍夫变换进行矩形检测

[英]Java OpenCV - Rectangle Detection with Hough Transform

I'm developing a program to detect rectangular shape and draw bounding box to the detected area.我正在开发一个程序来检测矩形形状并将边界框绘制到检测到的区域。

For edge detection, I used Canny Edge Detection.对于边缘检测,我使用了 Canny 边缘检测。 Then, I use Hough Transform to extract lines.然后,我使用霍夫变换来提取线条。

This is the original image enter image description here这是原始图像在此处输入图像描述

This is the result image enter image description here这是结果图像在此处输入图像描述

My problem is that I can't draw a bounding box to the detected area.我的问题是我无法在检测到的区域绘制边界框。 It seems that my program can only detect a single horizontal line.看来我的程序只能检测到一条水平线。 How can I detect rectangle shape and draw rectangle line to the detected shape?如何检测矩形形状并将矩形线绘制到检测到的形状上?

I've read similar problems and it is required to find the 4 corner points of the rectangle, check if the point is 90 degree, and find the intersection.我看过类似的问题,需要找到矩形的4个角点,检查点是否为90度,并找到交点。 I'm really confused how to code it in Java opencv.我真的很困惑如何在 Java opencv 中对其进行编码。 Other methods to detect the shape and draw bounding box to the detected would be okay too.其他检测形状并将边界框绘制到检测到的方法也可以。

Here's the code这是代码

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.*;
import org.opencv.imgproc.Imgproc;

public class HoughTransformCV2 {

    public static void main(String[] args) {
        try {
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
            Mat source = Imgcodecs.imread("rectangle.jpg", Imgcodecs.CV_LOAD_IMAGE_ANYCOLOR);
            Mat destination = new Mat(source.rows(), source.cols(), source.type());

            Imgproc.cvtColor(source, destination, Imgproc.COLOR_RGB2GRAY);
            Imgproc.equalizeHist(destination, destination);
            Imgproc.GaussianBlur(destination, destination, new Size(5, 5), 0, 0, Core.BORDER_DEFAULT);

            Imgproc.Canny(destination, destination, 50, 100);
            //Imgproc.adaptiveThreshold(destination, destination, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 15, 40);
            Imgproc.threshold(destination, destination, 0, 255, Imgproc.THRESH_BINARY);

            if (destination != null) {
                Mat lines = new Mat();
                Imgproc.HoughLinesP(destination, lines, 1, Math.PI / 180, 50, 30, 10);
                Mat houghLines = new Mat();
                houghLines.create(destination.rows(), destination.cols(), CvType.CV_8UC1);

                //Drawing lines on the image
                for (int i = 0; i < lines.cols(); i++) {
                    double[] points = lines.get(0, i);
                    double x1, y1, x2, y2;
                    x1 = points[0];
                    y1 = points[1];
                    x2 = points[2];
                    y2 = points[3];

                    Point pt1 = new Point(x1, y1);
                    Point pt2 = new Point(x2, y2);

                    //Drawing lines on an image
                    Imgproc.line(source, pt1, pt2, new Scalar(0, 0, 255), 4);
                }

            }

            Imgcodecs.imwrite("rectangle_houghtransform.jpg", source);

        } catch (Exception e) {
            System.out.println("error: " + e.getMessage());
        }
    }
}

Any help in Java would be appreciated :) Thank you very much!任何 Java 方面的帮助将不胜感激:) 非常感谢!

You can do this in these steps:您可以通过以下步骤执行此操作:

  1. After you did the converting color to gray, perform a canny edge.将颜色转换为灰色后,执行精巧的边缘。

    int threshold = 100; int 阈值 = 100;

    Imgproc.Canny(grayImage, edges, threshold, threshold*3); Imgproc.Canny(grayImage,edges, threshold, threshold*3);

  2. Now find the contours in edge image.现在找到边缘图像中的轮廓。

Imgproc.findContours(edges, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

  1. Then loop on all over the contours然后在整个轮廓上循环

..... .....

MatOfPoint2f matOfPoint2f = new MatOfPoint2f();
MatOfPoint2f approxCurve = new MatOfPoint2f();

for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0]) {
    MatOfPoint contour = contours.get(idx);
    Rect rect = Imgproc.boundingRect(contour);
    double contourArea = Imgproc.contourArea(contour);
    matOfPoint2f.fromList(contour.toList());
    Imgproc.approxPolyDP(matOfPoint2f, approxCurve, Imgproc.arcLength(matOfPoint2f, true) * 0.02, true);
    long total = approxCurve.total();
    if (total == 3) { // is triangle
        // do things for triangle
    }
    if (total >= 4 && total <= 6) {
        List<Double> cos = new ArrayList<>();
        Point[] points = approxCurve.toArray();
        for (int j = 2; j < total + 1; j++) {
            cos.add(angle(points[(int) (j % total)], points[j - 2], points[j - 1]));
        }
        Collections.sort(cos);
        Double minCos = cos.get(0);
        Double maxCos = cos.get(cos.size() - 1);
        boolean isRect = total == 4 && minCos >= -0.1 && maxCos <= 0.3;
        boolean isPolygon = (total == 5 && minCos >= -0.34 && maxCos <= -0.27) || (total == 6 && minCos >= -0.55 && maxCos <= -0.45);
        if (isRect) {
            double ratio = Math.abs(1 - (double) rect.width / rect.height);
            drawText(rect.tl(), ratio <= 0.02 ? "SQU" : "RECT");
        }
        if (isPolygon) {
            drawText(rect.tl(), "Polygon");
        }
    }
}

Helper methods:辅助方法:

private double angle(Point pt1, Point pt2, Point pt0) {
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

private void drawText(Point ofs, String text) {
    Imgproc.putText(colorImage, text, ofs, Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(255,255,25));
}

Hope this can help you!!希望这能帮到你!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM