【问题标题】:Accurate corners detection?准确的角点检测?
【发布时间】:2020-06-06 21:45:21
【问题描述】:

我有这个微不足道的参考图像(其他人在白色部分有物体),我想检测四个角来修复透视图。我尝试了几种策略:

  1. 等高线 + Houghlines + 线的交点

此策略不起作用,因为未正确找到霍夫线。白色矩形有轻微的桶形变形,线条不直,所以我为每个边缘找到了多条线。

  1. 轮廓 + goodFeaturesToTrack

这看起来很有希望,但是 cv.goodFeaturesToTrack(u, 4, 0.5, 50) 的角只在两个底角上找到

还有其他方法可以准确检测出这个矩形的四个角吗?

【问题讨论】:

标签: opencv


【解决方案1】:

在您的图像中,矩形似乎是检测其轮廓的合适矩形。所以适合这个轮廓的矩形可以解决这个问题。我的方法是使用minAreaRect函数:

这是我的代码:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;


int main()
{

    Mat src; Mat src_gray;
    int thresh = 100;
    src = imread( "/ur/image/directory/image.png", 1 );
    Mat source = src.clone();
    cvtColor( src, src_gray, CV_BGR2GRAY );

    Mat threshold_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
    findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

    vector<RotatedRect> minRect( contours.size() );

    for( int i = 0; i < contours.size(); i++ )
        minRect[i] = minAreaRect( Mat(contours[i]) );

    for( int i = 0; i< contours.size(); i++ )
    {

        Point2f rect_points[4]; minRect[i].points( rect_points );
        for( int j = 0; j < 4; j++ )
        {
            circle(source,rect_points[j],10,Scalar(255,255,0),2);
            line( source, rect_points[j], rect_points[(j+1)%4], Scalar(0,255,0), 2, 8 );
        }
    }

    imshow("output",source);

    waitKey(0);
    return(0);
}

结果:

【讨论】:

  • 你的方法很好。它仅在假设这是一个矩形的情况下准确检测角。不幸的是,有时我有一些视角扭曲,minAreaRect 不是正确的解决方案。
  • 是的,因为我假设它是矩形 :)。您可能需要共享一个示例图像才能看到什么样的失真。
【解决方案2】:

基于 Python 的解决方案类似于 Yunus Temurlenk 的回答。首先应用 Otsu 阈值处理、canny 边缘检测和膨胀以获得良好的轮廓。接下来,按面积提取最大轮廓,基于最小面积矩形提取四个点。

此代码在此图像中没有dilation 步骤也可以工作。在这种情况下,轮廓将更紧密地适合矩形。

代码:

## Press ESC button to get next image

import cv2
import cv2 as cv
import numpy as np



#frame = cv2.imread('resources/pstr1.png')
frame = cv2.imread('resources/pstr2.png')


## keeping a copy of original
print(frame.shape)
original_frame = frame.copy()




## Show the original image
winName = 'Original'
cv.namedWindow(winName, cv.WINDOW_NORMAL)
cv.resizeWindow(winName, 800, 800)
cv.imshow(winName, original_frame)
cv.waitKey(0)



# Otsu's thresholding
grayimg = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret2,thresh_n = cv.threshold(grayimg,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
thresh_n = cv2.cvtColor(thresh_n, cv2.COLOR_GRAY2BGR)
frame = thresh_n


## edge detection
frame = cv2.Canny(frame,100,200)


## dilate the edges
kernel = np.ones((5,5),np.uint8)
frame = cv2.dilate(frame,kernel,iterations = 1)




## Get largest contour from contours
contours, hierarchy = cv2.findContours(frame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)



## Get minimum area rectangle and corner points
rect = cv2.minAreaRect(max(contours, key = cv2.contourArea))
box = cv2.boxPoints(rect)
print(box)




## draw anchor points on corner
z = 6
for b in box:
    cv2.circle(original_frame, tuple(b), z, 255, -1)



## show original image with corners
box2 = np.int0(box)
cv2.drawContours(original_frame,[box2],0,(0,0,255), 2)
cv2.imshow('Detected Corners',original_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

输入图像:

输出图像:

【讨论】:

  • 你为什么要加膨胀?
  • 这里不需要。我只是添加它以在矩形周围获得松散配合,并在检测到的边缘之间存在微小间隙的情况下连接边缘。
猜你喜欢
  • 2022-01-17
  • 2014-08-20
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 2014-01-31
  • 1970-01-01
  • 2022-12-25
相关资源
最近更新 更多