opencv4 学习 15 直方图均衡化和直方图匹配
1、直方图均衡化的作用,主要就是提高图像的对比度同时均衡化图像的亮度,扩展像素的分布范围,同时使像素值尽量均匀分步。
函数使用:
Mat src = imread("lena.jpg", IMREAD_COLOR); cvtColor(src, src, COLOR_BGR2GRAY); Mat dst; equalizeHist(src, dst);
算法原理参考:https://docs.opencv.org/3.4/d4/d1b/tutorial_histogram_equalization.html
2、直方图的计算和绘制
normalize(
InputArray src,
InputOutputArray dst,
double alpha = 1, 归一化的低边界的值
double beta = 0, 归一化的高边界的值
int norm_type = NORM_MINMAX, 归一化方法,本示例使用最大最小归一化
int dtype = -1, -1表示输出值类型和输入相同
InputArray mask = noArray());
calcHist(
const Mat* images, 输入图片
int nimages, 输入图片的数量
const int* channels, InputArray mask, 选择需要的channel和channle的掩码
SparseMat& hist, int dims, 保存输出值,设置输出数组的维度
const int* histSize, 每个channel的bin的个数
const float** ranges, 每个channel的bin的范围
bool uniform = true, bool accumulate = false
);
#include <opencv2/imgcodecs.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char* argv[]) { Mat src = imread("lena.jpg", IMREAD_COLOR); vector<Mat> bgr_planes; split(src, bgr_planes); int histSize = 256; float range[] = {0, 256}; const float* histRange = { range }; bool uniform = true, accumulate = false; Mat b_hist, g_hist, r_hist; calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate); int hist_w = 512, hist_h = 400; int bin_w = cvRound((double)hist_w/histSize); Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0,0,0)); normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); for(int i=1; i<histSize; i++){ line(histImage, Point(bin_w*(i-1), hist_h-cvRound(b_hist.at<float>(i-1))), Point(bin_w*i, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255,0,0), 2, 8, 0); line(histImage, Point(bin_w*(i-1), hist_h-cvRound(g_hist.at<float>(i-1))), Point(bin_w*i, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0,255,0), 2, 8, 0); line(histImage, Point(bin_w*(i-1), hist_h-cvRound(r_hist.at<float>(i-1))), Point(bin_w*i, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0,0,255), 2, 8, 0); } imshow("Source image", src); imshow("calcHist Demo", histImage); waitKey(0); return 0; }
参看:
3、直方图匹配
函数介绍 double compareHist( InputArray H1, InputArray H2, int method );
method 的取值:
enum HistCompMethods { HISTCMP_CORREL = 0, // Correlation HISTCMP_CHISQR = 1, // Chi-Square HISTCMP_INTERSECT = 2, // Intersection HISTCMP_BHATTACHARYYA = 3, // Bhattacharyya distance HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA, //!< Synonym for HISTCMP_BHATTACHARYYA HISTCMP_CHISQR_ALT = 4, };
Correlation 和 Intersection 方法的返回值越大,表示越相似;另外两种方法相反。
#include <iostream> #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat src_base = imread("G:\\tools\\opencv4\\workspace\\opencv01\\Histogram_Comparison_Source_0.jpg"); Mat src_test1 = imread("G:\\tools\\opencv4\\workspace\\opencv01\\Histogram_Comparison_Source_1.jpg"); Mat src_test2 = imread("G:\\tools\\opencv4\\workspace\\opencv01\\Histogram_Comparison_Source_2.jpg"); Mat hsv_base, hsv_test1, hsv_test2; cvtColor(src_base, hsv_base, COLOR_BGR2HSV); cvtColor(src_test1, hsv_test1, COLOR_BGR2HSV); cvtColor(src_test2, hsv_test2, COLOR_BGR2HSV); Mat hsv_half_down = hsv_base(Range(hsv_base.rows / 2, hsv_base.rows), Range(0, hsv_base.cols)); int h_bins = 50, s_bins = 60; 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 }; Mat hist_base, hist_half_down, hist_test1, hist_test2; calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false); normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat()); calcHist(&hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false); normalize(hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat()); calcHist(&hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false); normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat()); calcHist(&hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false); normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat()); for (int compare_method = 0; compare_method < 4; compare_method++) { double base_base = compareHist(hist_base, hist_base, compare_method); double base_half = compareHist(hist_base, hist_half_down, compare_method); double base_test1 = compareHist(hist_base, hist_test1, compare_method); double base_test2 = compareHist(hist_base, hist_test2, compare_method); cout << "Method " << compare_method << " Perfect, Base-Half, Base-Test(1), Base-Test(2): " << base_base << " / " << base_half << " / " << base_test1 << " / " << base_test2 << endl; } cout << "Done \n"; waitKey(0); return 0; }
参考:https://docs.opencv.org/master/d8/dc8/tutorial_histogram_comparison.html