cornerHarris角点检测综合示例
视频讲解如下:
源码下载:https://download.csdn.net/download/gs1069405343/85543540
在本章节中给大家演示cornerHarris角点检测的一个综合示例,主要函数:cornerHarris。
当前代码同样是在毛星云的代码基础上进行扩展优化的。
这里要注意一下,OpenCvSharp3-AnyCPU 版本找不到 CornerHarris 方法,所以必须采用OpenCvSharp4 版本才行。
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
首先呢,我们需要准备一张测试图片。(不想下载工程的童鞋,可直接复制下面的图片和代码)

运行效果如下(C#):

C#版本代码如下:
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
using OpenCvSharp;
using System;
namespace demo
{
internal class Program
{
static string WINDOW_NAME1 = "【程序窗口1】";
static string WINDOW_NAME2 = "【程序窗口2】";
static Mat g_srcImage = new Mat();
static Mat g_srcImage1 = new Mat();
static Mat g_grayImage = new Mat();
static int thresh = 30; //当前阈值
static int max_thresh = 175; //最大阈值
static void Main(string[] args)
{
//【1】载入原图像和模板块
g_srcImage = Cv2.ImRead("../../../images/home5.jpg");
Cv2.ImShow(WINDOW_NAME1, g_srcImage);
g_srcImage.CopyTo(g_srcImage1);
//【2】存留一张灰度图
Cv2.CvtColor(g_srcImage1, g_grayImage, ColorConversionCodes.BGR2GRAY);
//【3】创建窗口和滚动条
Cv2.NamedWindow(WINDOW_NAME1, WindowFlags.AutoSize);
int v = Cv2.CreateTrackbar("阈值:", WINDOW_NAME1, ref thresh, max_thresh, on_CornerHarris);
on_CornerHarris(0, IntPtr.Zero);
Cv2.WaitKey(0);
}
static void on_CornerHarris(int pos, IntPtr userData)
{
//【1】定义一些局部变量
Mat dstImage = new Mat();//目标图
Mat normImage = new Mat();//归一化后的图
Mat scaledImage = new Mat();//线性变换后的八位无符号整型的图
//【2】初始化
//置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
dstImage = new Mat(g_srcImage.Size(), MatType.CV_32FC1);
g_srcImage.CopyTo(g_srcImage1);
//【3】正式检测
//进行角点检测
Cv2.CornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BorderTypes.Default);
// 归一化与转换
Cv2.Normalize(dstImage, normImage, 0, 255, NormTypes.MinMax, MatType.CV_32FC1);
//将归一化后的图线性变换成8位无符号整型
Cv2.ConvertScaleAbs(normImage, scaledImage);
//【4】进行绘制
// 将检测到的,且符合阈值条件的角点绘制出来
for (int j = 0; j < normImage.Rows; j++)
{
for (int i = 0; i < normImage.Cols; i++)
{
if ((int)normImage.At<float>(j, i) > thresh + 80)
{
Cv2.Circle(g_srcImage1, new Point(i, j), 5, new Scalar(10, 10, 255), 2, LineTypes.Link8, 0);
Cv2.Circle(scaledImage, new Point(i, j), 5, new Scalar(0, 10, 255), 2, LineTypes.Link8, 0);
}
}
}
//【4】显示最终效果
Cv2.ImShow(WINDOW_NAME1, g_srcImage1);
Cv2.ImShow(WINDOW_NAME2, scaledImage);
}
}
}
C++版本代码如下:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【程序窗口1】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【程序窗口2】" //为窗口标题定义的宏
Mat g_srcImage, g_srcImage1, g_grayImage;
int thresh = 30; //当前阈值
int max_thresh = 175; //最大阈值
void on_CornerHarris(int, void*)
{
//【1】定义一些局部变量
Mat dstImage;//目标图
Mat normImage;//归一化后的图
Mat scaledImage;//线性变换后的八位无符号整型的图
//【2】初始化
// 置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
dstImage = Mat::zeros(g_srcImage.size(), CV_32FC1);
g_srcImage1 = g_srcImage.clone();
//【3】正式检测
// 进行角点检测
cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);
// 归一化与转换
normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
// 将归一化后的图线性变换成8位无符号整型
convertScaleAbs(normImage, scaledImage);
//【4】进行绘制
// 将检测到的,且符合阈值条件的角点绘制出来
for (int j = 0; j < normImage.rows; j++)
{
for (int i = 0; i < normImage.cols; i++)
{
if ((int)normImage.at<float>(j, i) > thresh + 80)
{
circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
circle(scaledImage, Point(i, j), 5, Scalar(0, 10, 255), 2, 8, 0);
}
}
}
//【4】显示最终效果
imshow(WINDOW_NAME1, g_srcImage1);
imshow(WINDOW_NAME2, scaledImage);
}
int main()
{
//【1】载入原始图并进行克隆保存
g_srcImage = imread("../images/home5.jpg", 1);
if (!g_srcImage.data) {
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n");
return false;
}
imshow(WINDOW_NAME1, g_srcImage);
g_srcImage1 = g_srcImage.clone();
//【2】存留一张灰度图
cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);
//【3】创建窗口和滚动条
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
createTrackbar("阈值: ", WINDOW_NAME1, &thresh, max_thresh, on_CornerHarris);
//【4】调用一次回调函数,进行初始化
on_CornerHarris(0, 0);
waitKey(0);
return(0);
}
Python版本代码如下:
import cv2
import numpy as np
def on_CornerHarris(x):
global g_srcImage1,g_grayImage
# 获取滑动条的值
thresh = cv2.getTrackbarPos('value', 'WINDOW_NAME1')
#初始化
# 置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
g_srcImage1 = np.copy(g_srcImage)
# 进行角点检测
dstImage = cv2.cornerHarris(g_grayImage, 5, 3, 0.04)
# 归一化与转换
# 下面这两种新建画布的方式都可以,新建一个32位浮点型单通道
normImage=np.empty((g_srcImage.shape[0], g_srcImage.shape[1], 1),dtype=np.float32)
#normImage = np.ones((g_srcImage.shape[0], g_srcImage.shape[1], 1),np.float32)
cv2.normalize(dstImage,normImage,0,255,cv2.NORM_MINMAX)
# 将归一化后的图线性变换成8位无符号整型
scaledImage = cv2.convertScaleAbs(normImage)
# 进行绘制
# 将检测到的,且符合阈值条件的角点绘制出来
imgH = normImage.shape[0]
imgW = normImage.shape[1]
for j in range(imgW):
for i in range(imgH):
if normImage[i][j].max() > (thresh + 80):
cv2.circle(g_srcImage1, (j, i), 5, (10, 10, 255) ,2, 8, 0)
cv2.circle(scaledImage, (j, i), 5, (0, 10, 255) ,2, 8, 0)
#【5】显示最终效果
cv2.imshow("WINDOW_NAME1", g_srcImage1)
cv2.imshow("WINDOW_NAME2", scaledImage)
# 【1】载入原始图并进行克隆保存
g_srcImage = cv2.imread("../images/home5.jpg")
cv2.imshow("WINDOW_NAME1", g_srcImage)
g_srcImage1 = np.copy(g_srcImage)
#【2】存留一张灰度图
g_grayImage = cv2.cvtColor(g_srcImage1, cv2.COLOR_BGR2GRAY)
#【3】创建窗口和滚动条
cv2.namedWindow('WINDOW_NAME1')
cv2.createTrackbar('value', 'WINDOW_NAME1', 30, 175, on_CornerHarris)
#【4】调用一次回调函数,进行初始化
cv2.setTrackbarPos('value', 'WINDOW_NAME1', 30)
cv2.waitKey(0)
cv2.destroyAllWindows()