/*
Hu轮廓匹配:
#include "Opencv_MatchShape.h"
#include "Match_Shape_NCC.h"
int main(int argc, char* argv)
{
Opencv_MatchShape demo;
demo.MatchShape_HU();
system("pause");
return 0;
}
*/
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
class Opencv_MatchShape
{
public:
Opencv_MatchShape();
~Opencv_MatchShape();
//
void MatchShape_test1();// 轮廓寻找
//
struct ptin
{
int DerivativeX;
int DerivativeY;
double Magnitude;
double MagnitudeN;
}ptin;
void MatchShape_test2();
void MatchShape_HU();/* 对比两张图的形状是 否相似越小越相近 */
private:
};
Opencv_MatchShape::Opencv_MatchShape()
{
}
Opencv_MatchShape::~Opencv_MatchShape()
{
}
void Opencv_MatchShape::MatchShape_test1()
{
//***********************计算时间************************************************
double total_time = 0;
clock_t start_time = clock();
clock_t stop_time = clock();
total_time = double(stop_time - start_time) / CLOCKS_PER_SEC;
//***********************************************************************
char* param="./Resource/Search1.jpg";
Mat searchImage = imread(param, 1);
if (searchImage.empty())
{
return;
}
imshow("searchImage", searchImage);
waitKey(0);
//***********************Opencv自带的轮廓匹配__SearchImage灰度化****************************
Mat graySearchImg = cvCreateMat(searchImage.rows, searchImage.cols, CV_8UC1);
if (searchImage.channels() == 3)
cvtColor(searchImage, graySearchImg, CV_RGB2GRAY);
else
{
searchImage.copyTo(graySearchImg);
}
imshow("graySearchImg", graySearchImg);
waitKey(0);
//***********************Opencv自带的轮廓匹配__SearchImage二值化****************************
/*
//! type of the threshold operation
enum { THRESH_BINARY=CV_THRESH_BINARY, THRESH_BINARY_INV=CV_THRESH_BINARY_INV,
THRESH_TRUNC=CV_THRESH_TRUNC, THRESH_TOZERO=CV_THRESH_TOZERO,
THRESH_TOZERO_INV=CV_THRESH_TOZERO_INV, THRESH_MASK=CV_THRESH_MASK,
THRESH_OTSU=CV_THRESH_OTSU };
*/
Mat dst_bw;
threshold(graySearchImg, dst_bw, 20, 255, CV_THRESH_OTSU);
imshow("dst_bw", dst_bw);
waitKey(0);
//***********************Opencv自带的轮廓匹配__SearchImage边缘检测****************************
Mat edge;
Canny(dst_bw, edge, 125, 350);
imshow("dst_edge", edge);
waitKey(0);
//***********************Opencv自带的轮廓匹配_SearchImage'Contours****************************
/*
https://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
*/
/*
## mode:(定义轮廓的检索模式)
CV_RETR_EXTERNAL 只检测最外围轮廓,包含在外围轮廓内的内围轮廓将被忽略
CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立
CV_RETR_CCOMP 检测所有的轮廓,但所有的轮廓只建立两个等级关系
CV_RETR_TREE 检测所有轮廓,所有轮廓建立一个等级树结构
## method:(定义轮廓的近似方法)
CV_CHAIN_APPROX_NONE 存储所有的轮廓点
CV_CHAIN_APPROX_SIMPLE 压缩水平垂直对角等
CV_CHAIN_APPROX_TC89_L1 近似算法
*/
vector> contours;
vector hierarchy;
findContours(edge, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓
/// Draw contours
RNG rng(12345);
Mat drawing = Mat::zeros(edge.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(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
/// Show in a window
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
waitKey(0);
//***********************Opencv自带的轮廓匹配_模板TemplatImage轮廓****************************
char* param_template = "./Resource/Template.jpg";
Mat TemplateImage = imread(param_template, 1);
if (TemplateImage.empty())
{
return;
}
imshow("Template", TemplateImage);
waitKey(0);
//
Mat grayTemplateImg = cvCreateMat(TemplateImage.rows, TemplateImage.cols, CV_8UC1);
if (TemplateImage.channels() == 3)
cvtColor(TemplateImage, grayTemplateImg, CV_RGB2GRAY);
else
{
TemplateImage.copyTo(grayTemplateImg);
}
imshow("grayTemplateImg", grayTemplateImg);
waitKey(0);
//***********************Opencv自带的轮廓匹配_模板TemplatImage轮廓****************************
Mat dst_template_bw;
threshold(grayTemplateImg, dst_template_bw, 0, 255, CV_THRESH_OTSU);
imshow("dst_template_bw", dst_template_bw);
waitKey(0);
/*
## mode:(定义轮廓的检索模式)
CV_RETR_EXTERNAL 只检测最外围轮廓,包含在外围轮廓内的内围轮廓将被忽略
CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立
CV_RETR_CCOMP 检测所有的轮廓,但所有的轮廓只建立两个等级关系
CV_RETR_TREE 检测所有轮廓,所有轮廓建立一个等级树结构
## method:(定义轮廓的近似方法)
CV_CHAIN_APPROX_NONE 存储所有的轮廓点
CV_CHAIN_APPROX_SIMPLE 压缩水平垂直对角等
CV_CHAIN_APPROX_TC89_L1 近似算法
*/
//***********************Opencv自带的轮廓匹配_模板TemplatImage边缘检测****************************
Mat template_edge;
Canny(dst_template_bw, template_edge, 125, 350);
imshow("template_edge", template_edge);
waitKey(0);
//
vector> contours_template;
vector hierarchy_template;
findContours(template_edge, contours_template, hierarchy_template, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓
/// Draw contours
RNG rng_template(12345);
Mat drawing_template = Mat::zeros(template_edge.size(), CV_8UC3);
for (int i = 0; i< contours_template.size(); i++)
{
Scalar color = Scalar(rng_template.uniform(0, 255), rng_template.uniform(0, 255), rng_template.uniform(0, 255));
drawContours(drawing_template, contours_template, i, color, 2, 8, hierarchy_template, 0, Point());
}
/// Show in a window
namedWindow("Contours_Template", CV_WINDOW_AUTOSIZE);
imshow("Contours_Template", drawing_template);
waitKey(0);
system("pause");
}
void Opencv_MatchShape::MatchShape_test2()
{
char* param = "./Resource/Template.jpg";
Mat src = imread(param, 1);
if (src.empty())
{
return;
}
Mat gray;
cvtColor(src, gray, CV_RGB2GRAY);
if (gray.type() != CV_8UC1)
{
return;
}
imshow("gray", gray);
waitKey(0);
Mat bw;
threshold(gray, bw, 20, 255, CV_THRESH_OTSU);
imshow("bw", bw);
waitKey(0);
Mat edge;
Canny(bw, edge, 125, 350);
imshow("dst_edge", edge);
waitKey(0);
vector> contours;
vector hierarchy;
findContours(edge, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓
Mat gx, gy;
Sobel(gray, gx, CV_32F, 1, 0);
Sobel(gray, gy, CV_32F, 0, 1);
Mat magnitude, direction;
cartToPolar(gx, gy, magnitude, direction);
long contoursLength = 0;
double magnitudeTemp = 0;
int originx = contours[0][0].x;
int originy = contours[0][0].y;
typedef struct my
{
int DerivativeX;
int DerivativeY;
double Magnitude;
double MagnitudeN;
}ptin;
// 提取dx\dy\mag\log信息
vector> contoursInfo;
// 提取相对坐标位置
vector> contoursRelative;
// 开始提取
for (int i = 0; i < contours.size(); i++) {
int n = contours[i].size();
contoursLength += n;
contoursInfo.push_back(vector(n));
vector points(n);
for (int j = 0; j < n; j++) {
int x = contours[i][j].x;
int y = contours[i][j].y;
points[j].x = x - originx;
points[j].y = y - originy;
ptin pointInfo;
pointInfo.DerivativeX = gx.at(y, x);
pointInfo.DerivativeY = gy.at(y, x);
magnitudeTemp = magnitude.at(y, x);
pointInfo.Magnitude = magnitudeTemp;
if (magnitudeTemp != 0)
pointInfo.MagnitudeN = 1 / magnitudeTemp;
contoursInfo[i][j] = pointInfo;
}
contoursRelative.push_back(points);
}
// 计算目标图像梯度
char* param1 = "./Resource/Search2.jpg";
Mat src_search = imread(param1, 1);
Mat grayImage;
if (src_search.empty())
{
cout << "空" << endl;
return;
}
if (src_search.channels() == 3)
{
cvtColor(src_search, grayImage, CV_RGB2GRAY);
}
else
{
src_search.copyTo(grayImage);
}
if (grayImage.type() != CV_8UC1)
{
cout << "!CV_8UC1" << endl;
return;
}
Mat gradx, grady;
Sobel(grayImage, gradx, CV_32F, 1, 0);
Sobel(grayImage, grady, CV_32F, 0, 1);
Mat mag, angle;
cartToPolar(gradx, grady, mag, angle);
// NCC模板匹配
double minScore = 0.7; //deafult value
double greediness = 0.8; //deafult value
double nGreediness = 0.8; //deafult value
double nMinScore = 0.7; //deafult value
double partialScore = 0;
double resultScore = 0;
int resultX = 0;
int resultY = 0;
double start = (double)getTickCount();
for (int row = 0; row < grayImage.rows; row++)
{
for (int col = 0; col < grayImage.cols; col++) {
double sum = 0;
long num = 0;
for (int m = 0; m < contoursRelative.size(); m++) {
for (int n = 0; n < contoursRelative[m].size(); n++) {
num += 1;
int curX = col + contoursRelative[m][n].x;
int curY = row + contoursRelative[m][n].y;
if (curX < 0 || curY < 0 || curX > grayImage.cols - 1 || curY > grayImage.rows - 1) {
continue;
}
// 目标边缘梯度
double sdx = gradx.at(curY, curX);
double sdy = grady.at(curY, curX);
// 模板边缘梯度
double tdx = contoursInfo[m][n].DerivativeX;
double tdy = contoursInfo[m][n].DerivativeY;
// 计算匹配
if ((sdy != 0 || sdx != 0) && (tdx != 0 || tdy != 0))
{
double nMagnitude = mag.at(curY, curX);
if (nMagnitude != 0)
sum += (sdx * tdx + sdy * tdy) * contoursInfo[m][n].MagnitudeN / nMagnitude;
}
// 任意节点score之和必须大于最小阈值
partialScore = sum / num;
if (partialScore < min((minScore - 1) + (nGreediness * num), nMinScore * num))
break;
}
}
// 保存匹配起始点
if (partialScore > resultScore)
{
resultScore = partialScore;
resultX = col;
resultY = row;
}
}
}
cout << resultY << endl;
cout << resultX << endl;
CvPoint point;
point.x = resultX;
point.y = resultY;
circle(src_search, point, 10, Scalar(255, 255, 255), 8);
imshow("src", src_search);
waitKey(0);
}
/* 对比两张图的形状是 否相似越小越相近 */
void Opencv_MatchShape::MatchShape_HU()
{
cv::Mat src_template, hsv_base;
cv::Mat src_search, hsv_test1;
src_template = imread("./Resource/a.jpg");//模板
src_search = imread("./Resource/b.jpg");//待测图
int thresh = 100;
double ans = 0, result = 0;
Mat imageresult1, imageresult2;
if (src_template.type() == CV_8UC3)
{
cvtColor(src_template, imageresult1, CV_RGB2GRAY);
cvtColor(src_search, imageresult2, CV_RGB2GRAY);
}
else
{
src_template.copyTo(imageresult1);
src_search.copyTo(imageresult2);
}
blur(imageresult1, imageresult1, Size(3, 3));
blur(imageresult2, imageresult2, Size(3, 3));
threshold(imageresult1, hsv_base, 20, 255, CV_THRESH_OTSU);
threshold(imageresult2, hsv_test1, 20, 255, CV_THRESH_OTSU);
Canny(hsv_base, imageresult1, thresh, thresh * 2);
Canny(hsv_test1, imageresult2, thresh, thresh * 2);
std::vector>contours1, contours2;
std::vectorhierarchy1, hierarchy2;
CvSize Ssize;
Ssize.height = src_template.rows;;
Ssize.width = src_template.cols;
Mat drawing1(Ssize, CV_8UC3, Scalar(0, 0, 0));
findContours(imageresult1, contours1, hierarchy1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
RNG rng(12345);
int T_w, T_h;
for (int i = 0; ibox.size.width)
{
T_w = box.size.height;
T_h = box.size.width;
}
else
{
T_h = box.size.height;
T_w = box.size.width;
}
cout << T_w << endl<< T_h << endl;
}
namedWindow("imageresult2", 0);
imshow("imageresult1", drawing1);
CvSize Ssize2;
Ssize2.height = src_search.rows;;
Ssize2.width = src_search.cols;
Mat drawing2(Ssize2, CV_8UC3, Scalar(0, 0, 0));;
findContours(imageresult2, contours2, hierarchy2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));
vector boundRect(contours2.size());//包围矩形框
vector box(contours2.size());
for (int i = 0; i> label;
//
cout << box[j].size.width<< endl;
cout << box[j].size.height << endl;
float temp_size,w,h;
if (box[j].size.width < box[j].size.height)
{
h = box[j].size.width;
w = box[j].size.height;
}
else
{
w = box[j].size.width;
h = box[j].size.height;
}
cout << w << endl;
cout << h << endl;
//筛选最接近尺寸的形状-长和宽的比较
/*int T = 15;
if (sqrt(abs((w - T_w)*(w - T_w) + (h - T_h)*(h - T_h))) < T)
{
putText(drawing2, label, Point(box[j].center.x, box[j].center.y), CV_FONT_BLACK, 1, Scalar(0, 255, 0), 2);
}*/
putText(drawing2, label, Point(box[j].center.x, box[j].center.y), CV_FONT_BLACK, 1, Scalar(0, 255, 0), 2);
}
}
namedWindow("imageresult2", 0);
imshow("imageresult2", drawing2);
waitKey(0);
}