说在前面
- opencv版本:4.0.1
- 操作系统:win10
- vs版本:2017
- 官方文档:Harris corner detector
- 参考:wikipedia-Harris corner detector
- 其他说明:自学,记录,demo
Theory
- 对于某个像素(x, y),定义一个窗口W
- 对于该窗口中的每一个像素,计算其在偏移量为
(
Δ
x
,
Δ
y
)
(\Delta x, \Delta y)
(Δx,Δy)时,像素值之间的完全平方差:
[ I ( x + Δ x , y + Δ y ) − I ( x , y ) ] 2 [ I(x+\Delta x,y+\Delta y) - I(x,y)]^{2} [I(x+Δx,y+Δy)−I(x,y)]2 - 对这些值进行求和
∑ x , y [ I ( x + Δ x , y + Δ y ) − I ( x , y ) ] 2 \sum _{x,y}[ I(x+\Delta x,y+\Delta y) - I(x,y)]^{2} x,y∑[I(x+Δx,y+Δy)−I(x,y)]2 - 对
I
(
x
+
Δ
x
,
y
+
Δ
y
)
I(x+\Delta x,y+\Delta y)
I(x+Δx,y+Δy)使用泰勒展开
I ( x + Δ x , y + Δ y ) ≈ I ( x , y ) + I x ( x , y ) Δ x + + I y ( x , y ) Δ y I(x+\Delta x,y+\Delta y)\approx I(x,y) + I_x(x,y)\Delta x + + I_y(x,y)\Delta y I(x+Δx,y+Δy)≈I(x,y)+Ix(x,y)Δx++Iy(x,y)Δy
则
∑ x , y [ I x ( x , y ) Δ x + + I y ( x , y ) Δ y ] 2 \sum _{x,y}[ I_x(x,y)\Delta x + + I_y(x,y)\Delta y]^{2} x,y∑[Ix(x,y)Δx++Iy(x,y)Δy]2
其中 I x ( x , y ) I_x(x,y) Ix(x,y)、 I y ( x , y ) I_y(x,y) Iy(x,y)分别为 I ( x , y ) I(x,y) I(x,y)对x、y的偏微分(这个偏微分是将像素值作为z轴构成的三维图)
- 转换为矩阵形式
[ Δ x Δ y ] ( ∑ x , y [ I x 2 I x I y I x I y I y 2 ] ) [ Δ x Δ y ] \begin{bmatrix} \Delta x & \Delta y \end{bmatrix} \left ( \displaystyle \sum_{x,y} \begin{bmatrix} I_x^{2} & I_{x}I_{y} \\ I_xI_{y} & I_{y}^{2} \end{bmatrix} \right ) \begin{bmatrix} \Delta x \\ \Delta y \end{bmatrix} [ΔxΔy](x,y∑[Ix2IxIyIxIyIy2])[ΔxΔy] - 令
M = ∑ x , y [ I x 2 I x I y I x I y I y 2 ] = [ ∑ x , y I x 2 ∑ x , y I x I y ∑ x , y I x I y ∑ x , y I y 2 ] {\displaystyle M={\underset {x,y}{\sum }}{\begin{bmatrix}I_{x}^{2}&I_{x}I_{y}\\I_{x}I_{y}&I_{y}^{2}\end{bmatrix}}={\begin{bmatrix}{\underset {x,y}{\sum }}I_{x}^{2}&{\underset {x,y}{\sum }}I_{x}I_{y}\\{\underset {x,y}{\sum }}I_{x}I_{y}&{\underset {x,y}{\sum }}I_{y}^{2}\end{bmatrix}}} M=x,y∑[Ix2IxIyIxIyIy2]=⎣⎡x,y∑Ix2x,y∑IxIyx,y∑IxIyx,y∑Iy2⎦⎤
M就是该窗口W的一个梯度协方差矩阵 - 最后计算矩阵M的一个特定的值R
R = d e t ( M ) − k ( t r a c e ( M ) ) 2 R = det(M) - k(trace(M))^{2} R=det(M)−k(trace(M))2
其中 d e t ( M ) det(M) det(M)为矩阵M的行列式值, t r a c e ( M ) trace(M) trace(M)为矩阵M的迹, k k k是由经验得出来的值(通常为0.04-0.06) - 设置一个阈值S,只要R大于S,就表明点(x,y)为角点。
Code
- 代码比较简单
int blockSize = 2;//相当于窗口大小2x2 int apertureSize = 3;//Sobel算子的参数 double k = 0.04; Mat dst = Mat::zeros( src.size(), CV_32FC1 ); //角点检测 cornerHarris( src_gray, dst, blockSize, apertureSize, k ); Mat dst_norm, dst_norm_scaled; //将值归一化至0-255f normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); //计算绝对值并转为u8bit数据(CV_U8),便于显示 convertScaleAbs( dst_norm, dst_norm_scaled ); for( int i = 0; i < dst_norm.rows ; i++ ) { for( int j = 0; j < dst_norm.cols; j++ ) { //阈值 if( (int) dst_norm.at<float>(i,j) > thresh ) { //画个圈圈 circle( dst_norm_scaled, Point(j,i), 5, Scalar(0), 2, 8, 0 ); } } }
Result
- emmmm