OpenCV中的反向投影(21)

1 反向投影

如果一幅图像的区域中显示的是一种结构纹理或者一个独特的物体,那么这个区域的置方图可以看作一个概率函数,其表现形式是某个像素属于该纹理或物体的概率。
反向投影:是一种记录给定图像中的像素点如何适应直方图模型像素分布方式的一种方法。简单的讲,就是计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法。

1.1 反向投影的工作原理

使用模型直方图来检测测试图像中的区域,检测步骤:
(1)对测试图像中的每个像素(p(i, j)),获取色调数据并找到该色调 ( h i , j , s i , j ) (h_{i,j}, s_{i,j}) (hi,j,si,j)在直方图中的bin的位置。
(2)查找模型直方图对应的bin的数值。
(3)将此数值存储在新的反射投影图像中。也可以归一化直方图数值到0-255范围,这样可以直接显示反射投影图像(单通道图像)。
(4)通过对测试图像中的每个像素采用以上步骤,可以得到最终的反射投影图像。
(5)使用统计学的语言进行分析。反向投影中存储的数值代表了测试图像中该像素属于某特殊区域的概率。

1.2 反向投影的作用

用于在输入图像中查找特定图像最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。

1.3 计算反向投影:calcBackProject()函数

calcBackProject()函数用来计算直方图的反向投影。
void calcBackProject( const Mat* image, int nimages, const int* channels, InputArray hist, OutputArray backPorject, const float** ranges, double scale = 1, bool uniform=true)

  • 参数一:const Mat* images 输入的数组;
  • 参数二:nimages, 输入数组的个数,也就是第一个参数中存放了多少张“图像”,有几个原数组;
  • 参数三:需要统计的通道(dim)索引。第一个数组通道从0到iamges[0].channels()-1, 而第二个数组通道从images[0].channels()计算到images[0].channels()+images[1].channels()-1。
  • 参数四:输入的直方图;
  • 参数五:目标反像投影阵列,需为单通道,并且和image[0]有相同的大小和深度。
  • 参数六:ranges 表示每一个维度数组的每一维的边界阵列,可以理解为每一维数值的取值范围。
  • 参数七:scale,有默认值1,输出的方向投影可选的缩放因子。
  • 参数八:指示直方图是否均匀的标志符,默认true.
1.4 通道复制:mixChannels()函数

输入参数复制某通道到输出参数特定的通道中。
void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int * fromTo, size_t npairs)

  • 参数一:输入的数组,所有的矩阵必须有相同的尺寸和深度;
  • 参数二:第一个参数src输入的阵列数;
  • 参数三:输出的数组,所有阵列必须被初始化,且大小和深度需和src[0]相同;
  • 参数四:参数三dst输入的阵列数;
  • 参数五:对指定的通道进行复制的数组索引;
  • 参数六:第五个参数的索引数;

或着
void mixChannels(const vector & src, vector& dst, const int * fromTo, size_t npairs)

示例:将一个4通道的RGBA图像转化为3通道BGR和一个单通道Alpha通道的图像。

Mat rgba(100, 100, CV_8UC4, Scalar(1,2,3,4));
Mat bgr(rgba.rows, rgba.cols, CV_8UC3);
Mat alpha(rgba.rows, rgba.cols, CV_8UC1);

//组成矩阵数组来进行操作
Mat out[] = {bgr, alpha};
//rgba[0]->bgr[2], rgba[1]->bgr[1],rgba[2]->bgr[0], rgba[3]->alpha[0]
int from_to[] = {0,2, 1,1, 2,0, 3,3};
mixChannels(&rgba, 1, out, 2, from_to, 4);

综合示例:反向投影

#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;

#define WINDOW_NAME1 "原始图"
Mat g_srcImage, g_hsvImage,g_hueImage;
int g_bins = 30; // 直方图组距

void on_BinChange(int , void*);
int main()
{
    //读取原图像,并转换到HSV空间
    g_srcImage = imread("../1.jpg", 1);
    if(!g_srcImage.data) {
        printf("获取图像路径失败!\n");
        return false;
    }

    cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);

    //分离hue色调通道
    g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
    int ch[] = {0, 0};

    mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);

    //创建Trackbar来输入bin的数目
    namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
    createTrackbar("色调组距", WINDOW_NAME1, &g_bins, 180, on_BinChange);

    on_BinChange(0, 0);

    imshow(WINDOW_NAME1, g_srcImage);

    // waitKey(0);
    while (char (waitKey(0)) != 'q'){}
    
    return 0;
}

void on_BinChange(int , void*)
{
    //准备参数
    Mat hist;
    int histSize = MAX(g_bins, 2);
    float hue_range[] = {0, 180};
    const float* ranges = {hue_range};

    //计算直方图并归一化
    calcHist(&g_hueImage, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
    normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());

    //计算反向投影
    Mat backProject;
    calcBackProject(&g_hueImage, 1, 0, hist, backProject, &ranges, 1, true);

    imshow("反向投影", backProject);

    //绘制直方图的参数准备
    int w = 300, h = 400;
    int bin_w = cvRound((double) w / histSize);
    Mat histImage = Mat::zeros(w, h, CV_8UC3);

    //绘制直方图
    for(int i=0; i < g_bins; i++)
    {
        rectangle(histImage, Point(i * bin_w, h), Point((i + 1) * bin_w, h - cvRound(hist.at<float>(i) * h/255.0)), Scalar(100, 123, 255), -1);

        imshow("直方图窗口", histImage);
    }
}

实现效果:
OpenCV中的反向投影(21)_第1张图片

你可能感兴趣的:(opencv学习,opencv,计算机视觉,图像处理)