天天看點

花老濕學習OpenCV:圖像矩與輪廓比對

引言:

矩的概念介紹

       矩函數在圖像分析中有着廣泛的應用,如模式識别、目标分類、目辨別别與方位估計、圖像的編碼與重構等。從一幅圖像計算出來的矩集,不僅可以描述圖像形狀的全局特征,而且可以提供大量關于該圖像不同的幾何特征資訊,如大小,位置、方向和形狀等。圖像矩這種描述能力廣泛應用于各種圖像處理、計算機視覺和機器人技術領域的目辨別别與方位估計中。

一階矩:與形狀有關;

二階矩:顯示曲線圍繞直線平均值的擴充程度;

三階矩:關于平均值的對稱性測量;由二階矩和三階矩可以導出7個不變矩。而不變矩是圖像的統計特性,滿足平移、伸縮、旋轉均不變的不變性、在圖像識别領域得到廣泛的應用。

花老濕學習OpenCV:圖像矩與輪廓比對

API:

1.moments()用于計算多邊形和光栅形狀的最高達三階的所有矩。矩用來計算形狀的重心、面積,主軸和其他形狀特征,如7Hu不變量等。

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對

2.contourArea()用于計算整個輪廓或部分輪廓的面積。

花老濕學習OpenCV:圖像矩與輪廓比對

3.arcLength()函數用于計算封閉輪廓的周長或曲線的長度

花老濕學習OpenCV:圖像矩與輪廓比對

4. matchShapes()比較輪廓是基于Hu矩計算的,結果越小相似度越高。

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對

代碼示例:

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int thresholdval = 8;
int thresholdmax = 255;

int mode = 0;
void Moments_demo(int pos, void* userdata);

Mat src;
Mat blursrc;
RNG rng(getTickCount());

int main()
{
	//待檢測圖像
	src = imread("F:\\visual studio\\Image\\gesture1.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("src", src);
	
	//轉化為灰階圖
	Mat graysrc;
	cvtColor(src, graysrc, COLOR_BGR2GRAY);

	//高斯模糊
	GaussianBlur(graysrc, blursrc, Size(3, 3), 0, 0);

	namedWindow("dst", WINDOW_AUTOSIZE);
	createTrackbar("Threshold", "dst", &thresholdval, thresholdmax, Moments_demo);
	createTrackbar("mode", "dst", &mode, 3, Moments_demo);
	Moments_demo(0, 0);
	
	waitKey(0);

}

void Moments_demo(int pos, void* userdata)
{
	//門檻值化
	Mat bin;
	threshold(~blursrc, bin, thresholdval, thresholdmax, CV_THRESH_BINARY);
	imshow("bin", bin);

	//輪廓檢測
	vector<vector<Point>> Contours;
	vector<Vec4i> hierachy;
	findContours(bin, Contours, hierachy, mode, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	//輪廓繪制
	Mat dst = Mat::zeros(src.size(), CV_8UC3);
	for (int 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, LINE_AA);
	}
	

	//計算矩
	vector<Moments> mu(Contours.size());
	for (int i = 0; i < Contours.size(); i++)
	{
		mu[i]=moments(Contours[i], true);
	}
	
	vector<Point2f> mc(Contours.size());
	for (int i = 0; i < Contours.size(); i++)
	{
		//計算中心并繪制
		mc[i] = Point2f(static_cast<float>(mu[i].m10 / mu[i].m00), static_cast<float>(mu[i].m01 / mu[i].m00));
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		circle(dst, mc[i], 2, color, FILLED, LINE_AA);
		//計算輪廓面積與長度
		double area = contourArea(Contours[i],true);
		double length = arcLength(Contours[i], true);
		cout << "contours " << i << " : <m00> =  " << mu[i].m00 << " Area = " << contourArea(Contours[i]) << " Arc length = " << arcLength(Contours[i], true) << endl;
	}
	imshow("dst", dst);	
}
           

效果展示:

源圖像與二維圖像:

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對

畫出輪廓、根據圖像矩的值計算并繪制出中心點、計算輪廓的面積與長度。

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對
#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int thresholdval = 8;
int thresholdmax = 255;

int mode = 0;
void Moments_demo(int pos, void* userdata);

Mat src;
Mat temp;
Mat blursrc;
Mat blurtemp;

RNG rng(getTickCount());

int main()
{
	//待檢測圖像
	src = imread("F:\\visual studio\\Image\\gesture1.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	resize(src, src, Size(), 1, 0.8);
	//imshow("src", src);
	//轉化為灰階圖
	Mat graysrc;
	cvtColor(src, graysrc, COLOR_BGR2GRAY);

	//高斯模糊
	GaussianBlur(graysrc, blursrc, Size(3, 3), 0, 0);

    imshow("src", src);

	//模闆圖像
	temp = imread("F:\\visual studio\\Image\\temp.jpg");
	if (temp.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("temp", temp);
	
	//轉化為灰階圖
	Mat graytemp;
	cvtColor(temp, graytemp, COLOR_BGR2GRAY);
	//高斯模糊
	GaussianBlur(graytemp, blurtemp, Size(3, 3), 0, 0);
	
	namedWindow("dst", WINDOW_AUTOSIZE);
	createTrackbar("Threshold", "dst", &thresholdval, thresholdmax, Moments_demo);
	createTrackbar("mode", "dst", &mode, 3, Moments_demo);
	Moments_demo(0, 0);

	waitKey(0);

}

void Moments_demo(int pos, void* userdata)
{
	//門檻值化
	Mat binsrc;
	threshold(~blursrc, binsrc, thresholdval, thresholdmax, CV_THRESH_BINARY);
	imshow("binsrc", binsrc);

	//輪廓檢測
	vector<vector<Point>> Contours1;
	vector<Vec4i> hierachy1;
	findContours(binsrc, Contours1, hierachy1, mode, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	//輪廓繪制
	//Mat dst = Mat::zeros(src.size(), CV_8UC3);
	//for (int i = 0; i < Contours1.size(); i++)
	//{
	//	Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
	//	drawContours(dst, Contours1, i, color, 2, LINE_AA);
	//}

	
	Mat bintemp;
	threshold(~blurtemp, bintemp, thresholdval, thresholdmax, CV_THRESH_BINARY);
	imshow("bintemp", bintemp);

	//輪廓檢測
	vector<vector<Point>> Contours2;
	vector<Vec4i> hierachy2;
	findContours(bintemp, Contours2, hierachy2, mode, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	//輪廓繪制
	Mat dst = Mat::zeros(src.size(), CV_8UC3);
	//for (int i = 0; i < Contours2.size(); i++)
	//{
	//	Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
	//	drawContours(dst, Contours2, i, color, 2, LINE_AA);
	//}

	cout << Contours2.size() << endl;

	for (int i = 0; i < Contours2.size(); i++)
	{
		for (int j = 0; j < Contours1.size(); j++)
		{
			double matchRate = matchShapes(Contours2[i], Contours1[j], CV_CONTOURS_MATCH_I1, 0.0);
			cout << matchRate << endl;
			if (matchRate <= 0.01)
			{
				drawContours(dst, Contours1, j, Scalar(0, 255, 0), 2, 8);
			}
			imshow("dst", dst);
		}
	}
}
           

效果如下: 

待檢測圖像與其二值圖像:

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對

模闆圖像與其二值圖像: 

花老濕學習OpenCV:圖像矩與輪廓比對
花老濕學習OpenCV:圖像矩與輪廓比對

比對程度最高的輪廓: 

花老濕學習OpenCV:圖像矩與輪廓比對