具体实现:
//模板匹配
#include
#include
#include
using namespace cv;
using namespace std;
Mat src,dst,gray_src,temp;
int max_track = 5;//最多六种方法,0-5
const char* INPUT_T = "input_image";
const char* OUTPUT_T = "result_image";
const char* match_t = "template_match_demo";
int match_method = TM_SQDIFF;//方法参数
void Match_demo(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
temp = imread("C:/Users/18929/Desktop/博客项目/项目图片/09.jpg");
namedWindow(INPUT_T, WINDOW_AUTOSIZE);
namedWindow(OUTPUT_T, WINDOW_AUTOSIZE);
namedWindow(match_t, WINDOW_AUTOSIZE);
imshow(INPUT_T, src);
//定义一个滚动条控制使用哪个算法匹配
createTrackbar("tracker_title", OUTPUT_T, &match_method, max_track, Match_demo);
Match_demo(0, 0);
waitKey(0);
return 0;
}
void Match_demo(int, void*) {
int width = src.cols - temp.cols + 1;
int height = src.rows - temp.rows + 1;
Mat result(width, height, CV_32FC1);//定义一个图像接受匹配结果
matchTemplate(src,temp,result,match_method,Mat());//调用模板匹配方法
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
Point minLoc;//找到最小匹配坐标
Point maxLoc;//找到最大匹配坐标
double min, max;
src.copyTo(dst);
Point temLoc;//定义来记录对应结果坐标
minMaxLoc(result, &min, &max, &minLoc, &maxLoc, Mat());
//minMAXLoc -- 在数组中找到全局最小值和最大值
//即在result结果中,找出最小坐标和最大坐标
//&min, &max--返回的最小值指针, &minLoc, &maxLoc--返回最小最大值坐标的指针
if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED) {
temLoc = minLoc;//对应性算法--结果越小代表越相似
}
else {
temLoc = maxLoc;
}
//绘制矩形圈出结果
rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255));
rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255));
imshow(OUTPUT_T, result);
imshow(match_t, dst);
}
#include
#include
#include
using namespace cv;
using namespace std;
Mat src,dst,gray_src,temp;
const char* output_win = "findcontours-demo";
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Contours(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
namedWindow(output_win, WINDOW_AUTOSIZE);
imshow("input_image", src);
cvtColor(src, src, CV_BGR2GRAY);
//创建滚动条调节canny函数的最大最小阈值
const char* trackbar_title = "Threshold Value:";
createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
Demo_Contours(0, 0);
waitKey(0);
return 0;
}
void Demo_Contours(int, void*) {
Mat canny_output;
//定义一个容器装发现轮廓的位置
vector<vector<Point>> contours;
//定义图形的拓扑结构
vector<Vec4i> hierachy;
//边缘提取
Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
imshow("canny_img", canny_output);
//轮廓发现
findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//定义一个零图像,用来画轮廓
dst = Mat::zeros(src.size(), CV_8UC3);
RNG rng(12345);
for (size_t i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
}
imshow(output_win, dst);
}
效果:
可以看见,凸包会将所有轮廓包围在内,大小轮廓都有对应的凸包
代码实现:
//凸包
#include
#include
#include
using namespace cv;
using namespace std;
Mat src,dst,gray_src,temp,dst1;
const char* output_win = "output_img";
int threshold_value = 100;
int threshold_max = 255;
void Threshold_Callback(int, void*);
RNG rng(12345);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
namedWindow(output_win, WINDOW_AUTOSIZE);
const char* trackbar_label = "Threshold:";
cvtColor(src, gray_src, CV_BGR2GRAY);
//模糊一下,可以在图像二值化时降低噪声
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
imshow("input_image", gray_src);
createTrackbar(trackbar_label, output_win, &threshold_value, threshold_max, Threshold_Callback);
Threshold_Callback(0, 0);
waitKey(0);
return 0;
}
void Threshold_Callback(int, void*) {
Mat bin_output;
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
threshold(gray_src, bin_output, threshold_value, threshold_max, THRESH_BINARY);
findContours(bin_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//设定一个和contours大小的容器装可行的凸包点
vector<vector<Point>> convexs(contours.size());
//找出凸包可行点
for (size_t i = 0; i < contours.size(); ++i) {
convexHull(contours[i], convexs[i], false, true);//falsr--逆时针方向,true--返回点的个数
}
//绘制
dst = Mat::zeros(src.size(), CV_8UC3);
dst1 = Mat::zeros(src.size(), CV_8UC3);
vector<Vec4i> empty(0);//因为凸包没有拓扑结构,所以定义一个空的给它绘制
for (size_t j = 0; j < contours.size(); j++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//先画轮廓图
drawContours(dst, contours, j, color, 2, LINE_8, hierachy, 0, Point(0, 0));
drawContours(dst1, contours, j, color, 2, LINE_8, hierachy, 0, Point(0, 0));
//画凸包图
drawContours(dst, convexs, j, color, 2, LINE_8, empty, 0, Point(0, 0));
}
imshow(output_win, dst);
imshow("nature", dst1);
}
4. 轮廓周围绘制矩形或圆形
绘制矩形
什么是RDP算法?
对应就是设定最短距离,两点间最短距离小于最短距离的就要舍去中间点
openCV代码:
//绘制边缘矩形和圆形
#include
#include
#include
using namespace cv;
using namespace std;
Mat src,dst,gray_src,temp,dst1;
const char* output_win = "output_img";
RNG rng(12345);
int threshold_v = 100;
int threshold_max = 255;
void Contours_Callback(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/10.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
namedWindow(output_win, WINDOW_AUTOSIZE);
cvtColor(src, gray_src, CV_BGR2GRAY);
//模糊一下,二值化时减少噪点
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
imshow("input_image", gray_src);
createTrackbar("Threshold Value", output_win, &threshold_v, threshold_max, Contours_Callback);
Contours_Callback(0, 0);
waitKey(0);
return 0;
}
void Contours_Callback(int, void*) {
Mat binary_ouput;
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
threshold(gray_src, binary_ouput, threshold_v, threshold_max, THRESH_BINARY);
findContours(binary_ouput, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//设置存放矩形和圆形的容器
vector<vector<Point>> contours_poly(contours.size());
vector<Rect> ploy_rect(contours.size());
vector<Point2f> ccs(contours.size());
vector<float> radius(contours.size());
vector<RotatedRect> minRects(contours.size());
vector<RotatedRect> myellipse(contours.size());
for (size_t i = 0; i < contours.size(); i++)
{
//基于RDP算法,减少多边形轮廓点数,提高效率,把轮廓直线化,拟合为矩形
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//3-最短距离,低于该距离,舍弃,true--输出的是闭合的矩形
//绘制矩形
ploy_rect[i] = boundingRect(contours_poly[i]);
//获取可绘制矩形数据
minEnclosingCircle(contours[i], ccs[i], radius[i]);
//绘制旋转矩形,且旋转矩形需要大于5个连接点才可以进行
if (contours_poly[i].size() > 5) {
//用椭圆将像素点包围起来,椭圆拟合,获取绘制旋转椭圆的点
myellipse[i] = fitEllipse(contours_poly[i]);
//绘制旋转矩形
minRects[i] = minAreaRect(contours_poly[i]);
}
}
Mat drawImg,drawImg1;
drawImg = Mat::zeros(src.size(), src.type());
drawImg1 = Mat::zeros(src.size(), src.type());
Point2f pts[4];//存储矩形的四个点
for (size_t t = 0; t < contours.size(); t++) {
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
rectangle(drawImg, ploy_rect[t], color, 2, 8);
circle(drawImg, ccs[t], radius[t], color, 2, 8);
if (contours_poly[t].size()>5)
{
//绘制椭圆
ellipse(drawImg1, myellipse[t], color, 1, 8);
minRects[t].points(pts);//把minRect数据集分为多个点
//绘制旋转矩形
for (int r = 0; r < 4; r++)
{
line(drawImg1, pts[r], pts[(r + 1) % 4], color, 1, 8);
}
}
}
imshow(output_win, drawImg);
imshow("ROLATE", drawImg1);
return;