1. 程式人生 > >《數字影象處理》--直方圖處理

《數字影象處理》--直方圖處理

直方圖

灰度直方圖是灰度級的函式,描述的是影象中具有該灰度級的像元的個數。確定影象像元的灰度值範圍,以適當的灰度間隔為單位將其劃分為若干等級,以橫軸表示灰度級,以縱軸表示每一灰度級具有的像元數或該像元數佔總像元數的比例值,做出的條形統計圖即為灰度直方圖。

如下圖所示,做直方圖的過程:

這裡寫圖片描述

直方圖的性質:

  1. 直方圖反映了影象中的灰度分佈規律。它描述每個灰度級具有的像元個數,但不包含這些像元在影象中的位置資訊。
  2. 任何一幅特定的影象都有唯一的直方圖與之對應,但不同的影象可以有相同的直方圖。
  3. 如果一幅影象有兩個不相連的區域組成,並且每個區域的直方圖已知,則整幅影象的直方圖是該兩個區域的直方圖之和

直方圖的應用

  1. 對於每幅影象都可做出其灰度直方圖。
  2. 根據直方圖的形態可以大致推斷影象質量的好壞。由於影象包含有大量的像元,其像元灰度值的分佈應符合概率統計分佈規律。假定像元的灰度值是隨機分佈的,那麼其直方圖應該是正態分佈。
  3. 影象的灰度值是離散變數,因此直方圖表示的是離散的概率分佈。若以各灰度級的像元數佔總像元數的比例值為縱座標軸做出影象的直方圖,將直方圖中各條形的最高點連成一條外輪廓線,縱座標的比例值即為某灰度級出現的概率密度,輪廓線可近似看成影象相應的連續函式的概率分佈曲線

這裡寫圖片描述

直方圖均衡化

直方圖均衡化是將原影象的直方圖通過變換函式變為均勻的直方圖

,然後按均勻直方圖修改原影象,從而獲得一幅灰度分佈均勻的新影象。

這裡寫圖片描述

計算過程如下:

  1. 統計原影象每一灰度級的像元數和累積像元數。
  2. 按下圖公式計算變換後的值
  3. 四捨五入得到新的灰度值
  4. 統計像元

下圖所示:

這裡寫圖片描述

下面用Matlab實現其過程:

clc;clear;close all;
I=imread('flower.jpg');      //注意影象是灰度影象
subplot(1,2,1);
imshow(I)
title('原始影象')
subplot(1,2,2)
imhist(I);
title('直方圖')
J=histeq(I);
figure;
subplot(1
,2,1) imshow(J) title('直方圖均衡化') subplot(1,2,2) 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 = 255;                //直方圖的最大畫素值
    float range[] = { 0,256 };      
    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[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr[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_8U, Scalar(0, 0, 0));
    //將結果歸一化[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());

    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));
        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));
        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));
    }
    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[0], bgr[0]);
    equalizeHist(bgr[1], bgr[1]);
    equalizeHist(bgr[2], bgr[2]);
    //合併
    Mat dst;
    merge(bgr, dst);
    namedWindow("equalize", WINDOW_AUTOSIZE);
    imshow("equalize",dst);

    Mat equalHist = histogramCal(dst);
    namedWindow("equalhist", WINDOW_AUTOSIZE);
    imshow("equalhist", equalHist);

    waitKey();
}

結果如下圖所示:
這裡用的是彩色的影象,可以看到,均衡話後凸顯出了彩色部分。

這裡寫圖片描述
這裡寫圖片描述