直方圖
灰階直方圖是灰階級的函數,描述的是圖像中具有該灰階級的像元的個數。确定圖像像元的灰階值範圍,以适當的灰階間隔為機關将其劃分為若幹等級,以橫軸表示灰階級,以縱軸表示每一灰階級具有的像元數或該像元數占總像元數的比例值,做出的條形統計圖即為灰階直方圖。
如下圖所示,做直方圖的過程:
直方圖的性質:
- 直方圖反映了圖像中的灰階分布規律。它描述每個灰階級具有的像元個數,但不包含這些像元在圖像中的位置資訊。
- 任何一幅特定的圖像都有唯一的直方圖與之對應,但不同的圖像可以有相同的直方圖。
- 如果一幅圖像有兩個不相連的區域組成,并且每個區域的直方圖已知,則整幅圖像的直方圖是該兩個區域的直方圖之和
直方圖的應用:
- 對于每幅圖像都可做出其灰階直方圖。
- 根據直方圖的形态可以大緻推斷圖像品質的好壞。由于圖像包含有大量的像元,其像元灰階值的分布應符合機率統計分布規律。假定像元的灰階值是随機分布的,那麼其直方圖應該是正态分布。
- 圖像的灰階值是離散變量,是以直方圖表示的是離散的機率分布。若以各灰階級的像元數占總像元數的比例值為縱坐标軸做出圖像的直方圖,将直方圖中各條形的最高點連成一條外輪廓線,縱坐标的比例值即為某灰階級出現的機率密度,輪廓線可近似看成圖像相應的連續函數的機率分布曲線。
直方圖均衡化
直方圖均衡化是将原圖像的直方圖通過變換函數變為均勻的直方圖,然後按均勻直方圖修改原圖像,進而獲得一幅灰階分布均勻的新圖像。
計算過程如下:
- 統計原圖像每一灰階級的像元數和累積像元數。
- 按下圖公式計算變換後的值
- 四舍五入得到新的灰階值
- 統計像元
下圖所示:
下面用Matlab實作其過程:
clc;clear;close all;
I=imread('flower.jpg'); //注意圖像是灰階圖像
subplot(,,);
imshow(I)
title('原始圖像')
subplot(,,)
imhist(I);
title('直方圖')
J=histeq(I);
figure;
subplot(,,)
imshow(J)
title('直方圖均衡化')
subplot(,,)
imhist(J)
title('直方圖')
結果如下圖所示:很明顯,直方圖區域均勻分布。
用OpenCV實作過程如下:
#include "opencv2/opencv.hpp"
#include "opencv2/opencv_modules.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<iostream>
using namespace cv;
using namespace std;
/*
計算直方圖的函數
傳回的是直方圖的矩陣形式
輸入是圖像
*/
Mat histogramCal(const Mat& image) {
int histSize = ; //直方圖的最大像素值
float range[] = { , };
const float* histRange = { range };
vector<Mat> bgr; //存儲圖像的矩陣
split(image, bgr); //将彩色圖像分割成,b,g,r分别存儲
bool uniform = true, accumulate = false;
Mat b_hist, g_hist, r_hist;
//分别計算各個波段的直方圖
calcHist(&bgr[], , , Mat(), b_hist, , &histSize, &histRange, uniform, accumulate);
calcHist(&bgr[], , , Mat(), g_hist, , &histSize, &histRange, uniform, accumulate);
calcHist(&bgr[], , , Mat(), r_hist, , &histSize, &histRange, uniform, accumulate);
//繪制直方圖
int hist_w = , hist_h = ;
int bin_w = cvRound((double)hist_w / histSize);
Mat histImage(hist_h, hist_w, CV_8U, Scalar(, , ));
//将結果歸一化[0,histImage.rows]
normalize(b_hist,b_hist, , histImage.rows, NORM_MINMAX, -, Mat());
normalize(g_hist, g_hist, , histImage.rows, NORM_MINMAX, -, Mat());
normalize(r_hist, r_hist, , histImage.rows, NORM_MINMAX, -, Mat());
for (int i = ; i < histSize; i++) {
line(histImage, Point(bin_w*(i - ), hist_h - cvRound(b_hist.at<float>(i - ))),
Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(, , ));
line(histImage, Point(bin_w*(i - ), hist_h - cvRound(g_hist.at<float>(i - ))),
Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(, , ));
line(histImage, Point(bin_w*(i - ), hist_h - cvRound(r_hist.at<float>(i - ))),
Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(, , ));
}
return histImage;
}
int main() {
Mat src;
src = imread("flower.png");
src.convertTo(src, CV_8U); //改變圖像的深度
cout << src.channels() << endl;
namedWindow("origin", WINDOW_AUTOSIZE);
imshow("origin", src);
//imwrite("cute.jpg", src);
Mat histImage = histogramCal(src);
namedWindow("hist", WINDOW_AUTOSIZE);
imshow("hist", histImage);
Mat hist;
vector<Mat>bgr;
split(src, bgr);
equalizeHist(bgr[], bgr[]);
equalizeHist(bgr[], bgr[]);
equalizeHist(bgr[], bgr[]);
//合并
Mat dst;
merge(bgr, dst);
namedWindow("equalize", WINDOW_AUTOSIZE);
imshow("equalize",dst);
Mat equalHist = histogramCal(dst);
namedWindow("equalhist", WINDOW_AUTOSIZE);
imshow("equalhist", equalHist);
waitKey();
}
結果如下圖所示:
這裡用的是彩色的圖像,可以看到,均衡話後凸顯出了彩色部分。