摘要
角点在三维场景重建运动估计,目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。在现实世界中,角点对应于物体的拐角,道路的十字路口、丁字路口等。在近几个项目中,通过获取的角点,多用于透视变换。
一、哈尔角点检测
1. 原理
根据角点的定义,可以分为如下两类:
角点可以是两个边缘的角点,邻域内具有两个主方向的特征点。前者很大程度上依赖于图像的分割与边缘提取,具有相当大的难度和计算量。 第二种如Harris角点的检测。如果在各个方向上移动这个widow,
区域内的灰度发生较大的变化,就认为遇到了角点。
2. 公式推导
周围灰度变化的自相关函数如下:
进行泰勒展开如下,其中Ο(u2,v2)近似为0:
矩阵M又称Harris矩阵:
在不同方向的展示如下:
a. 图像中的直线。一个特征值大,另一个特征值小,λ1>λ2或λ2>λ1。自相关函数值在某一方向上大,在其他方向上小。
b. 图像中的平面。两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
c. 图像中的角点。两个特征值都大,且近似相等,自相关函数在所有方向都增大。
3. 存在问题
实际的烟盒不完全是直角,导致角点检测出现偏离。
二、拟合外接矩形求角点
相机拍摄的图像如下所示,在绿框中寻找角点的位置。
1. 钝角
先求出初始的外接矩形,如下所示。
再在该初始的外接矩形进行图像的取反,再次进行外接矩形的拟合,输出对应位置的矩形点。
2. 直角
寻找最小外接矩形,进行角点的排序,从而求得对应位置的角定。
3. 锐角
用findRect在二值化的cornerRoi图像上求外接矩形,再对该矩形的四个点进行排序,烟盒左下方的角点是对应拟合矩形的左下方角点,烟盒右下方的角点是对应拟合矩形的右下方角点。
三、检测例子
1. 获取轮廓,求外接矩形。
#近似边缘求角点point
def getSubCornerPoint(binImg, posFlag):
#寻找近似的轮廓
resContourFlag, approxContour = findApproxContour(binImg, posFlag)
if resContourFlag ==False:
return False, [], []
#轮廓的外接矩形
boxPoints = getBoundRect(approxContour)
#角点排序
sortBoxPoints = sortPoints(boxReverPoints)
#获取对应位置的point
resPoint = getPosSortPoint(sortBoxPoints, posFlag)
#寻找近似的轮廓
def findApproxContour(binImg, posFlag):
allContours, _ = cv2.findContours(binImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(allContours) ==0:
print("@ error findApproxContour not find the contour pos: ", posFlag)
return False, []
#计算轮廓面积,将最大的那组轮廓挑出来
contour = sorted(allContours, key=cv2.contourArea, reverse=True)[0]
lengthEps = 0.015 #轮廓边长的近似
contourMinArea = (binImg.shape[0])*(binImg.shape[1])*fourCornerBinImgRation
contourArea = cv2.contourArea(contour)
if (contourArea > contourMinArea):
epsilon = lengthEps * cv2.arcLength(contour, True) #精度的近似
approx = cv2.approxPolyDP(contour, epsilon, True) #轮廓的近似
return True, approx
else:
print("@ failed findApproxContour not ok area contour pos: ", posFlag)
return False, []
#轮廓求外接矩形 返回tl, tr, bl, br
def getBoundRect(approxContour):
x,y,w,h = cv2.boundingRect(approxContour) #外接矩形
boxPoints = np.array([[x, y], [x+w, y], [x, y+h], [x+w, y+h]])
return boxPoints
2. 角点的排序
#位置点的排序 tl, tr, bl, br
def sortPoints(pts):
xSorted = pts[np.argsort(pts[:, 0]), :]
leftMost = xSorted[:2,:]
rightMost = xSorted[2:,:]
leftMost = leftMost[np.argsort(leftMost[:, 1]),:] #np.argsort返回坐标的index
(tl, bl) = leftMost
rightMost = rightMost[np.argsort(rightMost[:, 1]), :]#y坐标偏上的是top
(tr, br) = rightMost
return np.array([tl, tr, bl, br], dtype=int)
总结
自带的角点检测方法,稳定行不高。可以采用外接矩形的求对应位置的角点。