第三张图:
方法:轮廓检测后亚像素级角点检测 ,得出角点坐标,再提取
个人感觉这种方法抗干扰能力最好。
代码:
//第三张,轮廓检测后亚像素级角点检测 ,得出角点坐标
#include
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
using namespace cv;
using namespace std;
#define WINDOW_NAME "【亚像素级角点检测】"
Mat g_srcImage, g_grayImage;
int g_maxCornerNumber = 20; //点数初始值
int g_maxTrackbarNumber = 500; //点数上线
//RNG g_rng(12345); //初始化随机数生成器
void on_GoodFeaturesToTrack(int, void*) //响应滑动条移动的回调函数
{
if (g_maxCornerNumber <= 7) { g_maxCornerNumber = 7; } //对变量小于等于1时的处理
vector corners; //Shi-Tomasi算法(goodFeaturesToTrack函数)的参数准备
double qualityLevel = 0.01; //角点检测可接受的最小特征值
double minDistance = 10; //角点之间的最小距离
int blockSize = 3; //计算导数自相关矩阵时指定的邻域范围
double k = 0.04; //权重系数
Mat copy = g_srcImage.clone();
//进行Shi-Tomasi角点检测
goodFeaturesToTrack
(g_grayImage, //输入图像
corners, //检测到的角点的输出向量
g_maxCornerNumber, //角点的最大数量
qualityLevel, //角点检测可接受的最小特征值
minDistance, //角点之间的最小距离
Mat(), //感兴趣区域
blockSize, //计算导数自相关矩阵时指定的邻域范围
false, //不使用Harris角点检测
k); //权重系数
cout << "\n\t>-此次检测到的角点数量为:" << corners.size() << endl;
//亚像素角点检测的参数设置
Size winSize = Size(5, 5);
Size zeroZone = Size(-1, -1);
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
//计算出亚像素角点位置
cornerSubPix(g_grayImage, corners, winSize, zeroZone, criteria);
Point2f lowstpoint, nextpoint, uppoint, mid; //初始化最下方点,下一个点,最下方上面的点,中间点
lowstpoint = corners[0];
uppoint = corners[0];
for (int i = 0; i < corners.size(); i++) //找出最低点
{
nextpoint = corners[i];
if (nextpoint.y > lowstpoint.y) { lowstpoint = nextpoint; }
if (i == corners.size() - 1)
{
for (int j = 0; j < corners.size(); j++) //已找到最后一个点,开始找竖直方向最近点
{
nextpoint = corners[j];
float a = abs(nextpoint.x - lowstpoint.x);
float b = abs(uppoint.x - lowstpoint.x);
if (nextpoint != lowstpoint) //除去最下方的点
{
if (a < b) { uppoint = nextpoint; }
}
if (j == corners.size() - 1) //已找到竖直方向最近点,得到中间点
{
mid.x = (uppoint.x + lowstpoint.x) / 2;
mid.y = (uppoint.y + lowstpoint.y) / 2;
circle(copy, mid, 3, Scalar(0, 255, 0), -1, 8, 0);
cout << " \t>>中间点坐标" << " (" << mid.x << "," << mid.y << ")" << endl;
}
}
}
}
imshow(WINDOW_NAME, copy);
}
int main(int argc, char** argv)
{
Mat srcImage = imread("3.jpg", 0); //载入原始图二值图模式
imshow("原始图", srcImage);
Mat element = getStructuringElement(MORPH_RECT, Size(2, 2)); //定义核,开运算
morphologyEx(srcImage, srcImage, MORPH_OPEN, element); //进行形态学开运算操作
Mat dstImage = Mat::zeros(srcImage.rows, srcImage.cols, CV_8UC3); //初始化结果图
srcImage = srcImage > 50; //srcImage取大于阈值。。。那部分
imshow("取阈值后的原始图", srcImage);
vector > contours;
vector hierarchy;
findContours(srcImage, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
int index = 0; //遍历所有顶层的轮廓, 以随机颜色绘制出每个连接组件颜色
for (; index >= 0; index = hierarchy[index][0])
{
Scalar color(rand() & 255, rand() & 255, rand() & 255);
drawContours(dstImage, contours, index, color, FILLED, 8, hierarchy);
}
system("color 2F");
g_srcImage = dstImage;
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE); //创建窗口和滑动条,并进行显示和回调函数初始化
createTrackbar("最大角点数", WINDOW_NAME, &g_maxCornerNumber, g_maxTrackbarNumber, on_GoodFeaturesToTrack);
//imshow(WINDOW_NAME, g_srcImage);
on_GoodFeaturesToTrack(0, 0);
waitKey(0);
return 0;
}
结果图:
位置图:
希望有其他方法的小伙伴可以留言。大家相互学习。