OpenCV之图像处理(二十七) 直方图反向投影(Back Projection)

反向投影是反映直方图模型在目标图像中的分布情况(此直方图模型是由目标图像计算生成的)
    简单点说就是用直方图模型去目标图像中寻找是否有相似的对象。通常用HSV色彩空间的HS两个通道直方图模型

反向投影 – 步骤
    1.建立直方图模型
    2.计算待测图像直方图并映射到模型中
    3.从模型反向计算生成图像

    加载图片imread
    将图像从RGB色彩空间转换到HSV色彩空间cvtColor
    计算直方图和归一化calcHist与normalize
    Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示。
    计算反向投影图像 - calcBackProject

代码

    #include "../common/common.hpp"

    static Mat src, hsv, hue;
    static int bins = 12;
    static char title[] = "inputImage";
    static int maxHue = 180; // 也可取 360,对应的 bins 取24

    static void histAndBackProjection(int, void *);

    void main(int argc, char** argv)
    {
        src = imread(getCVImagesPath("images/t1.jpg"), IMREAD_COLOR);

        cvtColor(src, hsv, CV_BGR2HSV);
        printf("type=%d, depth=%d, CV_8UC1=%d\n", hsv.type(), hsv.depth(), CV_8UC1); // type=16, depth=0, CV_8UC1=0
        // 色调在HSV颜色空间定义取值为0°到360°,实际在OpenCV中取值为0-180 , 所以mat.type用 CV_8UC1 ?
        hue.create(hsv.size(), CV_8UC1); // 这里要传深度,传type会报错
        int nchannels[] = { 0, 0 };
        /*  // 将输入数组的指定通道复制到输出数组的指定通道
            mixChannels( 
                const Mat* src, //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。
                size_t nsrcs, //矩阵的数量
                Mat* dst, //输出数组或矩阵向量,大小和深度必须与src相同
                size_t ndsts,//矩阵的数量
                const int* fromTo,//指定被复制通道与要复制到的位置组成的索引对
                size_t npairs //fromTo中索引对的数目
            );
        */
        mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
        imshow("hue", hue);

        namedWindow(title, CV_WINDOW_AUTOSIZE);
        createTrackbar("Histogram Bins:", title, &bins, maxHue, histAndBackProjection);
        histAndBackProjection(0, 0);
        imshow(title, src);

        waitKey(0);
    }

    static void histAndBackProjection(int, void *)
    {
        if (bins == 0) return; // 为0的时候,计算会报错
        float range[] = { 0, maxHue };
        const float * histRanges = { range };
        Mat h_hist;
        calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
        normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

        Mat backProImage;
        /*
            calcBackProject ( // 反向投影
                const Mat * images, // 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数 
                int nimages, // 输入图像的数量
                const int * channels, // 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,
                                                    第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数
                InputArray hist, // 输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
                OutputArray backProject, // 目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
                const float ** ranges, // 直方图中每个维度bin的取值范围
                double scale = 1, // 可选输出反向投影的比例因子
                bool uniform = true // 直方图是否均匀分布(uniform)的标识符,默认值true
            )
        */
        calcBackProject(&hue, 1, 0, h_hist, backProImage, &histRanges, 1, true);// 0表示hue的第0通道
        imshow("backProImage", backProImage);

        //绘制直方图
        int hist_cols = 400;
        int hist_rows = 400;
        int bin_w = hist_rows / bins;
        Mat histImage(hist_rows, hist_cols, CV_8UC3, Scalar(0, 0, 0));
        for (int i = 1; i < bins; i++)
        {
            rectangle(histImage, Point((i - 1)*bin_w, (hist_cols - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
                Point(i*bin_w, hist_cols), Scalar(0, 0, 255), -1);//-1表示填充矩形
        }
        imshow("histImage27", histImage);
    }

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81178582