当前位置:   article > 正文

《OpenCV3编程入门》学习笔记九:直方图与匹配_opencv3编程入门中绘制直方图的错误

opencv3编程入门中绘制直方图的错误

一:内容介绍

本节主要介绍OpenCV的imgproc模块的直方图与模板匹配部分:
1. 直方图的计算与绘制
2. 直方图对比
3. 反向投影
4. 模板匹配

二:学习笔记

1. 关于图像的HSV格式

平常老是用RGB了解这个较少,参见:HSL和HSV色彩空间如何通俗地解释色彩三要素:色相、明度、纯度?什么是色像?什么是饱和度?什么是色温?什么是色调呢?

2. 对比直方图的方法

有多种
这里写图片描述

3. 累积直方图

有时候根据需要我们也会用到累积直方图,或者水平直方图、竖直直方图等,知道就行。

4. 反向投影

这里主要使用了HSV中的H色相直方图,具体见书吧,写的还比较清楚。或者调试例程时,多用image watch插件看一看。

5. matchTemplate()函数

用的很广泛,最简单的目标匹配方法啦。其度量方式有很多种,官网type of the template matching operation ,这一点书中也有介绍。

6 . 本节函数清单

这里写图片描述

三:相关源码及解析

本章示例较多,示例列表:
1.绘制H-S直方图
2.绘制RGB三色直方图
3.直方图对比
4. 反向投影
5.模板匹配

1 . 绘制H-S直方图

源码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat srcImage, hsvImage;
    srcImage = imread("poster_cup.jpg");
    cvtColor(srcImage, hsvImage, COLOR_BGR2HSV);

    int hueBinNum = 30;  //色调的直方图直条数量
    int saturationBinNum = 32;  //饱和度的直方图直条数量
    int histSize[] = { hueBinNum, saturationBinNum };
    float hueRanges[] = {0, 180}; //色相的变化范围为0到179
    float saturationRanges[] = { 0, 256 }; //定义饱和度的变化范围为0(黑、白、灰)到255(纯光谱颜色)
    const float* ranges[] = {hueRanges, saturationRanges};  //指向指针的数组,指针数组
    MatND dstHist;
    int channels[] = { 0, 1 };//calcHist函数中将计算第0通道和第1通道的直方图

    calcHist(&hsvImage, //输入的数组
        1,  //数组个数为1
        channels,  //通道索引
        Mat(),  //不使用掩膜
        dstHist,  //输出的目标直方图
        2,  //需要计算的直方图的维度为2
        histSize,  //存放每个维度的直方图尺寸的数组
        ranges //每一维数值的取值范围数组
        );

    double maxValue = 0;  //最大值
    minMaxLoc(dstHist, 0, &maxValue, 0, 0);  //查找数组和子数组的全局最大值存入maxValue中
    int scale = 10;
    Mat histImg = Mat::zeros(saturationBinNum*scale, hueBinNum*scale, CV_8UC3);
    for (int hue = 0; hue < hueBinNum; hue++)  //双层循环,进行直方图绘制
        for (int saturation = 0; saturation < saturationBinNum; saturation++) {
            float binValue = dstHist.at<float>(hue, saturation); //直方图直条的值
            int intensity = cvRound(binValue*255/maxValue);  //强度,归一化到0-255之间
            rectangle(histImg, Point(hue*scale, saturation*scale), Point((hue+1)*scale-1, (saturation+1)*scale-1), Scalar::all(intensity), FILLED); //绘制
        }
    imshow("【素材图】", srcImage);
    imshow("【H-S 直方图】", histImg);
    while (waitKey(8)!=27);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

素材:
这里写图片描述
效果图:
这里写图片描述
提示:

2 . 绘制RGB三色直方图

源码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

int main() {
    Mat srcImage = imread("poster_building_1.jpg");
//  Mat srcImage(200, 200, CV_8UC3, Scalar(50, 100, 150));
    imshow("【素材图】", srcImage);
    int bins = 256;
    int hist_size[] = { bins };
    float range[] = { 0, 256 };
    const float* ranges[] = { range };  //指针数组
    MatND redHist, greenHist, blueHist;
    //红色分量直方图的计算(OpenCV中的存储顺序为BGR)
    int channels_r[] = { 2 };
    calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges);
    //绿色分量直方图的计算
    int channels_g[] = { 1 };
    calcHist(&srcImage, 1, channels_g, Mat(), greenHist, 1, hist_size, ranges);
    //蓝色分量直方图的计算
    int channels_b[] = { 0 };
    calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges);

    double maxValue_red, maxValue_green, maxValue_blue;
    minMaxLoc(redHist, 0, &maxValue_red, 0, 0);  //此处不需要最小值
    minMaxLoc(greenHist, 0, &maxValue_green, 0, 0);
    minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
    int scale = 1;
    int histHeight = 256;
    Mat histImage = Mat::zeros(histHeight, bins*3, CV_8UC3);

    for (int i = 0; i < bins; i++)
    {
        float binValue_red = redHist.at<float>(i);
        float binValue_green = greenHist.at<float>(i);
        float binValue_blue = blueHist.at<float>(i);
        int intensity_red = cvRound(binValue_red*histHeight/maxValue_red);  //要绘制的高度
        int intensity_green = cvRound(binValue_green*histHeight / maxValue_green);
        int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue);
        rectangle(histImage, Point(i*scale, histHeight-1), Point((i+1)*scale-1, histHeight - intensity_red), Scalar(0, 0, 255));
        rectangle(histImage, Point((i+bins)*scale, histHeight - 1), Point((i+bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
        rectangle(histImage, Point((i+bins*2)*scale, histHeight - 1), Point((i+bins*2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(255, 0, 0));
    }
    imshow("【图像的RGB直方图】", histImage);
    while (waitKey(9) !=27);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

素材:
这里写图片描述
效果图:
这里写图片描述
提示:

3 . 直方图对比

源码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

int main() {
    Mat srcImage_base, hsvImage_base;
    Mat srcImage_test1, hsvImage_test1;
    Mat srcImage_test2, hsvImage_test2;
    Mat hsvImage_halfDown;
    srcImage_base = imread("poster_book.jpg");
    srcImage_test1 = imread("poster_book_1.jpg");
    srcImage_test2 = imread("poster_book_2.jpg");
    imshow("【基准图像】", srcImage_base);
    imshow("【测试图像1】", srcImage_test1);
    imshow("【测试图像2】", srcImage_test2);
    cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
    cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
    cvtColor(srcImage_test2, hsvImage_test2, COLOR_BGR2HSV);
    hsvImage_halfDown = hsvImage_base(Range(hsvImage_base.rows/2, hsvImage_base.rows - 1), Range(0, hsvImage_base.cols - 1));  //此处选取的是ROI,引用
    int h_bins = 30;  //对hue通道分30个等级
    int s_bins = 32;  //saturation通道分32个等级
    int histSize[] = { h_bins, s_bins };
    float h_ranges[] = { 0, 180 };
    float s_ranges[] = { 0, 256 };
    const float* ranges[] = { h_ranges, s_ranges };
    int channels[] = { 0, 1 };
    MatND baseHist, halfDownHist, testHist1, testHist2;
    calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges);
    normalize(baseHist, baseHist, 0, 1, NORM_MINMAX);
    calcHist(&hsvImage_halfDown, 1, channels, Mat(), halfDownHist, 2, histSize, ranges);
    normalize(halfDownHist, halfDownHist, 0, 1, NORM_MINMAX);
    calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges);
    normalize(testHist1, testHist1, 0, 1, NORM_MINMAX);
    calcHist(&hsvImage_test2, 1, channels, Mat(), testHist2, 2, histSize, ranges);
    normalize(testHist2, testHist2, 0, 1, NORM_MINMAX);
    for (int i = 0; i < 4; i++) {
        int compare_method = i;
        double base_base = compareHist(baseHist, baseHist, compare_method);
        double base_half = compareHist(baseHist, halfDownHist, compare_method);
        double base_test1 = compareHist(baseHist, testHist1, compare_method);
        double base_test2 = compareHist(baseHist, testHist2, compare_method);
        printf("方法[%d]的匹配结果如下:\n\n【基准图-基准图】:%f,【基准图-半身图】:%f,【基准图-测试图1】:%f,【基准图-测试图2】:%f \n--------------------------------------------\n", i, base_base, base_half, base_test1, base_test2);

    }
    cout << "检测结束。";
    while (waitKey(5) != 27);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

素材:
poster_book.jpg:
这里写图片描述
poster_book_1.jpg:
这里写图片描述
poster_book_2.jpg:
这里写图片描述
效果图:
这里写图片描述
提示:

4 . 反向投影

源码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

#define WINDOW_NAME1 "【原始图】"
Mat g_srcImage, g_hsvImage, g_hueImage;
int g_bins = 30;  //直方图组距
void on_BinChange(int, void*);

int main() {
    g_srcImage = imread("poster_hand.jpg");
    cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);
    g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
    int ch[]{ 0, 0 };
    mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);
    namedWindow(WINDOW_NAME1);
    createTrackbar("色相组距", WINDOW_NAME1, &g_bins, 180, on_BinChange);
    on_BinChange(0, 0);  
    imshow(WINDOW_NAME1, g_srcImage);
    while (waitKey(9)!=27);
    return 0;
}

void on_BinChange(int, void*) {
    MatND hist;
    g_bins = MAX(g_bins, 2);
    int histSize[] = { g_bins };
    float hue_range[] = { 0, 180 };
    const float* ranges[] = { hue_range };
    int channels[]={0};
    calcHist(&g_hueImage, 1, channels, Mat(), hist, 1, histSize, ranges);  //计算直方图并归一化
    normalize(hist, hist, 0, 255, NORM_MINMAX);
    MatND backproj;  //计算反向投影
    calcBackProject(&g_hueImage, 1, channels, hist, backproj, ranges);
    imshow("【反向投影图】", backproj);
    int w = 400, h = 400;
    int bin_w = cvRound((double)w/ g_bins);
    Mat histImg = Mat::zeros(w, h, CV_8UC3);
    for(int i = 0; i < g_bins; i++ ){
        rectangle(histImg, Point(i*bin_w, h), Point((i+1)*bin_w, h-cvRound(hist.at<float>(i)*h/255.0)), Scalar(100, 123, 255), CV_FILLED);
    }
    imshow("【直方图】", histImg);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

素材:
这里写图片描述
效果图:
这里写图片描述
这里写图片描述
提示:

5 . 模板匹配

源码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

#define WINDOW_NAME1 "【原始图片】"
#define WINDOW_NAME2 "【效果窗口】"
Mat g_srcImage, g_templateImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum=5;
void on_Matching(int, void*);

int main() {
    g_srcImage = imread("poster_girl_4.jpg");
    g_templateImage = imread("poster_girl_4_ROI.jpg");
    namedWindow(WINDOW_NAME1);
    namedWindow(WINDOW_NAME2);
    createTrackbar("方法", WINDOW_NAME1, &g_nMatchMethod, g_nMaxTrackbarNum, on_Matching);
    on_Matching(0, 0);
    while (waitKey(8)!=27);
    return 0;
}

void on_Matching(int, void*) {
    Mat srcImage;
    g_srcImage.copyTo(srcImage);
    g_resultImage.create(g_srcImage.cols-g_templateImage.cols+1, g_srcImage.rows - g_templateImage.rows + 1, CV_32FC1);
    matchTemplate(g_srcImage, g_templateImage, g_resultImage, g_nMatchMethod);  //第3中方法明显跑偏了
    normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX);
    double minValue, maxValue;
    Point minLocation, maxLocation;
    minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation);
    Point matchLocation;
    if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == TM_SQDIFF_NORMED) {
        matchLocation = minLocation;
    }
    else {
        matchLocation = maxLocation;
    }
    rectangle(srcImage, Point(matchLocation),Point(matchLocation.x+g_templateImage.cols, matchLocation.y+g_templateImage.rows), Scalar(0, 0, 255), 2);
    rectangle(g_resultImage, Point(matchLocation), Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2);
    imshow(WINDOW_NAME1, srcImage);
    imshow(WINDOW_NAME2, g_resultImage);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

素材:
这里写图片描述
这里写图片描述
效果图:
这里写图片描述
提示:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/46705
推荐阅读
相关标签
  

闽ICP备14008679号