1.25【OpenCV圖像處理】直方圖反向投影

反向投影calcBackProject()、抽取通道mixChannels()、繪製直方圖rectangle()

1.25.1 反向投影(Back Projection)

反向投影原理:反映直方圖模型在目標圖像中的分布情況。簡單點說就是用直方圖模型去目標圖像中尋找是否有相似的對象。(就是首先計算某一特徵的直方圖模型,然後使用模型去尋找圖像中存在的該特徵)

通常用HSV色彩空間的H S兩個通道直方圖模型做反向投影。

其他領域反嚮應用:地震震源檢測時,震源波向四周傳播,兩個設備檢測到後反向發射,兩個反向的交點就是震源。

例如,你有一個膚色直方圖 ( Hue-Saturation 直方圖 ),你可以用它來尋找圖像中的膚色區域:

我們要做的就是使用模型直方圖 (代表手掌的皮膚色調) 來檢測測試圖像中的皮膚區域。以下是檢測的步驟:

  1. 對測試圖像中的每個像素,獲取色調數據並找到該色調在直方圖中的bin的位置。
  2. 查詢模型直方圖中對應的bin 並讀取該bin的數值。
  3. 將此數值儲存在新的圖像中(BackProjection)。 你也可以先歸一化模型直方圖 ,這樣測試圖像的輸出就可以在屏幕顯示了。
  4. 通過對測試圖像中的每個像素採用以上步驟,我們得到了下面的 BackProjection結果圖。
  5. 使用統計學的語言, BackProjection中儲存的數值代表了測試圖像中該像素屬於皮膚區域的概率 。越亮起的區域是皮膚區域的概率越大,而更暗的區域則表示更低的概率(注意手掌內部和邊緣的陰影影響了檢測的精度)。

反向投影 – 步驟:

1.建立直方圖模型

2.計算待測圖像直方圖並映射到模型中

3.從模型反向計算生成圖像

為什麼像素點的值表示的是概率?meanshift演算法里用到的反向投影圖就是概率圖。什麼又是反向投影圖呢?舉個例子:

(1)例如灰度圖像如下

Image=

0 1 2 3

4 5 6 7

8 9 10 11

8 9 14 15

(2)該灰度圖的直方圖為(bin指定的區間為[0,4),[4,7),[7,12),[12,16))

Histogram=

4 3 7 2

(3)反向投影圖

Back_Projection=

4 4 4 4

3 3 3 7

7 7 7 7

7 7 2 2

可見,反向投影圖就是反應了顏色分布的概率圖。

1.25.2 相關API及實現步驟

簡單計算同一圖像的Hue通道直方圖和反向投影圖:

1)將圖像從RGB色彩空間轉換到HSV色彩空間 - cvtColor()

cvtColor(src, hsv, CV_BGR2HSV); //轉為HSV

2)抽取拷貝HSV圖像的0通道(hue)- mixChannels()

mixChannels(&hsv, 1, &hue, 1, nchannels, 1); //抽取HSV圖像的0通道拷貝到hue:輸入圖像指針,輸入圖像數,輸出圖像指針,輸出圖像數,通道索引對,通道索引對的數目

3)計算直方圖和歸一化 - calcHist()與normalize()

/*計算直方圖並歸一化*/nfloat range[] = { 0, 180 }; //H取值範圍nconst float *histRanges = { range };nMat h_hist;ncalcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false); //計算直方圖nnormalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat()); //歸一化n

4)計算反向投影圖像 - calcBackProject()

calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true); //反向投影:輸入圖像指針,輸入圖像數量,通道數,直方圖,輸出,值域,比例尺度

5)繪製直方圖 - rectangle()矩形

/*繪製直方圖*/nint hist_h = 400;nint hist_w = 400;nMat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));nint bin_w = (hist_w / bins); //bin的寬度nfor (int i = 1; i < bins; i++) {n rectangle(histImage, //畫矩形nPoint((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1) * (400 / 255)))), //cvRound將浮點型轉化為整形,h_hist輸出是0-255的所以要除以255歸一到0-1之間,再乘400n//Point(i*bin_w, (hist_h - cvRound(h_hist.at<float>(i) * (400 / 255)))),nPoint(i*bin_w, hist_h),nScalar(0, 0, 255), -1); //-1是填充矩形n}nimshow("Histogram", histImage); //顯示1維 Hue 直方圖n

注意:Mat與MatND,其中Mat表示二維數組,MatND表示三維或者多維數據,此處均可以用Mat表示。


完整程序:

/*1.25 直方圖反向投影 - 計算同一圖像的Hue通道直方圖和反向投影圖*/n#include <opencv2/opencv.hpp>n#include <iostream>n#include <math.h>nnusing namespace std;nusing namespace cv;nnMat src; Mat hsv; Mat hue;nint bins = 12;nvoid Hist_And_Backprojection(int, void*);nint main(int argc, char** argv) {n src = imread("E:/OpenCV/testimage/t3.jpg");nif (src.empty()) {n printf("could not load image...n");nreturn -1;n }nconst char* window_image = "input image";n namedWindow(window_image, CV_WINDOW_NORMAL);n imshow(window_image, src);nn/*轉為HSV*/n cvtColor(src, hsv, CV_BGR2HSV); //轉為HSVnn/*抽取拷貝HSV圖像的0通道(hue)*/n hue.create(hsv.size(), hsv.depth()); //創建相同大小深度的hue通道空圖像nint nchannels[] = { 0, 0 }; //通道索引對的數組,&hsv圖像的Hue(0)通道被拷貝到&hue圖像(單通道)的0通道。n mixChannels(&hsv, 1, &hue, 1, nchannels, 1); //抽取HSV圖像的0通道拷貝到hue:輸入圖像指針,輸入圖像數,輸出圖像指針,輸出圖像數,通道索引對,通道索引對的數目nn createTrackbar("Histogram Bins:", window_image, &bins, 180, Hist_And_Backprojection); // 跟蹤條,改變bin的數目n Hist_And_Backprojection(0, 0);nn waitKey(0);nreturn 0;n}nnvoid Hist_And_Backprojection(int, void*) {n/*計算直方圖並歸一化*/nfloat range[] = { 0, 180 }; //H取值範圍nconst float *histRanges = { range };nMat h_hist;n calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false); //計算直方圖n normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat()); //歸一化nn /*反向投影*/nMat backPrjImage;n calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true); //反向投影:輸入圖像指針,輸入圖像數量,通道數,直方圖,輸出,值域,比例尺度n imshow("BackProject", backPrjImage); //顯示反向投影圖nn /*繪製直方圖*/nint hist_h = 400;nint hist_w = 400;nMat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));nint bin_w = (hist_w / bins); //bin的寬度nfor (int i = 1; i < bins; i++) {nrectangle(histImage, //畫矩形nPoint((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1) * (400 / 255)))), //cvRound將浮點型轉化為整形,h_hist輸出是0-255的所以要除以255歸一到0-1之間,再乘400n//Point(i*bin_w, (hist_h - cvRound(h_hist.at<float>(i) * (400 / 255)))),nPoint(i*bin_w, hist_h),nScalar(0, 0, 255), -1); //-1是填充矩形n }n imshow("Histogram", histImage); //顯示1維 Hue 直方圖nnreturn;n}n

運行結果:

推薦閱讀:

OpenCV檢測篇(一)——貓臉檢測
【小林的OpenCV基礎課 3】視頻淺淺談
OpenCV AdaBoost + Haar目標檢測技術內幕
OpenCV玩九宮格數獨(零)——預告篇

TAG:OpenCV | 图像处理 | 计算机视觉 |