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編程入門,學完了直方圖部分,基於書籍談一下自己的認識和看法,如果有紕漏,請大家及時提出,小白一枚,希望大家多多指教!!!