如何从OpenCV C ++的HoughLines函数输出中绘制所需的线?

时间:2018-08-11 04:40:13

标签: c++ opencv line draw houghlines

上下文:

lecture中的第8页说,OpenCV HoughLines函数返回N x 2的行参数 rho theta 数组。存储在名为 lines 的数组中。

然后为了从这些角度实际创建线,我们有一些公式,后来我们使用了 line 函数。公式在下面的代码中进行了解释。

代码:

    //Assuming we start our program with the Input Image as shown below.
    //This array will be used for storing rho and theta as N x 2 array

    vector<Vec2f> lines; 

    //The input bw_roi is a canny image with detected edges
    HoughLines(bw_roi, lines, 1, CV_PI/180, 70, 0, 0); '

    //These formulae below do the line estimation based on rho and theta

    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point2d pt1, pt2;
        double m;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;

        //When we use 1000 below we get Observation 1 output. 
        //But if we use 200, we get Observation 2 output.

        pt1.x = cvRound(x0 + 1000*(-b)); 
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));

        //This line function is independent of HoughLines function    
        //and is used for drawing any type of line in OpenCV

        line(frame, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);
     }

输入图像:

enter image description here

观察1:

enter image description here

观察2:

enter image description here

问题:

在上面显示的代码中,如果我们使用数字乘以a,-a,b和-b,则会得到不同长度的行。当我乘以200而不是1000时获得观察值2(得出观察值1)。

有关更多信息,请参见上面显示的代码的第18和19行中的注释。

问题:

当我们从HoughLines输出中绘制线条时,如何控制线条的起点和终点?

例如,我希望观察2中的右车道(红线从左上角指向右下角)从屏幕的右下角开始并指向屏幕的左上角(例如左车道)。

1 个答案:

答案 0 :(得分:2)

给予

import lombok.val;
import org.opencv.core.*;
import org.springframework.core.io.ClassPathResource;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import static javax.imageio.ImageIO.read;
import static javax.imageio.ImageIO.write;
import static javax.swing.SwingUtilities.invokeAndWait;
import static org.opencv.core.CvType.CV_32FC1;
import static org.opencv.highgui.HighGui.imshow;
import static org.opencv.highgui.HighGui.waitKey;
import static org.opencv.imgcodecs.Imgcodecs.CV_LOAD_IMAGE_UNCHANGED;
import static org.opencv.imgcodecs.Imgcodecs.imdecode;
import static org.opencv.imgproc.Imgproc.*;

public class TemplateMatcher
{
    static
    {
        // loadNativeOpenCVLibrary();
    }

    private static final int MATCH_METHOD = TM_SQDIFF_NORMED;

    private static Mat BufferedImage2Mat(BufferedImage image) throws IOException
    {
        try (val byteArrayOutputStream = new ByteArrayOutputStream())
        {
            write(image, "jpg", byteArrayOutputStream);
            byteArrayOutputStream.flush();
            val matOfByte = new MatOfByte(byteArrayOutputStream.toByteArray());
            return imdecode(matOfByte, CV_LOAD_IMAGE_UNCHANGED);
        }
    }

    public static Point performTemplateMatching(BufferedImage bigImage, BufferedImage templateImage,
                                                double detectionThreshold, boolean showMatch) throws IOException
    {
        val image = BufferedImage2Mat(bigImage);
        val template = BufferedImage2Mat(templateImage);

        // Create the result matrix
        val result_cols = image.cols() - template.cols() + 1;
        val result_rows = image.rows() - template.rows() + 1;
        val result = new Mat(result_rows, result_cols, CV_32FC1);

        // Do the matching
        matchTemplate(image, template, result, MATCH_METHOD);

        // Localize the best match
        val minMaxLocResult = Core.minMaxLoc(result);

        // / Show me what you got
        val matchedLocation = minMaxLocResult.minLoc;
        rectangle(image, matchedLocation, new Point(matchedLocation.x + template.cols(),
                matchedLocation.y + template.rows()), new Scalar(0, 255, 0));

        if (showMatch)
        {
            try
            {
                invokeAndWait(() -> imshow("Image Search", image));
            } catch (InterruptedException | InvocationTargetException exception)
            {
                exception.printStackTrace();
            }
            waitKey();
        }

        // Determine whether this sub image has been found
        val minVal = minMaxLocResult.minVal;
        if (minVal < detectionThreshold)
        {
            return minMaxLocResult.maxLoc;
        }

        return null;
    }

    public static BufferedImage getBufferedImage(String classpathFile) throws IOException
    {
        val classPathResource = new ClassPathResource(classpathFile);
        val filePath = classPathResource.getFile();
        return read(filePath);
    }
}

您可以为data(){ cats:[], ... }, beforeMount(){ axios.get(`${process.env.KITTY_URL}/api/v1/cats/`) .then(response => { self.cats = response.data.results; <----What should this be? }) .catch(error => console.log(error)); }, mounted () { console.log(this.cats); } 定义的直线上的所有点编写公式,

a = cos(theta)
b = sin(theta)

x0 = a * rho
y0 = b * rho

其中(rho, theta)是距参考点的距离(与通过原点的垂直线相交)。

在您的情况下,您已经用x = x0 - c * b y = y0 + c * a c对其进行了评估,得到了两个要点。

您可以将其重写为

c = 1000

然后使用替代计算水平和垂直截距:

c = -1000

c = (x0 - x) / b
c = (y - y0) / a

注意::请注意正确处理x = x0 - ((y - y0) / a) * b y = y0 + ((x0 - x) / b) * a 为0的情况。


假设您有一个800x600的图片(使数字保持简单)。我们可以将图像的底部边缘定义为a行。使用上面的公式计算b的值,您的行将其截取。

  • 如果截取点位于图像(y = 599)中,那就是您的起点。
  • 如果位于左边(x)处,则找到第0 <= x < 800行的截距作为起点。
  • 如果它在右边(x < 0),则找到第x = 0行的截距作为起点。

然后使用类似的技术找到能够画线的第二点。

相关问题