2018/10/20
1.最近一段时间可以说有点忙吧,一直在学习opencv3的基础内容,渐渐的也发现了很多好玩的事物,作为计算机开源视觉库,资源是及其丰富和充满奥秘的,记得和朋友说过,单纯调用一个库就像夹娃娃一样(并不是每一次都可以调用成功是吧,但是成功率或许会比真正的夹娃娃要高出不少),opencv看了也将近两个月,基础的知识也慢慢梳理了,会渐渐的发一些笔记吧!!!
2.直方图的简单介绍(一维)
2-1:直方图的简单介绍:
简单来说,直方图就是对数据统计的一种方法,描述的是对于像素强度的分布形式,通过自设的强度,来统计基于该强度值上的像素分布情况
2-2:直方图(一维)
下面为RGB三通道直方图的简单介绍
2-2-1:代码部分:
//实现三色直方图的绘制
//picture adress C:\\Users\\ASUS\\Pictures\\opencv_Pirture
//直方图 统计了每一个强度所拥有的像素个数
//通过给定的范围区间 实现不同的统计方式
#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
src = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\1.jpg");
int bins = 600;
int hist_size[] = { bins };//代表着全局范围 框的尺寸
float range[] = {0, 256 };//确定像素的范围 在这里是为了实现对0--255像素区间强度的描述
const float* ranges[] = {range};
MatND hist_r, hist_g, hist_b;//专门用来储存直方图
int channels_r[] = { 0 };//channel_red
calcHist(&src, 1, channels_r, Mat(), // do not use mask
hist_r, 1, hist_size, ranges,
true, // the histogram is uniform
false);
/*
FUNCTION DETAILS:
1.输入的数组集,需要有相同的深度
2.输入数组的个数(前面有几张图)
3.通道索引 数组名
4.操作掩码
5.输出目标(redhist) MatND
6.直方图的维度(在这里为1维)
7.直方图的尺寸 数组名
8.每一维数据的范围 数组名
9.直方图是否均匀
10.累计标识符 (默认为false)
*/
int channels_g[] = { 1 };//channel_green
calcHist(&src, 1, channels_g, Mat(), // do not use mask
hist_g, 1, hist_size, ranges,
true, // the histogram is uniform
false);
int channels_b[] = { 2 };//channel_blue
calcHist(&src, 1, channels_b, Mat(), // do not use mask
hist_b, 1, hist_size, ranges,
true, // the histogram is uniform
false);
double max_val_r, max_val_g, max_val_b;
minMaxLoc(hist_r, 0, &max_val_r, 0, 0);
minMaxLoc(hist_g, 0, &max_val_g, 0, 0);
minMaxLoc(hist_b, 0, &max_val_b, 0, 0);
/*FUNCTION DETAILS:
1.输入的单通道阵列
2.返回最小值指针
3.返回最大值指针
4.返回最小位置指针
5.返回最大位置指针
*/
int scale = 1;
int hist_height = 256;
Mat hist_img = Mat::zeros(hist_height, bins * 3, CV_8UC3);
for (int i = 0; i<bins; i++)
{
float bin_val_r = hist_r.at<float>(i);
float bin_val_g = hist_g.at<float>(i);
float bin_val_b = hist_b.at<float>(i);
int intensity_r = cvRound(bin_val_r*hist_height / max_val_r); //要绘制的高度
int intensity_g = cvRound(bin_val_g*hist_height / max_val_g); //要绘制的高度
int intensity_b = cvRound(bin_val_b*hist_height / max_val_b); //要绘制的高度
rectangle(hist_img, Point(i*scale, hist_height - 1),
Point((i + 1)*scale - 1, hist_height - intensity_r),
CV_RGB(255, 0, 0));
rectangle(hist_img, Point((i + bins)*scale, hist_height - 1),
Point((i + bins + 1)*scale - 1, hist_height - intensity_g),
CV_RGB(0, 255, 0));
rectangle(hist_img, Point((i + bins * 2)*scale, hist_height - 1),
Point((i + bins * 2 + 1)*scale - 1, hist_height - intensity_b),
CV_RGB(0, 0, 255));
}
imshow("Source", src);
imshow("RGB Histogram", hist_img);
while (waitKey(0) != 27);
return 0;
}
2-2-2:效果图
3.基于直方图的简单匹配方案
3-1:匹配方法
对于opencv3而言,比较常见的图像匹配方案是通过surf算法进行特征点匹配(不详细说明,有兴趣的大家可以自行百度),,但是说实话,比较难实现(虽然效果很好),在opencv3中提供了一个函数compareHist()用于直方图的匹配,通过对函数的返回值的对比,实现对图像是否匹配的判断
3-2:compareHist(srcImage,dstImage,compare_method)
srcImage:原图
dstImage:输出图
compare_method:这个值以int形式出现,在opencv3中有着较好的封装,一般来说有四种方法
0:Correlation(相关) 反馈的数值越大 说明越匹配 归一化后完全匹配为1 完全不匹配为-1 随机为0
1:Chi_Square(卡方)完全匹配为0 不完全匹配为任意值
2:Intersection(直方图相较)数值越高代表着匹配值越高,数值越低代表着匹配值越低
3.Bhattacharyya(距离) 数值越低越好,越高代表图像越不匹配,完全匹配为0 不匹配为1
3-3:设计思路:构建直方图并且归一化,最后比较compareHist()的返回值(使用原图和原图比较以及原图和效果图比较,通过一个逻辑判断是否是相同的图)
(注:逻辑阈值为自设 可以自行设计为百分数参数或者任意逻辑输出)
代码如下:(在这里使用了方法2)
//直方图匹配
//进入hsv空间进行匹配
//C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\base.jpg
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
//【0】改变console字体颜色
system("color 2F");
//【1】声明储存基准图像和另外两张对比图像的矩阵( RGB 和 HSV )
Mat srcImage_base, hsvImage_base;
Mat srcImage_test1, hsvImage_test1;
Mat srcImage_test2, hsvImage_test2;
Mat hsvImage_halfDown;//半身图
//【2】载入基准图像(srcImage_base) 和两张测试图像srcImage_test1、srcImage_test2,并显示
srcImage_base = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\base.jpg", 1);//基准图
srcImage_test1 = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\text.jpg", 1);//测试图1
imshow("基准图像", srcImage_base);
imshow("测试图像1", srcImage_test1);
// 【3】将图像由BGR色彩空间转换到 HSV色彩空间
cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
//【4】创建包含基准图像下半部的半身图像(HSV格式)
//【5】初始化计算直方图需要的实参
// 对hue通道使用30个bin,对saturatoin通道使用32个bin
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue的取值范围从0到256, saturation取值范围从0到180
float h_ranges[] = { 0, 256 };
float s_ranges[] = { 0, 180 };
const float* ranges[] = { h_ranges, s_ranges };
// 使用第0和第1通道
int channels[] = { 0, 1 };
// 【6】创建储存直方图的 MatND 类的实例:
MatND baseHist;
MatND testHist1;
// 【7】计算基准图像,测试图像
calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges, true, false);
normalize(baseHist, baseHist, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges, true, false);
normalize(testHist1, testHist1, 0, 1, NORM_MINMAX, -1, Mat());
int compare_method = 1;
double base_base = compareHist(baseHist, baseHist, 2);
double base_text1 = compareHist(baseHist, testHist1, 2);
//printf("基准值为%lf\n", base_base);
cout << "原图基准值为" << base_base << endl;
//printf("匹配值为%lf\n", base_text1);
cout << "比较值为" << base_text1 << endl;
if (base_base == base_text1)
{
cout << "图像匹配成功" << endl;
}
else
{
cout << "图像匹配失败" << endl;
}
cout << "检测结束" << endl;
waitKey(0);
return 0;
}
效果图:
注:该内容基于浅墨大神的opencv3编程入门,学完了直方图部分,基于书籍谈一下自己的认识和看法,如果有纰漏,请大家及时提出,小白一枚,希望大家多多指教!!!