学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为2816字,预计阅读9分钟
OpenCV匹配轮廓
其实查找相似的东西用机器学习训练的方式处理应该是最好的,今天做的这个小练习主要是针对OpenCV的matchShapes函数的练习,正好把OpenCV的几个函数综合运用一下。
实现效果
从图上我们可以看出来,通过鼠标点击找到我们要实现的轮廓,然后通过匹配轮廓把找到的轮廓在左边的图中都画出来,其中是我们点击的轮廓就红色填充,匹配的相似轮廓用的蓝色填充,就是实现的一个这样简单的效果。
综合练习知识点
# | 实现的方式及用到的学习函数 |
---|---|
1 | 通过点击鼠标来选中需要匹配的轮廓,所以用到了setMouseCallback函数 |
2 | 基本图像操作,灰度图,高斯模糊,形态学梯度操作 |
3 | 查找轮廓findContours,获取鼠标点击的轮廓pointPolygonTest |
4 | 轮廓匹配matchShapes |
代码实现
微卡智享
OpenCV的项目搭建及配置请直接看《VS2017配置OpenCV通用属性》
整个项目中,一个main.cpp的文件,一个matchShape的类,如下图:
main.cpp
#include<opencv2/opencv.hpp>
#include<iostream>
#include"matchShape.h"
using namespace cv;
using namespace std;
string showsrc = "源图";
Point mPoint;
Mat src, srccopy;
void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数
int main(int agrc, char** argv) {
src = imread("E:/DCIM/tempsrc.jpg");
namedWindow(showsrc);
//设置鼠标响影事件
setMouseCallback(showsrc, onMouse);
imshow(showsrc, src);
waitKey(0);
return 0;
}
void onMouse(int event, int x, int y, int flags, void* ustc)
{
//鼠标左键按下抬起
if (event == EVENT_LBUTTONUP)
{
mPoint = Point(x, y);
srccopy = src.clone();
matchShape shape = matchShape();
srccopy = shape.findmatchShape(srccopy, mPoint);
imshow("res", srccopy);
}
}
matchShape.h
#pragma once
#include <opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
class matchShape
{
private:
//匹配阈值
double threshdouble = 0.3;
//获取图像轮廓
vector<vector<Point>> getContours(Mat src);
//获取点击的点的所在轮廓
vector<Point> getPointContour(vector<vector<Point>> contours, Point pt);
public:
Mat findmatchShape(Mat src, Point pt);
};
matchShape.cpp
#include "matchShape.h"
vector<vector<Point>> matchShape::getContours(Mat src)
{
vector<vector<Point>> contours;
Mat gray,tmp;
//1.灰度图
cvtColor(src, gray, COLOR_BGR2GRAY);
//2.高斯模糊
GaussianBlur(gray, gray, Size(3, 3), 0.5, 0.5);
//3.二值化
threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU);
//4.形态学梯度处理
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(gray, gray, MORPH_GRADIENT, kernel);
//imshow("gray", gray);
//4.查找轮廓
findContours(gray, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
return contours;
}
//获取点所在的轮廓
vector<Point> matchShape::getPointContour(vector<vector<Point>> contours, Point pt)
{
for (int i = 0; i < contours.size(); i++) {
if (pointPolygonTest(contours[i], pt, false) >= 0) return contours[i];
}
return vector<Point>();
}
Mat matchShape::findmatchShape(Mat src, Point pt)
{
Mat dst = Mat::zeros(src.size(), CV_8UC3);
//获取轮廓
vector<vector<Point>> contours = getContours(src);
//获取点所在的轮廓
vector<Point> ptcontour = getPointContour(contours, pt);
if (ptcontour.size() <= 0) return dst;
//获取相似轮廓
for (int t = 0; t < contours.size(); t++) {
double ret = matchShapes(ptcontour, contours[t], CONTOURS_MATCH_I3, 0.0);
cout << t << "相似度:" << ret << endl;
if (ret == 0) drawContours(dst, contours, t, Scalar(0, 0, 255),-1);
else if (ret <= threshdouble)
drawContours(dst, contours, t, Scalar(255, 0, 0),-1);
}
return dst;
}
运行起来后通过点击鼠标就可以直接显示出来了。
测试的图像在OpenCV的源码sources/samples/data下,我用的是smarties.png那一张。
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」