OpenCV 之 直方图处理
1? 圖像直方圖
1.1? 定義
統計各個像素值,在整幅圖像中出現次數的一個分布函數。
??? ? ? ??
1.2? 標準化
? $\quad p_r(r_k) = \frac{n_k}{MN} \qquad k = 0, 1, 2, ..., L -1 $
$r_{k}$ - 第 k 個像素灰度值;? $n_{k}$ - 像素灰度值為 rk 的像素數目;
MN - 圖像中總的像素個數;? [0, L-1] - 像素灰度值的范圍
1.3? 直方圖均衡化
1.3.1? 定義?
? 直方圖均衡化,是將給定圖像的直方圖改造成均勻分布的直方圖,從而擴大像素灰度值的動態范圍,達到增強圖像對比度的效果。
? $\quad s_k = \frac{(L - 1)}{MN} \sum\limits_{j=0}^k n_j \qquad k = 0, 1, 2, ..., L - 1 $
??? ???????
??? ???????
1.3.2? 實例
? 一幅灰度值范圍是[0, 7],64行64列的數字圖像,其灰度分布如下表所示,求直方圖均衡化之后的灰度分布。
| ? r(k) | ?n(k) | ?P(rk) |
| ?r(0) = 0 | ?790 | ?0.19 |
| ?r(1) = 1 | ?1023 | ?0.25 |
| ?r(2) = 2 | ?850 | ?0.21 |
| ?r(3) = 3 | ?656 | ?0.16 |
| ?r(4) = 4 | ?329 | ?0.08 |
| ?r(5) = 5 | ?245 | ?0.06 |
| ?r(6) = 6 | ?122 | ?0.03 |
| ?r(7) = 7 | ?81 | ?0.02 |
? 根據上述公式得, s(0)=1.33≈1,s(1)=3.08≈3,s(2)≈5,s(3)≈6,s(4)≈6,s(5)≈7,s(6)≈7,s(7)≈7
? 因為 r(k) -> s(k),所以 s(0)=1 對應有790個像素值。因為r(3), r(4) 分別對應 s(3), s(4),且 s(3)=s(4)=6,
? 故像素值為6的像素數為 (656+329)個,同理可計算像素值為7的像素數。
? 將不同像素值對應的的像素數除以MN(圖像的像素總數),便得到均衡化之后的灰度直方圖,如下所示:
?
?
2? 四個參數
? H1 和 H2 為兩個待比較的直方圖。1) 和 2) 的值越大,二者越匹配;而 3) 和 4) 的值越小,兩者越匹配。
1) Correlation
??
2) Intersection
???
3) Chi-square
???
4) Bhattacharyya distance
???
3? OpenCV中的函數
3.1? equalizeHist
void equalizeHist (InputArray src, // 輸入圖像
OutputArray dst // 輸出圖像
);
? 源碼:
void cv::equalizeHist( InputArray _src, OutputArray _dst ) {CV_Assert( _src.type() == CV_8UC1 );if (_src.empty())return;CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),ocl_equalizeHist(_src, _dst))Mat src = _src.getMat();_dst.create( src.size(), src.type() );Mat dst = _dst.getMat();Mutex histogramLockInstance;const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;int hist[hist_sz] = {0,};int lut[hist_sz];EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);EqualizeHistLut_Invoker lutBody(src, dst, lut);cv::Range heightRange(0, src.rows);if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))parallel_for_(heightRange, calcBody);elsecalcBody(heightRange);int i = 0;while (!hist[i]) ++i;int total = (int)src.total();if (hist[i] == total){dst.setTo(i);return;}float scale = (hist_sz - 1.f)/(total - hist[i]);int sum = 0;for (lut[i++] = 0; i < hist_sz; ++i){sum += hist[i];lut[i] = saturate_cast<uchar>(sum * scale);}if(EqualizeHistLut_Invoker::isWorthParallel(src))parallel_for_(heightRange, lutBody);elselutBody(heightRange); } View Code3.2? calcHist
void cv::calcHist( const Mat * images,int nimages,const int * channels,InputArray mask,OutputArray hist,int dims,const int * histSize,const float ** ranges,bool uniform = true,bool accumulate = false ) View Code3.3? compareHist
double cv::compareHist ( InputArray H1,InputArray H2,int method ) View Code?
4? 實例
4.1? 直方圖計算
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgcodecs/imgcodecs.hpp" #include "opencv2/imgproc/imgproc.hpp"using namespace cv;int main( int, char** argv ) {Mat src, dst;// 1) Load imagesrc = imread("left.png");if(src.empty()) {return -1;}// 2) Separate the image in 3 places ( B, G and R )std::vector<Mat> bgr_planes;split( src, bgr_planes );// 3) Establish the number of binsint histSize = 256;// 4) Set the ranges (for B,G,R)float range[] = { 0, 256 } ;const float* histRange = { range };bool uniform = true;bool accumulate = false;Mat b_hist, g_hist, r_hist;// 5) Compute the histogramscalcHist( &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 );// 6) Draw the histograms for B, G and Rint hist_w = 512;int hist_h = 400;int bin_w = cvRound( (double) hist_w/histSize );Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );// 7) Normalize the result to [ 0, histImage.rows ]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() );// 8) Draw for each channelfor( 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 );}// 9) Displayimshow("calcHist Demo", histImage );waitKey(0); }4.2? 直方圖均衡化
#include "opencv2/imgcodecs.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h>using namespace cv; using namespace std;int main( int, char** argv ) {Mat src, dst;const char* source_window = "Source image";const char* equalized_window = "Equalized Image";// Load imagesrc = imread( argv[1], 1 );if( src.empty() ){ cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;return -1;}// Convert to grayscale cvtColor( src, src, COLOR_BGR2GRAY );// Apply Histogram Equalization equalizeHist( src, dst );// Display results namedWindow( source_window, WINDOW_AUTOSIZE );namedWindow( equalized_window, WINDOW_AUTOSIZE );imshow( source_window, src );imshow( equalized_window, dst );// Wait until user exits the programwaitKey(0);return 0;} View Code4.3? 直方圖比較
#include "opencv2/imgcodecs.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h>using namespace std; using namespace cv;/*** @function main*/ int main( int argc, char** argv ) {Mat src_base, hsv_base;Mat src_test1, hsv_test1;Mat src_test2, hsv_test2;Mat hsv_half_down;/// Load three images with different environment settingsif( argc < 4 ){printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");return -1;}src_base = imread( argv[1], 1 );src_test1 = imread( argv[2], 1 );src_test2 = imread( argv[3], 1 );/// Convert to HSV cvtColor( src_base, hsv_base, COLOR_BGR2HSV );cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );/// Using 50 bins for hue and 60 for saturationint h_bins = 50; int s_bins = 60;int histSize[] = { h_bins, s_bins };// hue varies from 0 to 179, saturation from 0 to 255float h_ranges[] = { 0, 180 };float s_ranges[] = { 0, 256 };const float* ranges[] = { h_ranges, s_ranges };// Use the o-th and 1-st channelsint channels[] = { 0, 1 };/// Histograms MatND hist_base;MatND hist_half_down;MatND hist_test1;MatND hist_test2;/// Calculate the histograms for the HSV imagescalcHist( &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() );/// Apply the histogram comparison methodsfor( int i = 0; i < 4; i++ ){int compare_method = i;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 );printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 );}printf( "Done \n" );return 0; } View Code?
參考資料
? <Digital Image Processing> 3rd
? OpenCV Tutorials / Image Processing (imgproc module) / Histogram Calculation
?
轉載于:https://www.cnblogs.com/xinxue/p/5290660.html
總結
以上是生活随笔為你收集整理的OpenCV 之 直方图处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpiderMonkey
- 下一篇: OS X进程管理之launchctl