相机矫正中常用到角点或径向鞍点的亚像素精确位置: cornerSubPix,典型用法如下:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
found, corners = cv2.findChessboardCorners(
gray,
grid_size,
cv2.CALIB_CB_ADAPTIVE_THRESH +
cv2.CALIB_CB_NORMALIZE_IMAGE +
cv2.CALIB_CB_FILTER_QUADS
)
if found:
term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.01)
cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), term)
cv2.drawChessboardCorners(img, grid_size, corners, found)
cornerSubPix opencv cornerSubPix说明
void cv::cornerSubPix ( InputArray image,
InputOutputArray corners,
Size winSize,
Size zeroZone,
TermCriteria criteria
)
Python:
cv.cornerSubPix( image, corners, winSize, zeroZone, criteria ) -> corners
其原理来自于:
W FORSTNER. A fast operator for detection and precise location of distincs points, corners and center of circular features
亚像素精确角点定位器基于,观察到从中心 q 到位于 q 邻域内的点 p 的每个向量都与 p 处的图像梯度正交,并受到图像和测量噪声的影响。
其其中Dipi是q领域内点pi点处的图像梯度。因此需要找到一个q点,从而使ϵi最小。
其中梯度为q邻域内像素的梯度和。
该算法将邻域窗口的中心设置在这个新的中心 q 处,然后迭代直到中心保持在设定的阈值内。
疑问:
邻域内所有像素的梯度累加是否合理?
要求:
(1)image 为单通道
(2)corner 要求N12 或N*2
(3)corner 值要求float32 不能为double
封装:
将该函数做一定的封装,如下:
def findCornerSubPix(gray,corner):
corner = corner.astype(np.float32)
corner=corner.copy()
if gray.ndim==3:
gray = cv2.cvtColor(gray,cv2.COLOR_BGR2GRAY)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corner2 = cv2.cornerSubPix(gray,corner,(8,8),(-1,-1),criteria)
return corner2
报错1:
cv2.error: OpenCV(4.6.0) /io/opencv/modules/imgproc/src/cornersubpix.cpp:58: error: (-215:Assertion failed) count >= 0 in function 'cornerSubPix'
解决方案: corner 值要求float32 不能为double