如何使用OpenCv在图像上找到角落
image-processing
opencv
4
0

我正在尝试查找图像上的角,我不需要轮廓,只需要4个角。我将使用4个角更改视角。

我正在使用Opencv,但是我需要知道查找拐角的步骤以及将使用的功能。

我的图像将是这样的:(没有红色点,以后我会画点) 在此处输入图片说明

编辑:

按照建议的步骤操作后,我编写了代码:(注意:我不是使用纯OpenCv,而是使用javaCV,但是逻辑上是相同的)。

// Load two images and allocate other structures (I´m using other image)
    IplImage colored = cvLoadImage(
            "res/scanteste.jpg",
            CV_LOAD_IMAGE_UNCHANGED);

在此处输入图片说明

    IplImage gray = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);
    IplImage smooth = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);

    //Step 1 - Convert from RGB to grayscale (cvCvtColor)
    cvCvtColor(colored, gray, CV_RGB2GRAY);

在此处输入图片说明

    //2 Smooth (cvSmooth)
    cvSmooth( gray, smooth, CV_BLUR, 9, 9, 2, 2); 

在此处输入图片说明

    //3 - cvThreshold  - What values?
    cvThreshold(gray,gray, 155, 255, CV_THRESH_BINARY);

在此处输入图片说明

    //4 - Detect edges (cvCanny) -What values?
    int N = 7;
    int aperature_size = N;
    double lowThresh = 20;
    double highThresh = 40;     
    cvCanny( gray, gray, lowThresh*N*N, highThresh*N*N, aperature_size );   

在此处输入图片说明

    //5 - Find contours (cvFindContours)
    int total = 0;
    CvSeq contour2 = new CvSeq(null);
    CvMemStorage storage2 = cvCreateMemStorage(0);
    CvMemStorage storageHull = cvCreateMemStorage(0);
    total = cvFindContours(gray, storage2, contour2, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
    if(total > 1){
          while (contour2 != null && !contour2.isNull()) {
              if (contour2.elem_size() > 0) {
                //6 - Approximate contours with linear features (cvApproxPoly)
                  CvSeq points = cvApproxPoly(contour2,Loader.sizeof(CvContour.class), storage2, CV_POLY_APPROX_DP,cvContourPerimeter(contour2)*0.005, 0);
                  cvDrawContours(gray, points,CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);

              }
              contour2 = contour2.h_next();
          }

    } 

在此处输入图片说明

因此,我想找到角落,但是我不知道如何使用cvCornerHarris等拐角功能。

参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

首先,在您的OpenCV发行版中查看/samples/c/squares.c。此示例提供了一个正方形检测器,这对于如何检测类似拐角的特征应该是一个很好的开始。然后,看看OpenCV的面向功能的函数,例如cvCornerHarris()和cvGoodFeaturesToTrack()。

上面的方法可以返回许多类似拐角的特征-大多数不会是您要查找的“真拐角”。在我的应用程序中,我必须检测到旋转或倾斜的正方形(由于透视)。我的检测管道包括:

  1. 从RGB转换为灰度(cvCvtColor)
  2. 平滑(cvSmooth)
  3. 阈值(cvThreshold)
  4. 检测边缘(cvCanny)
  5. 查找轮廓(cvFindContours)
  6. 具有线性特征的近似轮廓(cvApproxPoly)
  7. 找到具有以下特征的“矩形”:具有4个点的多边形轮廓,具有足够的面积,相邻的边缘约为90度,“相对”的顶点之间的距离具有足够的大小,等等。

步骤7是必需的,因为略微嘈杂的图像可能会产生许多在多边形化后显示为矩形的结构。在我的应用程序中,我还必须处理出现在所需正方形内或与所需正方形重叠的正方形结构。我发现轮廓的面积属性和重心有助于识别适当的矩形。

收藏
评论

乍看之下,人眼有4个角。但是在计算机视觉中,拐角被认为是在其整个邻域中强度梯度变化较大的点。邻域可以是4像素邻域或8像素邻域。

在此处输入图片说明

在提供的用于找到强度梯度的方程式中,已考虑将其用于4像素邻域SEE DOCUMENTATION

这是我要处理的图像的方法。我也有python中的代码:

path = r'C:\Users\selwyn77\Desktop\Stack\corner'
filename = 'env.jpg'

img = cv2.imread(os.path.join(path, filename))
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)    #--- convert to grayscale 

始终模糊图像以消除可能的渐变变化并保留更强烈的渐变是一个不错的选择。我选择选择双边滤波器 ,该滤波器与高斯滤波器不同,它不会模糊附近的所有像素。而是模糊具有与中心像素相似的像素强度的像素。简而言之,它保留了高梯度变化的边缘/角,但模糊了具有最小梯度变化的区域。

bi = cv2.bilateralFilter(gray, 5, 75, 75)
cv2.imshow('bi',bi)

在此处输入图片说明

对于人类而言,与原始图像相比并没有太大的区别。但这很重要。现在找到可能的角落:

dst = cv2.cornerHarris(bi, 2, 3, 0.04)

dst返回一个数组(图像的2D形状相同),该数组具有从此处提到的最终方程式获得的特征值。

现在必须应用阈值来选择那些超出特定值的角。我将在文档中使用一个:

#--- create a black image to see where those corners occur ---
mask = np.zeros_like(gray)

#--- applying a threshold and turning those pixels above the threshold to white ---           
mask[dst>0.01*dst.max()] = 255
cv2.imshow('mask', mask)

在此处输入图片说明

白色像素是可能的角区域。您会发现彼此相邻的许多角。

要在图像上绘制选定的角:

img[dst > 0.01 * dst.max()] = [0, 0, 255]   #--- [0, 0, 255] --> Red ---
cv2.imshow('dst', img)

在此处输入图片说明

(红色像素是角落,不太明显)

为了得到带有角的所有像素的数组:

coordinates = np.argwhere(mask)

更新

变量coor是一个数组数组。将其转换为列表列表

coor_list = [l.tolist() for l in list(coor)]

将上面的转换为元组列表

coor_tuples = [tuple(l) for l in coor_list]

我有一种简单而又幼稚的方法来找到4个角。我只是简单地计算了每个角到另一个角的距离。我保留了距离超过一定阈值的那些角。

这是代码:

thresh = 50

def distance(pt1, pt2):
    (x1, y1), (x2, y2) = pt1, pt2
    dist = math.sqrt( (x2 - x1)**2 + (y2 - y1)**2 )
    return dist

coor_tuples_copy = coor_tuples

i = 1    
for pt1 in coor_tuples:

    print(' I :', i)
    for pt2 in coor_tuples[i::1]:
        print(pt1, pt2)
        print('Distance :', distance(pt1, pt2))
        if(distance(pt1, pt2) < thresh):
            coor_tuples_copy.remove(pt2)      
    i+=1

在运行片段之前, coor_tuples具有所有拐角点: [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)] coor_tuples [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)]

运行代码段后,我剩下了四个角:

[(4, 42), (7, 219), (133, 36), (135, 224)]

更新2

现在您所要做的只是在原始图像的副本上标记这4个点。

img2 = img.copy()
for pt in coor_tuples:
    cv2.circle(img2, tuple(reversed(pt)), 3, (0, 0, 255), -1)
cv2.imshow('Image with 4 corners', img2) 

在此处输入图片说明

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号