直方圖均衡化C++實現


直方圖均衡化在圖像增強方面有着很重要的應用。一些拍攝得到的圖片,我們從其直方圖可以看出,它的分布是集中於某些灰度區間,這導致人在視覺上感覺這張圖的對比度不高。所以,對於這類圖像,我們可以通過直方圖均衡技術,將圖像的灰度分布變得較為均勻,從而使得圖像對比度增大,視覺效果更佳。

直方圖均衡化的代碼實現有以下幾個步驟:

  1. 遍歷全圖,先統計每個灰度級下的像素點個數(為此我們開辟了256大小的數組);
  2. 計算每個灰度級的像素點占總像素的點的比例;
  3. 按照第二步求出的比例重新計算每個灰度級下的新的灰度值,即均衡化;
  4. 依照新的灰度值表遍歷更新圖像的灰度值。

實現代碼:

int gray[256] = { 0 };  //記錄每個灰度級別下的像素個數
double gray_prob[256] = { 0 };  //記錄灰度分布密度
double gray_distribution[256] = { 0 };  //記錄累計密度
int gray_equal[256] = { 0 };  //均衡化后的灰度值

int gray_sum = 0;  //像素總數

Mat equalize_hist(Mat& input)
{
    Mat output = input.clone();
    gray_sum = input.cols * input.rows;

    //統計每個灰度下的像素個數
    for (int i = 0; i < input.rows; i++)
    {
        uchar* p = input.ptr<uchar>(i);
        for (int j = 0; j < input.cols; j++)
        {
            int vaule = p[j];
            gray[vaule]++;
        }
    }

  
    //統計灰度頻率
    for (int i = 0; i < 256; i++)
    {
        gray_prob[i] = ((double)gray[i] / gray_sum);
    }

    //計算累計密度
    gray_distribution[0] = gray_prob[0];
    for (int i = 1; i < 256; i++)
    {
        gray_distribution[i] = gray_distribution[i-1] +gray_prob[i];
    }

    //重新計算均衡化后的灰度值,四舍五入。參考公式:(N-1)*T+0.5
    for (int i = 0; i < 256; i++)
    {
        gray_equal[i] = (uchar)(255 * gray_distribution[i] + 0.5);
    }


    //直方圖均衡化,更新原圖每個點的像素值
    for (int i = 0; i < output.rows; i++)
    {
        uchar* p = output.ptr<uchar>(i);
        for (int j = 0; j < output.cols; j++)
        {
            p[j] = gray_equal[p[j]];
        }
    }

    return output;
}

這里還分享一段代碼,就是如何畫灰度直方圖

void show_histogram(Mat& img)
{
    //為計算直方圖配置變量  
    //首先是需要計算的圖像的通道,就是需要計算圖像的哪個通道(bgr空間需要確定計算 b或g貨r空間)  
    int channels = 0;
    //然后是配置輸出的結果存儲的 空間 ,用MatND類型來存儲結果  
    MatND dstHist;
    //接下來是直方圖的每一個維度的 柱條的數目(就是將數值分組,共有多少組)  
    int histSize[] = { 256 };       //如果這里寫成int histSize = 256;   那么下面調用計算直方圖的函數的時候,該變量需要寫 &histSize  
    //最后是確定每個維度的取值范圍,就是橫坐標的總數  
    //首先得定義一個變量用來存儲 單個維度的 數值的取值范圍  
    float midRanges[] = { 0, 256 };
    const float *ranges[] = { midRanges };

    calcHist(&img, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);

    //calcHist  函數調用結束后,dstHist變量中將儲存了 直方圖的信息  用dstHist的模版函數 at<Type>(i)得到第i個柱條的值  
    //at<Type>(i, j)得到第i個並且第j個柱條的值  

    //開始直觀的顯示直方圖——繪制直方圖  
    //首先先創建一個黑底的圖像,為了可以顯示彩色,所以該繪制圖像是一個8位的3通道圖像  
    Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
    //因為任何一個圖像的某個像素的總個數,都有可能會有很多,會超出所定義的圖像的尺寸,針對這種情況,先對個數進行范圍的限制  
    //先用 minMaxLoc函數來得到計算直方圖后的像素的最大個數  
    double g_dHistMaxValue;
    minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
    //將像素的個數整合到 圖像的最大范圍內  
    //遍歷直方圖得到的數據  
    for (int i = 0; i < 256; i++)
    {
        int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);

        line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 255, 255));
    }

    imshow("【原圖直方圖】", drawImage);
}

測試圖片以及其灰度直方圖:

直方圖均衡化后,圖像對比度顯著增加,圖像增強效果明顯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM