赞
踩
本节主要介绍OpenCV的imgproc模块的直方图与模板匹配部分:
1. 直方图的计算与绘制
2. 直方图对比
3. 反向投影
4. 模板匹配
平常老是用RGB了解这个较少,参见:HSL和HSV色彩空间 , 如何通俗地解释色彩三要素:色相、明度、纯度? , 什么是色像?什么是饱和度?什么是色温?什么是色调呢? 。
有多种
有时候根据需要我们也会用到累积直方图,或者水平直方图、竖直直方图等,知道就行。
这里主要使用了HSV中的H色相直方图,具体见书吧,写的还比较清楚。或者调试例程时,多用image watch插件看一看。
用的很广泛,最简单的目标匹配方法啦。其度量方式有很多种,官网type of the template matching operation ,这一点书中也有介绍。
本章示例较多,示例列表:
1.绘制H-S直方图
2.绘制RGB三色直方图
3.直方图对比
4. 反向投影
5.模板匹配
源码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage, hsvImage;
srcImage = imread("poster_cup.jpg");
cvtColor(srcImage, hsvImage, COLOR_BGR2HSV);
int hueBinNum = 30; //色调的直方图直条数量
int saturationBinNum = 32; //饱和度的直方图直条数量
int histSize[] = { hueBinNum, saturationBinNum };
float hueRanges[] = {0, 180}; //色相的变化范围为0到179
float saturationRanges[] = { 0, 256 }; //定义饱和度的变化范围为0(黑、白、灰)到255(纯光谱颜色)
const float* ranges[] = {hueRanges, saturationRanges}; //指向指针的数组,指针数组
MatND dstHist;
int channels[] = { 0, 1 };//calcHist函数中将计算第0通道和第1通道的直方图
calcHist(&hsvImage, //输入的数组
1, //数组个数为1
channels, //通道索引
Mat(), //不使用掩膜
dstHist, //输出的目标直方图
2, //需要计算的直方图的维度为2
histSize, //存放每个维度的直方图尺寸的数组
ranges //每一维数值的取值范围数组
);
double maxValue = 0; //最大值
minMaxLoc(dstHist, 0, &maxValue, 0, 0); //查找数组和子数组的全局最大值存入maxValue中
int scale = 10;
Mat histImg = Mat::zeros(saturationBinNum*scale, hueBinNum*scale, CV_8UC3);
for (int hue = 0; hue < hueBinNum; hue++) //双层循环,进行直方图绘制
for (int saturation = 0; saturation < saturationBinNum; saturation++) {
float binValue = dstHist.at<float>(hue, saturation); //直方图直条的值
int intensity = cvRound(binValue*255/maxValue); //强度,归一化到0-255之间
rectangle(histImg, Point(hue*scale, saturation*scale), Point((hue+1)*scale-1, (saturation+1)*scale-1), Scalar::all(intensity), FILLED); //绘制
}
imshow("【素材图】", srcImage);
imshow("【H-S 直方图】", histImg);
while (waitKey(8)!=27);
return 0;
}

素材:
效果图:
提示:
无
源码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
Mat srcImage = imread("poster_building_1.jpg");
// Mat srcImage(200, 200, CV_8UC3, Scalar(50, 100, 150));
imshow("【素材图】", srcImage);
int bins = 256;
int hist_size[] = { bins };
float range[] = { 0, 256 };
const float* ranges[] = { range }; //指针数组
MatND redHist, greenHist, blueHist;
//红色分量直方图的计算(OpenCV中的存储顺序为BGR)
int channels_r[] = { 2 };
calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges);
//绿色分量直方图的计算
int channels_g[] = { 1 };
calcHist(&srcImage, 1, channels_g, Mat(), greenHist, 1, hist_size, ranges);
//蓝色分量直方图的计算
int channels_b[] = { 0 };
calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges);
double maxValue_red, maxValue_green, maxValue_blue;
minMaxLoc(redHist, 0, &maxValue_red, 0, 0); //此处不需要最小值
minMaxLoc(greenHist, 0, &maxValue_green, 0, 0);
minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
int scale = 1;
int histHeight = 256;
Mat histImage = Mat::zeros(histHeight, bins*3, CV_8UC3);
for (int i = 0; i < bins; i++)
{
float binValue_red = redHist.at<float>(i);
float binValue_green = greenHist.at<float>(i);
float binValue_blue = blueHist.at<float>(i);
int intensity_red = cvRound(binValue_red*histHeight/maxValue_red); //要绘制的高度
int intensity_green = cvRound(binValue_green*histHeight / maxValue_green);
int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue);
rectangle(histImage, Point(i*scale, histHeight-1), Point((i+1)*scale-1, histHeight - intensity_red), Scalar(0, 0, 255));
rectangle(histImage, Point((i+bins)*scale, histHeight - 1), Point((i+bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
rectangle(histImage, Point((i+bins*2)*scale, histHeight - 1), Point((i+bins*2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(255, 0, 0));
}
imshow("【图像的RGB直方图】", histImage);
while (waitKey(9) !=27);
return 0;
}

素材:
效果图:
提示:
无
源码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
Mat srcImage_base, hsvImage_base;
Mat srcImage_test1, hsvImage_test1;
Mat srcImage_test2, hsvImage_test2;
Mat hsvImage_halfDown;
srcImage_base = imread("poster_book.jpg");
srcImage_test1 = imread("poster_book_1.jpg");
srcImage_test2 = imread("poster_book_2.jpg");
imshow("【基准图像】", srcImage_base);
imshow("【测试图像1】", srcImage_test1);
imshow("【测试图像2】", srcImage_test2);
cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
cvtColor(srcImage_test2, hsvImage_test2, COLOR_BGR2HSV);
hsvImage_halfDown = hsvImage_base(Range(hsvImage_base.rows/2, hsvImage_base.rows - 1), Range(0, hsvImage_base.cols - 1)); //此处选取的是ROI,引用
int h_bins = 30; //对hue通道分30个等级
int s_bins = 32; //saturation通道分32个等级
int histSize[] = { h_bins, s_bins };
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
int channels[] = { 0, 1 };
MatND baseHist, halfDownHist, testHist1, testHist2;
calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges);
normalize(baseHist, baseHist, 0, 1, NORM_MINMAX);
calcHist(&hsvImage_halfDown, 1, channels, Mat(), halfDownHist, 2, histSize, ranges);
normalize(halfDownHist, halfDownHist, 0, 1, NORM_MINMAX);
calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges);
normalize(testHist1, testHist1, 0, 1, NORM_MINMAX);
calcHist(&hsvImage_test2, 1, channels, Mat(), testHist2, 2, histSize, ranges);
normalize(testHist2, testHist2, 0, 1, NORM_MINMAX);
for (int i = 0; i < 4; i++) {
int compare_method = i;
double base_base = compareHist(baseHist, baseHist, compare_method);
double base_half = compareHist(baseHist, halfDownHist, compare_method);
double base_test1 = compareHist(baseHist, testHist1, compare_method);
double base_test2 = compareHist(baseHist, testHist2, compare_method);
printf("方法[%d]的匹配结果如下:\n\n【基准图-基准图】:%f,【基准图-半身图】:%f,【基准图-测试图1】:%f,【基准图-测试图2】:%f \n--------------------------------------------\n", i, base_base, base_half, base_test1, base_test2);
}
cout << "检测结束。";
while (waitKey(5) != 27);
return 0;
}

素材:
poster_book.jpg:
poster_book_1.jpg:
poster_book_2.jpg:
效果图:
提示:
无
源码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
#define WINDOW_NAME1 "【原始图】"
Mat g_srcImage, g_hsvImage, g_hueImage;
int g_bins = 30; //直方图组距
void on_BinChange(int, void*);
int main() {
g_srcImage = imread("poster_hand.jpg");
cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);
g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
int ch[]{ 0, 0 };
mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);
namedWindow(WINDOW_NAME1);
createTrackbar("色相组距", WINDOW_NAME1, &g_bins, 180, on_BinChange);
on_BinChange(0, 0);
imshow(WINDOW_NAME1, g_srcImage);
while (waitKey(9)!=27);
return 0;
}
void on_BinChange(int, void*) {
MatND hist;
g_bins = MAX(g_bins, 2);
int histSize[] = { g_bins };
float hue_range[] = { 0, 180 };
const float* ranges[] = { hue_range };
int channels[]={0};
calcHist(&g_hueImage, 1, channels, Mat(), hist, 1, histSize, ranges); //计算直方图并归一化
normalize(hist, hist, 0, 255, NORM_MINMAX);
MatND backproj; //计算反向投影
calcBackProject(&g_hueImage, 1, channels, hist, backproj, ranges);
imshow("【反向投影图】", backproj);
int w = 400, h = 400;
int bin_w = cvRound((double)w/ g_bins);
Mat histImg = Mat::zeros(w, h, CV_8UC3);
for(int i = 0; i < g_bins; i++ ){
rectangle(histImg, Point(i*bin_w, h), Point((i+1)*bin_w, h-cvRound(hist.at<float>(i)*h/255.0)), Scalar(100, 123, 255), CV_FILLED);
}
imshow("【直方图】", histImg);
}

素材:
效果图:
提示:
无
源码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
#define WINDOW_NAME1 "【原始图片】"
#define WINDOW_NAME2 "【效果窗口】"
Mat g_srcImage, g_templateImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum=5;
void on_Matching(int, void*);
int main() {
g_srcImage = imread("poster_girl_4.jpg");
g_templateImage = imread("poster_girl_4_ROI.jpg");
namedWindow(WINDOW_NAME1);
namedWindow(WINDOW_NAME2);
createTrackbar("方法", WINDOW_NAME1, &g_nMatchMethod, g_nMaxTrackbarNum, on_Matching);
on_Matching(0, 0);
while (waitKey(8)!=27);
return 0;
}
void on_Matching(int, void*) {
Mat srcImage;
g_srcImage.copyTo(srcImage);
g_resultImage.create(g_srcImage.cols-g_templateImage.cols+1, g_srcImage.rows - g_templateImage.rows + 1, CV_32FC1);
matchTemplate(g_srcImage, g_templateImage, g_resultImage, g_nMatchMethod); //第3中方法明显跑偏了
normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX);
double minValue, maxValue;
Point minLocation, maxLocation;
minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation);
Point matchLocation;
if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == TM_SQDIFF_NORMED) {
matchLocation = minLocation;
}
else {
matchLocation = maxLocation;
}
rectangle(srcImage, Point(matchLocation),Point(matchLocation.x+g_templateImage.cols, matchLocation.y+g_templateImage.rows), Scalar(0, 0, 255), 2);
rectangle(g_resultImage, Point(matchLocation), Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2);
imshow(WINDOW_NAME1, srcImage);
imshow(WINDOW_NAME2, g_resultImage);
}

素材:
效果图:
提示:
无
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。