OpenCV图像处理教程C++(十八) 直方图均衡化、计算、比较、反向投影

直方图均衡化:
直方图(Histogram): 是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图。
直方图反映了图像灰度的分布情况。是图像的统计学特征。
直方图均衡化: 是一种提高图像对比度的方法,拉伸图像灰度值范围。让图像更均衡。对于图像的特征提取是非常有用的
通过remap我们知道可以将图像灰度分布从一个分布映射到另外一个分布,然后在得到映射后的像素值即可。
提升对比度:就是图像中所有的像素值之间的差异都比较明显
API:

equalizeHist(
src,8单通道
dst)
*/

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

int main() {
    Mat src, graysrc,dst;
    src = imread("C:\\Users\\Administrator\\Desktop\\pic\\z2.jpg");
    imshow("input", src);
    cvtColor(src, graysrc,CV_RGB2GRAY);
    imshow("graysrc", graysrc);
    equalizeHist(graysrc, dst);
    imshow("dst", dst);
    waitKey(0);
}

结果:
这里写图片描述

直方图计算:
我们队图像灰度,梯度,每个像素的角度,等一切图像的属性值都可以建立直方图,基于图像像素灰度直方图最常见。
直方图的几个常见属性:
dims表示维度。对灰度图像来说只有一个通道值dims=1
bins表示维度中子区域大小划分,bins=256,划分为256个等级
range表示值的范围,灰度值范围0-255
API:

calcHist(
const Mat*src,//输入图像的指针
int images,//图像数目, 这些图像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F)
const int*channels,//通道数
mask,//可选的掩码 可选的掩码,不使用时可设为空。要和输入图像具有相同的大小,在进行直方图计算的时候,只会统计该掩码不为0的对应像素
hist,//输出直方图数据
int dims,//维数
const int*histsize,//直方图级数
const float*ranges,//值域范围
bool uniform,//默认true  是否进行归一化
bool accumulate)//默认false  累积标志

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

int main() {
    Mat src,b_hist,g_hist,r_hist;
    src = imread("C:\\Users\\Administrator\\Desktop\\pic\\1-H.jpg");
    imshow("input", src);
    //分通道显示
    vector<Mat> bgr_palnes;
    split(src, bgr_palnes);
    imshow("bgr_planes", bgr_palnes[0]);
    //计算直方图
    int histSize = 256;
    float range[] = { 0,256 };
    const float *histRange = { range };
    calcHist(&bgr_palnes[0], // 要计算图像的
        1,// 只计算一幅图像的直方图
        0,// 通道数量
        Mat(),//不用掩码
        b_hist, // 存放直方图
        1,// 1D直方图
        &histSize,// 统计的灰度的个数
        &histRange);// 灰度值的范围
    calcHist(&bgr_palnes[1], 1,0,Mat(),g_hist, 1,&histSize,&histRange);
    calcHist(&bgr_palnes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange);
    //归一化
    int hist_h = 400;//直方图高度
    int hist_w = 512;//直方图宽度
    int bin_w = hist_w / histSize;
    Mat histimage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
    normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    //绘制直方图
    for (int i = 1; i < histSize; i ++ ) {
        line(histimage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))),
            Scalar(255, 0, 0), 2);
        line(histimage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))),
            Scalar(0, 255, 0), 2);
        line(histimage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))),
            Scalar(0, 0, 255), 2);
    }
    imshow("dst", histimage);
    waitKey(0);
}

结果:
这里写图片描述

直方图比较:
对输入的两张图像计算得到直方图H1和H2,归一化到相同的空间然后可以通过计算H1和H2之间的距离得到两个直方图的相似度进而比较图像本身的相似度,opencv提供四种比较方法:

  • Correlation:相关性比较(就是最小二乘法r的取值公式)计算结果范围为 -1到1 -1很不相关,1完全一样
  • Chi-Square:卡方比较计算 结果越接近0,两个直方图越相似
  • Intersection:十字交叉性 公式为取两个直方图每个相同位置的值的最小值,然后求和,这个比较方式不是很好,不建议使用
  • Bhattacharyya distance:巴氏距离 比较结果是很准的,计算结果范围为 0-,0表示两个直方图非常相关,1最不相似

步骤:

  1. 首先把图像从RGB色彩空间转换到HSV色彩空间cvtColor; 色调(H),饱和度(S),明度(V)
  2. 计算图像的直方图,然后归一化到0-1之间caHist和normalize;
  3. 使用上述四种比较方法之一进行比较compareHist;

    API:

compareHist(
InputArray h1, // 直方图数据,下同
InputArray H2,
int method// 比较方法,上述四种方法之一
)

代码:

扫描二维码关注公众号,回复: 2808281 查看本文章
#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

string convertToString(double d) {    // << 运算符重载了,将double转成string
    ostringstream os;
    if (os << d)
        return os.str();
    return "invalid conversion";
}
int main() {
    Mat base, test1, test2, basehsv, test1hsv, test2hsv;
    base = imread("C:\\Users\\Administrator\\Desktop\\pic\\z1.jpg");
    test1 = imread("C:\\Users\\Administrator\\Desktop\\pic\\z2.jpg");
    test2 = imread("C:\\Users\\Administrator\\Desktop\\pic\\z3.jpg");

    cvtColor(base, basehsv, CV_RGB2HSV);
    cvtColor(test1, test1hsv, CV_RGB2HSV);
    cvtColor(test2, test2hsv, CV_RGB2HSV);

    int h_bin = 50, s_bin = 60;
    int histBins[] = { h_bin,s_bin };
    //
    float h_ranges[] = { 0,180 };
    float s_ranges[] = { 0,256 };
    const float *ranges[] = { h_ranges,s_ranges };
    //
    int channels[] = { 0,1 };
    //ND表示二维或者多维的Mat,
    //归一化
    Mat hist_base, hist_test1, hist_test2;
    calcHist(&basehsv, 1, channels, Mat(), hist_base, 2, histBins, ranges);
    normalize(hist_base, hist_base, 0, 1, NORM_MINMAX);
    calcHist(&test1hsv, 1, channels, Mat(), hist_test1, 2, histBins, ranges);
    normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX);
    calcHist(&test2hsv, 1, channels, Mat(), hist_test2, 2, histBins, ranges);
    normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX);

    int compareType = CV_COMP_BHATTACHARYYA;
    double basebase = compareHist(hist_base, hist_base, compareType);
    double basetest1 = compareHist(hist_base, hist_test1, compareType);
    double basetest2 = compareHist(hist_base, hist_test2, compareType);
    double test1test2 = compareHist(hist_test1, hist_test2, compareType);

    Mat test12;
    test2.copyTo(test12);
    //将比较的结果转换为string,然后以文字的方式绘制到图形上
    putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
    putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
    putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
    putText(test12, convertToString(test1test2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));

    imshow("basebase", base);
    imshow("basetest1", test1);
    imshow("basetest2", test2);
    imshow("test11test2", test12);
    waitKey(0);
}

结果:
这里写图片描述

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

步骤:
建立直方图模型
计算待检测图像直方图并映射到模型中
从模型反向计算生成图像

API步骤:
加载imread
RGB转到HSV, cvtColor
计算直方图和归一化calHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处都可以用
计算反向投影图像,calcBackProject

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

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

Mat src, hsv, hue;
int bins = 12;
void Hist_and_Backprojection(int, void*) {
    if (bins == 0)
        return;
    float range[] = { 0,180 };
    const float*histRanges = { range };
    Mat h_hist;
    calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges);
    normalize(h_hist, h_hist, 0, 255,NORM_MINMAX,-1,Mat());
    Mat backpriIamge;
    calcBackProject(&hue, 1, 0, h_hist, backpriIamge, &histRanges, 1);
    imshow("output", backpriIamge);
    //绘制直方图
    int hist_h = 400;
    int hist_w = 400;
    Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
    int bin_w = hist_w / bins;
    for (int i = 1; i < bins; i++) {
        rectangle(histImage, Point((i - 1)*bin_w, hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255))),
            Point(i*bin_w, hist_h ), Scalar(0, 0, 255),-1);//-1表示填充矩形
    }
    imshow("zhifangtu", histImage);
}
int main() {
    src = imread("C:\\Users\\Administrator\\Desktop\\pic\\6.jpeg");
    imshow("input", src);
    cvtColor(src, hsv, CV_RGB2HSV);
    hue.create(hsv.size(), hsv.depth());
    int channels[] = { 0,0 };
    mixChannels(&hsv, 1,&hue, 1, channels, 1);
    Hist_and_Backprojection(0, 0);
    createTrackbar("zhifangtubins", "output", &bins, 180, Hist_and_Backprojection);
    waitKey(0);
}

结果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_26907755/article/details/81738048