一:内容介绍

本节主要介绍OpenCV的imgproc模块的直方图与模板匹配部分:
1. 直方图的计算与绘制
2. 直方图对比
3. 反向投影
4. 模板匹配

二:学习笔记

1. 关于图像的HSV格式

平常老是用RGB了解这个较少,参见:HSL和HSV色彩空间 , 如何通俗地解释色彩三要素:色相、明度、纯度? , 什么是色像?什么是饱和度?什么是色温?什么是色调呢? 。

2. 对比直方图的方法

有多种

3. 累积直方图

有时候根据需要我们也会用到累积直方图,或者水平直方图、竖直直方图等,知道就行。

4. 反向投影

这里主要使用了HSV中的H色相直方图,具体见书吧,写的还比较清楚。或者调试例程时,多用image watch插件看一看。

5. matchTemplate()函数

用的很广泛,最简单的目标匹配方法啦。其度量方式有很多种,官网type of the template matching operation ,这一点书中也有介绍。

6 . 本节函数清单

三:相关源码及解析

本章示例较多,示例列表:
1.绘制H-S直方图
2.绘制RGB三色直方图
3.直方图对比
4. 反向投影
5.模板匹配

1 . 绘制H-S直方图

源码:

#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到179float saturationRanges[] = { 0, 256 }; //定义饱和度的变化范围为0(黑、白、灰)到255(纯光谱颜色)const float* ranges[] = {hueRanges, saturationRanges};  //指向指针的数组,指针数组MatND dstHist;int channels[] = { 0, 1 };//calcHist函数中将计算第0通道和第1通道的直方图calcHist(&hsvImage, //输入的数组1,  //数组个数为1channels,  //通道索引Mat(),  //不使用掩膜dstHist,  //输出的目标直方图2,  //需要计算的直方图的维度为2histSize,  //存放每个维度的直方图尺寸的数组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;
}

素材:

效果图:

提示:

2 . 绘制RGB三色直方图

源码:

#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;
}

素材:

效果图:

提示:

3 . 直方图对比

源码:

#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:

效果图:

提示:

4 . 反向投影

源码:

#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);
}

素材:

效果图:


提示:

5 . 模板匹配

源码:

#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);
}

素材:


效果图:

提示:

《OpenCV3编程入门》学习笔记九:直方图与匹配相关推荐

  1. 原创 OpenCV3编程入门 学习笔记(总)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36163358/article/ ...

  2. OpenCV3编程入门 学习笔记(总)

    OpenCV3编程入门 学习笔记 2018.12.12-2018.12.29 此博客为在看过毛星云版<OpenCV3编程入门>后所总结的一本笔记,可供复习使用. 文章目录 OpenCV3编 ...

  3. Opencv3编程入门学习笔记(五)之通道分离(split)与合并(merge)

    若要对Opencv中(BGR)颜色通道进行单一处理,那必然会涉及到通道分离(split)与合并(merge).那么本篇博客笔者记录了两个方法的使用方法和案例.案例来源于<Opencv3编程入门学 ...

  4. Opencv3编程入门学习笔记(三)之访问图像像素的三种方法

    访问图像像素的三种方法:指针访问,迭代器访问,动态地址访问.访问最快的为指针访问,以下算法在几毫秒,但指针访问容易造成内存泄漏:其次为迭代器访问:最后为动态地址访问. 以下程序是根据<OpenC ...

  5. 【OpenCV3编程入门学习笔记】——第1章 邂逅OpenCV

    邂逅OpenCV 文章目录 邂逅OpenCV 前言 1.1 OpenCV周边概念认知 1.1.1 图像处理.计算机视觉与OpenCV 1.1.2 OpenCV概述 1.1.3 起源及发展 1.1.4 ...

  6. Opencv3编程入门学习笔记(四)之split通道分离Debug过程中0xC0000005内存访问冲突问题

    这是笔者学习<Opencv3编程入门>的第四篇博客,这篇博客主要是解决在Windows系统下VS 2013中Debug含有split分离通道色彩函数时报出的0xC0000005内存访问冲突 ...

  7. 【OpenCV3编程入门学习笔记】——第3章 HighGUI图形用户界面初步

    文章目录 前言 3.1 图形的载入.显示和输出到文件 3.1.1 OpenCV的命名空间 3.1.2 Mat类简析 3.1.3 图像的载入与显示概述 3.1.4 图像的载入:imread()函数 3. ...

  8. Opencv3编程入门学习笔记(二)之显式创建Mat对象

    以下总结是基于<Opencv3编程入门>一书4.1节总结的内容进行验证与总结,验证环境均为Windows10 ---VS2013 C++环境,验证Opencv3.0提供的开发包. 1. 方 ...

  9. 01.Java 编程入门学习笔记20210307

    Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...

  10. Python快速编程入门#学习笔记01# |第一章 :Python基础知识 (Python发展历程、常见的开发工具、import模块导入)

    全文目录 ==先导知识== 1 认识Python 1.1.1 Python的发展历程 1.1.2 Python语言的特点 2. Python解释器的安装与Python程序运行 1.2.1 安装Pyth ...

最新文章

  1. Transformers 研究指南
  2. ajax 与php页面取值,在同一页面中使用PHP和AJAX的最佳方法
  3. 簡單安裝軟件 GNU Linux
  4. POJ 3279(Fliptile)题解
  5. 摄像头poe供电原理_什么是POE供电,这种POE套装有什么优势呢?
  6. ROS探索总结(五)——创建简单的机器人模型smartcar
  7. android通过php判断用户是否注册,android - 判断Token是否有效
  8. 关于perl和shell的参数传递
  9. CAP 2.4版本发布,支持版本隔离特性
  10. 从java到C++入门
  11. 20145321 《Java程序设计》第4周学习总结
  12. 企业级及电子商务常见缩写
  13. Redis(RedisTemplate)使用string字符串
  14. mysql 23000_mysql – SQLSTATE [23000]:完整性约束违规:1452无法添加或更新子行:外键约束失败...
  15. sin查找表 matlab,FPGA利用查找表实现sin正弦函数
  16. 分布式协议与算法(一)Paxos 算法
  17. ASP.NETf发送邮件
  18. int 几个字节 java_java中int是几个字节
  19. mysql中筛选不重复值_MYSQL中筛选不重复记录值的示例
  20. 机械硬盘无法访问要怎么办啊

热门文章

  1. 【图像融合】基于matalb小波变换(加权平均法+局域能量+区域方差匹配)图像融合【含Matlab源码 1819期】
  2. 遗传算法python实现
  3. shapefile(.shp)空间数据格式详细说明
  4. Svn下载及安装(附带汉化包安装)
  5. 调节效应检验(一):线性回归分析
  6. 基于大数据的推荐算法综述
  7. B站 (哔哩哔哩) 泄露源码中的有趣片段(彩蛋)
  8. live2d_Live2D 性能优化
  9. nginx强制下载txt等文件
  10. 根据UE4官方文档实现一个FPS游戏