直方图

直方图

示例代码

 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
50
51
52
//
// Created by itheima on 6/12/19.
//
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(){
    // 读取图片
    Mat img = imread("../assets/lena.jpg",IMREAD_COLOR);
    imshow("src",img);
    // 单通道处理数据
    vector<Mat> bgr_channels;
    // 颜色分割
    split(img,bgr_channels);

    int histSize=256;
    float range[] = {0,256};
    const float * histRange = {range};
    // 用于说明bin宽度是否相等
//    bool uniform=true;
    // 当计算多通道直方图的时候,是否进行累加
//    bool accumulate=false;

    Mat b_hist,g_hist,r_hist;
    calcHist(&bgr_channels[0],1,0,Mat(),b_hist,1,&histSize,&histRange);
    calcHist(&bgr_channels[1],1,0,Mat(),g_hist,1,&histSize,&histRange);
    calcHist(&bgr_channels[2],1,0,Mat(),r_hist,1,&histSize,&histRange);

    int histsize = 256;

    // 创建一个灰色图像
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound(512.0/histSize);

    //进行归一化处理       最小值   最大值  模式
    normalize(b_hist,b_hist,0,hist_h,NORM_MINMAX);
    cout<<"归一化之后:"<<b_hist<<endl;

    Mat histImage(hist_h,hist_w,CV_8UC3,Scalar(0,0,0));
    // 绘制图像
    for(int i=0;i<histsize;i++){
        line(histImage,Point(bin_w*i,hist_h),Point(bin_w*(i),hist_h-b_hist.at<float>(i-1)),Scalar(255,0,0),2,LINE_AA);
    }

    imshow("histgrom",histImage);
    waitKey(0);
    destroyAllWindows();
}

直方图绘制工具

 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
#ifndef OPENCV_DEMO_COMMON_H
#define OPENCV_DEMO_COMMON_H

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

/**
 * 直接传入直方图数据
 */
void drawHistgrom(string title,Mat &hist) {
    int hist_h = 500;
    int bin_w = 4;
    int hist_w = 4 * 256;

    // 将数据归一化到0-hist_h之间
    Mat outRatios;
    normalize(hist,outRatios,0,hist_h,NORM_MINMAX);

    Mat histImage(hist_h, hist_w, CV_8UC3);
    for (int i = 0; i < 256; i++) {
        Point pt1(i * bin_w, hist_h);
        Point pt2(i * bin_w, hist_h - (int) outRatios.at<float>(i));
        line(histImage, pt1, pt2, Scalar(0, 255, 255), 1, LINE_AA);
    }


    imshow(title, histImage);
}

/**
 * 传入进来的上图像
 */
void showHistgrom(string title,Mat &img) {
    int histSize=256;
    float range[] = {0,256};
    const float * histRange = {range};

    Mat hist;
    calcHist(&img,1,0,Mat(),hist,1,&histSize,&histRange);

    drawHistgrom(title,hist);
}

#endif //OPENCV_DEMO_COMMON_H

直方图均衡化

示例代码

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <opencv2/opencv.hpp>
#include "common.h"


using namespace std;
using namespace cv;


int main() {
    Mat img = imread("../assets/itheima.jpg", IMREAD_COLOR);

    //将图像转成灰度图像
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    imshow("gray",gray);
    // 计算直方图
    Mat hist;
    int histSize = 256;
    float range[] = {0, 255.0};
    const float *histRange[] = {range};
    calcHist(&gray, 1, 0, Mat(), hist, 1, &histSize, histRange);

    // 计算直方图的概率
    Mat ratios = hist / (img.rows * img.cols);


    drawHistgrom("src hist", ratios);


    float sum1 = 0;
    // 计算直方图的累加概率
    for (int i = 0; i < ratios.rows; i++) {
        sum1 += ratios.at<float>(i);
        ratios.at<float>(i) = sum1;
    }
    cout<<ratios<<endl;

    // 绘制直方图
    drawHistgrom("leiji hist", ratios);

    Mat dst(gray.rows, gray.cols, CV_8UC1);
    // 对原图像进行处理
    for (int row = 0; row < img.rows; ++row) {
        for (int col = 0; col < img.cols; ++col) {
            // 获取每个位置的灰度值
            int color = gray.at<uint8_t>(row, col);
            // 根据颜色值从累计概率中获取累计概率
            float ratio = ratios.at<float>(color);
            // 计算新的颜色值
            color = cvRound(255 * ratio);
            // 填充到原图中
            dst.at<uchar>(row, col) = color;
        }
    }
    imshow("dst", dst);
    showHistgrom("dst hist",dst);

    waitKey(0);
    destroyAllWindows();
    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
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <opencv2/opencv.hpp>
#include "common.h"


using namespace std;
using namespace cv;

Mat getAccumulate(Mat &src);

Mat histogramMatch(Mat &src, Mat &refer);

int main(){
    // 原图像
    Mat src = imread("../assets/1.jpg",IMREAD_COLOR);
    // 参考图
    Mat refer = imread("../assets/2.jpg",IMREAD_COLOR);

    vector<Mat> srcChannels;
    vector<Mat> referChannels;

    split(src,srcChannels);
    split(refer,referChannels);

    Mat b_channel = histogramMatch(srcChannels[0], referChannels[0]);
    Mat g_channel = histogramMatch(srcChannels[1], referChannels[1]);
    Mat r_channel = histogramMatch(srcChannels[2], referChannels[2]);

    cout<<"开始图像的合并:"<<endl;
    Mat dst;
    vector<Mat> channels = {b_channel,g_channel,r_channel};
    merge(channels,dst);



    // 显示图像
    imshow("src",src);
    imshow("refer",refer);
    imshow("dst",dst);

    // 绘制直方图
//    showHistgrom("src hist",src);
//    showHistgrom("refer hist",refer);
//    showHistgrom("dst hist",dst);

    waitKey(0);
    destroyAllWindows();
    return 0;
}

Mat histogramMatch(Mat &src, Mat &refer) {// 计算src的累计概率
    Mat srcRatios = getAccumulate(src);

    // 计算src的累计概率
    Mat referRatios = getAccumulate(refer);

    // 执行关系映射
    Mat map(256, 1, CV_8UC1);

    // 遍历原图像
    for (int i = 0; i < 256; ++i) {
        float srcRatio = srcRatios.at<float>(i);

        float min = 10;
        int k = 0;
        // 去参考图的直方图中查找最小的差值
        for (int j = 0; j < 256; ++j) {
            float referRatio = referRatios.at<float>(j);
            // 计算差值
            float diff = abs(srcRatio - referRatio);
            if (diff < min) {
                min = diff;
                k = j;
            }
        }
        // 当上面循环执行完毕,就找到了最小的差值  120 ---》 200
        map.at<uchar>(i) = k;
    }

    Mat dst(src.rows, src.cols, src.type());

    // 处理原图,将原图的颜色映射到新的颜色空间
    for (int row = 0; row < dst.rows; ++row) {
        for (int col = 0; col < dst.cols; ++col) {
            uchar color = src.at<uchar>(row, col);
            uchar newColor = map.at<uchar>(color);
            dst.at<uchar>(row, col) = newColor;
        }
    }

    return dst;
}

Mat getAccumulate(Mat &src) {
    Mat hist_src;
    int histSize = 256;
    float range[] = {0.0, 255.0};
    const float *histRange[] = {range};

    calcHist(&src, 1, 0, Mat(), hist_src, 1, &histSize, histRange);

    // 1.计算每个像素的概率
    Mat ratios = hist_src/(src.rows*src.cols);

    float sum = 0;
    // 2. 计算累计概率
    for (int i = 0; i < hist_src.rows; ++i) {
        sum += ratios.at<float>(i);
        ratios.at<float>(i) = sum;
    }
    // 计算累计概率
    return ratios;
}