圖像反向投影的最終目的是獲取ROI然后實現對ROI區域的標注、識別、測量等圖像處理與分析,是計算機視覺與人工智能的常見方法之一。圖像反向投影通常是彩色圖像投影效果會比灰度圖像效果要好,原因在于彩色圖像帶有更多對象細節信息,在反向投影的時候更加容易判斷、而轉為灰度圖像會導致這些細節信息丟失、從而導致分割失敗。最常見的是基于圖像直方圖特征的反向投影。我們這里介紹一種跟直方圖反向投影不一樣的彩色圖像反向投影方法,通過基于高斯的概率分布公式(PDF)估算,反向投影得到對象區域,該方法也可以看做最簡單的圖像分割方法。缺點是對象顏色光照改變和尺度改變不具備不變性特征。所以需要在光照度穩定情況下成像采集圖像數據。 在這種情況下使用的高斯概率密度公式為:

輸入模型M,對M的每個像素點(R,G,B)計算I=R+G+B r=R/I, g=G/I, b=B/I
根據得到權重比例值,計算得到對應的均值 與標準方差
對輸入圖像的每個像素點計算根據高斯公式計算P(r)與P(g)的乘積
歸一化之后輸出結果,即為最終基于高斯PDF的反向投影圖像
首先加載模型圖像與測試圖像
根據模型圖像計算得到每個通道對應的均值與標準方差參數
根據參數方差計算每個像素點的PDF值
歸一化概率分布圖像-即為反向投影圖像,顯示
根據Mask得到最終顏色模型對象分割
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
? ?// 加載模型圖像與測試圖像
? ?Mat src = imread("D:/gloomyfish/gc_test.png");
? ?Mat model = imread("D:/gloomyfish/gm.png");
? ?if (src.empty() || model.empty()) {
? ? ? ?printf("could not load image...\n");
? ? ? ?return -1;
? ?}
? ?imshow("input image", src);
? ?// 對每個通道 計算高斯PDF的參數
? ?// 有一個通道不計算,是因為它可以通過1-r-g得到
? ?// 無需再計算
? ?Mat R = Mat::zeros(model.size(), CV_32FC1);
? ?Mat G = Mat::zeros(model.size(), CV_32FC1);
? ?int r = 0, g = 0, b = 0;
? ?float sum = 0;
? ?for (int row = 0; row < model.rows; row++) {
? ? ? ?uchar* current = model.ptr(row);
? ? ? ?for (int col = 0; col < model.cols; col++) {
? ? ? ? ? ?b = *current++;
? ? ? ? ? ?g = *current++;
? ? ? ? ? ?r = *current++;
? ? ? ? ? ?sum = b + g + r;
? ? ? ? ? ?R.at(row, col) = r / sum;
? ? ? ? ? ?G.at(row, col) = g / sum;
? ? ? ?}
? ?}
? ?// 計算均值與標準方差
? ?Mat mean, stddev;
? ?double mr, devr;
? ?double mg, devg;
? ?meanStdDev(R, mean, stddev);
? ?mr = mean.at(0, 0);
? ?devr = mean.at(0, 0);
? ?meanStdDev(G, mean, stddev);
? ?mg = mean.at(0, 0);
? ?devg = mean.at(0, 0);
? ?int width = src.cols;
? ?int height = src.rows;
? ?// 反向投影
? ?float pr = 0, pg = 0;
? ?Mat result = Mat::zeros(src.size(), CV_32FC1);
? ?for (int row = 0; row < height; row++) {
? ? ? ?uchar* currentRow = src.ptr(row);
? ? ? ?for (int col = 0; col < width; col++) {
? ? ? ? ? ?b = *currentRow++;
? ? ? ? ? ?g = *currentRow++;
? ? ? ? ? ?r = *currentRow++;
? ? ? ? ? ?sum = b + g + r;
? ? ? ? ? ?float red = r / sum;
? ? ? ? ? ?float green = g / sum;
? ? ? ? ? ?pr = (1 / (devr*sqrt(2 * CV_PI)))*exp(-(pow((red - mr), 2)) / (2 * pow(devr, 2)));
? ? ? ? ? ?pg = (1 / (devg*sqrt(2 * CV_PI)))*exp(-(pow((green - mg),2)) / (2 * pow(devg, 2)));
? ? ? ? ? ?sum = pr*pg;
? ? ? ? ? ?result.at(row, col) = sum;
? ? ? ?}
? ?}
? ?// 歸一化顯示高斯反向投影
? ?Mat img(src.size(), CV_8UC1);
? ?normalize(result, result, 0, 255, NORM_MINMAX);
? ?result.convertTo(img, CV_8U);
? ?Mat segmentation;
? ?src.copyTo(segmentation, img);
? ?// 顯示
? ?imshow("backprojection demo", img);
? ?imshow("segmentation demo", segmentation);
? ?waitKey(0);
? ?return 0;
}
藍色矩形框為模型,整個圖像為測試圖像

反向投影結果

分割提取結果

大家看了這個例子總是有點怪怪的,總會想起點什么,如果你能想起點什么的話就是GMM,高斯混合模型,高斯混合模型正是在此基礎上進一步演化而來。
治療對未來焦慮的良藥就在今天你自己的所為


推薦閱讀
OpenCV4.8+YOLOv8對象檢測C++推理演示
ZXING+OpenCV打造開源條碼檢測應用
攻略 | 學習深度學習只需要三個月的好方法
三行代碼實現 TensorRT8.6 C++ 深度學習模型部署
實戰 | YOLOv8+OpenCV 實現DM碼定位檢測與解析
對象檢測邊界框損失 – 從IOU到ProbIOU
初學者必看 | 學習深度學習的五個誤區
