1 Harris corner demo
opencv_tutorials.pdf中的例子:
/**
* @function cornerHarris_Demo.cpp
* @brief Demo code for detecting corners using Harris-Stephens method
* @author OpenCV team
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
/// Global variables
Mat src, src_gray;
int thresh = 124;
int max_thresh = 255;
const char* filename = "Sydney_opera_house.jpg";
const char* source_window = "Source image";
const char* corners_window = "Corners detected";
cv::RNG rng(12345);
/// Function header
void cornerHarris_demo(int, void*);
/**
* @function main
*/
int main(int, char** argv)
{
/// Load source image and convert it to gray
src = imread(filename, CV_LOAD_IMAGE_ANYCOLOR);
if (src.empty()){
cout << "Can't load the image." << endl;
return -1;
}
if (src.channels() == 3){
cvtColor(src, src_gray, COLOR_BGR2GRAY);
}
else{
src_gray = src.clone();
}
/// Create a window and a trackbar
namedWindow(source_window, WINDOW_AUTOSIZE);
createTrackbar("Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo);
imshow(source_window, src_gray);
cornerHarris_demo(0, 0);
waitKey(0);
return(0);
}
/**
* @function cornerHarris_demo
* @brief Executes the corner detection and draw a circle around the possible corners
*/
void cornerHarris_demo(int, void*)
{
Mat dst, dst_norm, dst_norm_scaled;
dst = Mat::zeros(src.size(), CV_32FC1);
/// Detector parameters
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
/// Detecting corners
cornerHarris(src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT);
/// Normalizing
normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(dst_norm, dst_norm_scaled);
cv::Mat drawing;
src.copyTo(drawing);
/// Drawing a circle around corners
for (int j = 0; j < dst_norm.rows; j++)
{
for (int i = 0; i < dst_norm.cols; i++)
{
if ((int)dst_norm.at<float>(j, i) > thresh)
{
circle(drawing, Point(i, j), 4, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255), 255)
, 2, 8, 0);
}
}
}
/// Showing the result
namedWindow(corners_window, WINDOW_AUTOSIZE);
imshow(corners_window, drawing);
//imwrite("corner.png", drawing);
}
检测效果图:
2 Harris corner detection(source code analysis in OpenCV )
关于Harris角点检测的具体内容可以参考: Corner detection(Wikipedia)、Harris角点检测原理与流程.ppt,主要分析Harris 角点检测在OpenCV中是如何实现的:
Step 1
Harris 角点检测接口cornerHarris()
:
void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType )
{
Mat src = _src.getMat();
_dst.create( src.size(), CV_32F );
Mat dst = _dst.getMat();
cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType );
}
Step 2
OpenCV 内部调用cornerEigenValsVecs()
实现Harris焦点检测:
static void
cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size,
int aperture_size, int op_type, double k=0.,
int borderType=BORDER_DEFAULT )
{
#ifdef HAVE_TEGRA_OPTIMIZATION
if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType))
return;
#endif
int depth = src.depth();
double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;
if( aperture_size < 0 )
scale *= 2.;
if( depth == CV_8U )
scale *= 255.;
scale = 1./scale;
CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
Mat Dx, Dy;
if( aperture_size > 0 )
{
Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType );
Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType );
}
else
{
Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType );
Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType );
}
Size size = src.size();
Mat cov( size, CV_32FC3 );
int i, j;
for( i = 0; i < size.height; i++ )
{
float* cov_data = (float*)(cov.data + i*cov.step);
const float* dxdata = (const float*)(Dx.data + i*Dx.step);
const float* dydata = (const float*)(Dy.data + i*Dy.step);
for( j = 0; j < size.width; j++ )
{
float dx = dxdata[j];
float dy = dydata[j];
cov_data[j*3] = dx*dx;
cov_data[j*3+1] = dx*dy;
cov_data[j*3+2] = dy*dy;
}
}
boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),
Point(-1,-1), false, borderType );
if( op_type == MINEIGENVAL )
calcMinEigenVal( cov, eigenv );
else if( op_type == HARRIS )
calcHarris( cov, eigenv, k );
else if( op_type == EIGENVALSVECS )
calcEigenValsVecs( cov, eigenv );
}
}
这一部分通过Sobel
算子计算得到在每个像素点处的x/y
方向的梯度,并将x/y
处的偏导数保存在与原图size
相同,但depth = 3
的矩阵cov
中,最后调用calcHarris()
对cov
进行处理。
Step 3
static void
calcHarris( const Mat& _cov, Mat& _dst, double k )
{
int i, j;
Size size = _cov.size();
if( _cov.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const float* cov = (const float*)(_cov.data + _cov.step*i);
float* dst = (float*)(_dst.data + _dst.step*i);
j = 0;
for( ; j < size.width; j++ )
{
float a = cov[j*3];
float b = cov[j*3+1];
float c = cov[j*3+2];
dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
}
}
}
计算了Harris角点检测原理与流程.ppt中每个像素的角点响应函数:
其中
Step 2
计算:
NOTE: Source code path: D:\opencv\sources\modules\imgproc\src\corner.cpp