1 叭莫、反向投影
反向投影是反映直方圖模型在目標(biāo)圖像中的分布情況
簡(jiǎn)單點(diǎn)說就是用直方圖模型去目標(biāo)圖像中尋找是否有相似的對(duì)象匿辩。通常用HSV色彩空間的HS兩個(gè)通道直方圖模型
2 、步驟
1.建立直方圖模型
2.計(jì)算待測(cè)圖像直方圖并映射到模型中
3.從模型反向計(jì)算生成圖像
3 、代碼流程
加載圖片imread
將圖像從RGB色彩空間轉(zhuǎn)換到HSV色彩空間cvtColor
計(jì)算直方圖和歸一化calcHist與normalize
Mat與MatND其中Mat表示二維數(shù)組鄙才,MatND表示三維或者多維數(shù)據(jù)佩番,此處均可以用Mat表示杆勇。
計(jì)算反向投影圖像 - calcBackProject
4呕缭、理解
直方圖運(yùn)算是統(tǒng)計(jì)每個(gè)灰度值對(duì)應(yīng)的像素個(gè)數(shù),而反向投影則是將像素個(gè)數(shù)回送到該像素個(gè)數(shù)對(duì)應(yīng)灰度區(qū)間的像素位置
image.png
將灰度值劃分為如下四個(gè)區(qū)間:[0,2] [3,5] [6,7] [8,10]很容易得到這個(gè)圖像矩陣的直方圖hist= 4 4 6 2
最后計(jì)算反向投影筒愚,原圖像中坐標(biāo)為(0,0)的灰度值為1赴蝇,1位于區(qū)間[0,2] 中,區(qū)間[0,2] 對(duì)應(yīng)的直方圖值為4巢掺,所以反向投影矩陣中中坐標(biāo)為(0,0)的值記為4句伶。以此類推芍耘,得到反向投影后的矩陣:
image.png
反向投影是基于直方圖的逆運(yùn)算,而直方圖則反應(yīng)了圖像的色彩(亮度)特征熄阻,當(dāng)兩幅相似的圖像僅發(fā)生位置的變化而色彩(光線)幾乎不變時(shí),對(duì)應(yīng)的兩幅直方圖相似度非常高倔约。
直方圖只是得到了特征秃殉,反向投影則是將特征“反映”到圖像上,對(duì)于物體特征識(shí)別和分割有著很大的作用
4 浸剩、整體代碼測(cè)試
mixChannels()函數(shù)用于將輸入數(shù)組的指定通道復(fù)制到輸出數(shù)組的指定通道钾军。
void mixChannels(
const Mat* src, //輸入數(shù)組或向量矩陣,所有矩陣的大小和深度必須相同。
size_t nsrcs, //矩陣的數(shù)量
Mat* dst, //輸出數(shù)組或矩陣向量,大小和
深度必須與src[0]相同
size_t ndsts,//矩陣的數(shù)量
const int* fromTo,//指定被復(fù)制通道與要復(fù)制到的位置組成的索引對(duì)
size_t npairs //fromTo中索引對(duì)的數(shù)目
);
calcBackProject
const Mat* images:輸入圖像绢要,圖像深度必須位CV_8U,CV_16U或CV_32F中的一種吏恭,尺寸相同,每一幅圖像都可以有任意的通道數(shù)
int nimages:輸入圖像的數(shù)量
const int* channels:用于計(jì)算反向投影的通道列表重罪,通道數(shù)必須與直方圖維度相匹配樱哼,第一個(gè)數(shù)組的通道是從0到image[0].channels()-1,第二個(gè)數(shù)組通道從圖像image[0].channels()到image[0].channels()+image[1].channels()-1計(jì)數(shù)
InputArray hist:輸入的直方圖,直方圖的bin可以是密集(dense)或稀疏(sparse)
OutputArray backProject:目標(biāo)反向投影輸出圖像剿配,是一個(gè)單通道圖像搅幅,與原圖像有相同的尺寸和深度
const float ranges**:直方圖中每個(gè)維度bin的取值范圍
double scale=1:可選輸出反向投影的比例因子
bool uniform=true:直方圖是否均勻分布(uniform)的標(biāo)識(shí)符,有默認(rèn)值true
C++: void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )
參數(shù)詳解:
onst Mat* images:輸入圖像
int nimages:輸入圖像的個(gè)數(shù)
const int* channels:需要統(tǒng)計(jì)直方圖的第幾通道
InputArray mask:掩膜呼胚,茄唐,計(jì)算掩膜內(nèi)的直方圖 ...Mat()
OutputArray hist:輸出的直方圖數(shù)組
int dims:需要統(tǒng)計(jì)直方圖通道的個(gè)數(shù)
const int* histSize:指的是直方圖分成多少個(gè)區(qū)間,就是 bin的個(gè)數(shù)
const float** ranges: 統(tǒng)計(jì)像素值得區(qū)間
bool uniform=true::是否對(duì)得到的直方圖數(shù)組進(jìn)行歸一化處理
bool accumulate=false:在多個(gè)圖像時(shí)蝇更,是否累計(jì)計(jì)算像素值得個(gè)數(shù)
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <stdio.h>
using namespace std;
using namespace cv;
//定義全局變量
Mat srcImage, hsvImage, hueImage;
const int hueBinMaxValue = 180;
int hueBinValue = 25;
//聲明回調(diào)函數(shù)
void Hist_and_Backprojection(int, void*);
int main()
{
srcImage = imread("D:\\pic/z2.jpg");
//判斷圖像是否加載成功
if (srcImage.empty())
{
cout << "圖像加載失敗" << endl;
return -1;
}
else
cout << "圖像加載成功..." << endl << endl;
//將圖像轉(zhuǎn)化為HSV圖像
cvtColor(srcImage, hsvImage, CV_BGR2HSV);
//只使用圖像的H參數(shù)
hueImage.create(hsvImage.size(), hsvImage.depth());
int ch[] = { 0,0 };
mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);
//軌跡條參數(shù)設(shè)置
//char trackBarName[20];
//sprintf(trackBarName, "Hue bin:%d", hueBinMaxValue);
namedWindow("SourceImage", WINDOW_AUTOSIZE);
//創(chuàng)建軌跡條并調(diào)用回調(diào)函數(shù)
createTrackbar("bar", "SourceImage", &hueBinValue, hueBinMaxValue, Hist_and_Backprojection);
Hist_and_Backprojection(hueBinValue, 0);
imshow("SourceImage", srcImage);
waitKey(0);
return 0;
}
void Hist_and_Backprojection(int, void*)
{
MatND hist;
int histsize = MAX(hueBinValue, 2);
float hue_range[] = { 0,180 };
const float* ranges = { hue_range };
//計(jì)算圖像直方圖并歸一化處理
calcHist(&hueImage, 1, 0, Mat(), hist, 1, &histsize, &ranges, true, false);
normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
//獲取反向投影
MatND backProjection;
calcBackProject(&hueImage, 1, 0, hist, backProjection, &ranges, 1, true);
//輸出反向投影
imshow("BackProjection", backProjection);
//繪制圖像直方圖
int w = 400;
int h = 400;
int bin_w = cvRound((double)w / histsize);
Mat histImage = Mat::zeros(w, h, CV_8UC3);
for (int i = 0; i < hueBinValue; i++)
{
rectangle(histImage, Point(i * bin_w, h), Point((i + 1) * bin_w, h - cvRound(hist.at<float>(i) * h / 255.0)), Scalar(0, 0, 255), -1);
}
imshow("HistImage", histImage);
}
image.png