日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【机器视觉学习笔记】直方图的绘制及直方图均衡化(C++)

發布時間:2023/12/9 c/c++ 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【机器视觉学习笔记】直方图的绘制及直方图均衡化(C++) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 概念
    • 直方圖定義
    • 直方圖均衡化
      • 為什么要選用累積分布函數
      • 如何運用累積分布函數使得直方圖均衡化
  • C++ 源碼
    • 直方圖均衡化
    • 繪制直方圖
    • 主函數
  • 效果
  • 完整源碼

平臺:Windows 10 20H2
Visual Studio 2015
OpenCV 4.5.3


本文綜合自直方圖計算和程序員-圖哥——圖像處理之直方圖均衡化及C++實現

概念

直方圖定義

直方圖均衡化


直方圖均衡化的作用是圖像增強。

有兩個問題比較難懂,一是為什么要選用累積分布函數,二是為什么使用累積分布函數處理后像素值會均勻分布。

為什么要選用累積分布函數

均衡化過程中,必須要保證兩個條件:
①像素無論怎么映射,一定要保證原來的大小關系不變,較亮的區域,依舊是較亮的,較暗依舊暗,只是對比度增大,絕對不能明暗顛倒;
②如果是八位圖像,那么像素映射函數的值域應在0和255之間的,不能越界。

綜合以上兩個條件,累積分布函數是個好的選擇,因為累積分布函數是單調增函數(控制大小關系),并且值域是0到1(控制越界問題),所以直方圖均衡化中使用的是累積分布函數。

如何運用累積分布函數使得直方圖均衡化

直方圖均衡化過程中,映射方法是

其中,n是圖像中像素的總和,nkn_knk?是當前灰度級的像素個數,L是圖像中可能的灰度級總數。

C++ 源碼

直方圖均衡化

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

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

Mat getEqualizeHistImage(Mat input) {int gray[256] = { 0 }; //記錄每個灰度級別下的像素個數double gray_prob[256] = { 0 }; //記錄灰度分布密度double gray_distribution[256] = { 0 }; //記錄累計密度int gray_equal[256] = { 0 }; //均衡化后的灰度值int gray_sum = 0; //像素總數Mat chRGB[3];split(input, chRGB);Mat output = input.clone();for (unsigned char k = 0; k < 3; ++k){for (unsigned short i = 0; i < 256; ++i){gray[i] = 0;gray_prob[i] = 0;gray_distribution[i] = 0;gray_equal[i] = 0;}gray_sum = chRGB[k].cols * chRGB[k].rows;//統計每個灰度下的像素個數for (int i = 0; i < chRGB[k].rows; i++){uchar* p = chRGB[k].ptr<uchar>(i);for (int j = 0; j < chRGB[k].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.5for (int i = 0; i < 256; i++){gray_equal[i] = (uchar)(255 * gray_distribution[i] + 0.5);}//直方圖均衡化,更新原圖每個點的像素值for (int i = 0; i < chRGB[k].rows; i++){uchar* p = chRGB[k].ptr<uchar>(i);for (int j = 0; j < chRGB[k].cols; j++){p[j] = gray_equal[p[j]];}}}merge(chRGB, 3, output);return output; }

繪制直方圖

Mat getHistImage(Mat input) {Mat chRGB[3];split(input, chRGB);// 設定bin數目int histSize = 255;// 設定取值范圍 ( R,G,B) )float range[] = { 0, 255 };const float* histRange = { range };bool uniform = true; bool accumulate = false;Mat RGB_Hist[3];for(uint8_t i = 0; i < 3; ++i)// 計算直方圖:calcHist(&chRGB[i], 1, 0, Mat(), RGB_Hist[i], 1, &histSize, &histRange, uniform, accumulate);// 創建直方圖畫布int hist_w = 400; int hist_h = 400;int bin_w = cvRound((double)hist_w / histSize);Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));for(uint8_t i = 0; i < 3; ++i)// 將直方圖歸一化到范圍 [ 0, histImage.rows ]normalize(RGB_Hist[i], RGB_Hist[i], 0, histImage.rows, NORM_MINMAX, -1, Mat());// 在直方圖畫布上畫出直方圖for (int i = 1; i < histSize; i++){line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[0].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[0].at<float>(i))),Scalar(0, 0, 255), 2, 8, 0);line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[1].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[1].at<float>(i))),Scalar(0, 255, 0), 2, 8, 0);line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[2].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[2].at<float>(i))),Scalar(255, 0, 0), 2, 8, 0);}/// 顯示直方圖///imshow("calcHist Demo", histImage);return histImage; }

主函數

圖片路徑根據實際情況調整,注意反斜杠是轉義字符的開頭,故“\”應替換為“\\”

int main(int argc, char * argv[]) {Mat Image = imread("D:\\Work\\OpenCV\\Workplace\\Test_1\\1.jpg");imshow("原圖", Image);imshow("原圖直方圖", getHistImage(Image));imshow("直方圖均衡化后的圖像", getEqualizeHistImage(Image));imshow("直方圖均衡化后的直方圖", getHistImage(getEqualizeHistImage(Image)));waitKey(0);return 0; }

效果




完整源碼

#include <opencv2/opencv.hpp> #include <iostream>using namespace cv; using namespace std;Mat getHistImage(Mat input) {Mat chRGB[3];split(input, chRGB);// 設定bin數目int histSize = 255;// 設定取值范圍 ( R,G,B) )float range[] = { 0, 255 };const float* histRange = { range };bool uniform = true; bool accumulate = false;Mat RGB_Hist[3];for(uint8_t i = 0; i < 3; ++i)// 計算直方圖:calcHist(&chRGB[i], 1, 0, Mat(), RGB_Hist[i], 1, &histSize, &histRange, uniform, accumulate);// 創建直方圖畫布int hist_w = 400; int hist_h = 400;int bin_w = cvRound((double)hist_w / histSize);Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));for(uint8_t i = 0; i < 3; ++i)// 將直方圖歸一化到范圍 [ 0, histImage.rows ]normalize(RGB_Hist[i], RGB_Hist[i], 0, histImage.rows, NORM_MINMAX, -1, Mat());// 在直方圖畫布上畫出直方圖for (int i = 1; i < histSize; i++){line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[0].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[0].at<float>(i))),Scalar(0, 0, 255), 2, 8, 0);line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[1].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[1].at<float>(i))),Scalar(0, 255, 0), 2, 8, 0);line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(RGB_Hist[2].at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(RGB_Hist[2].at<float>(i))),Scalar(255, 0, 0), 2, 8, 0);}/// 顯示直方圖///imshow("calcHist Demo", histImage);return histImage; }Mat getEqualizeHistImage(Mat input) {int gray[256] = { 0 }; //記錄每個灰度級別下的像素個數double gray_prob[256] = { 0 }; //記錄灰度分布密度double gray_distribution[256] = { 0 }; //記錄累計密度int gray_equal[256] = { 0 }; //均衡化后的灰度值int gray_sum = 0; //像素總數Mat chRGB[3];split(input, chRGB);Mat output = input.clone();for (unsigned char k = 0; k < 3; ++k){for (unsigned short i = 0; i < 256; ++i){gray[i] = 0;gray_prob[i] = 0;gray_distribution[i] = 0;gray_equal[i] = 0;}gray_sum = chRGB[k].cols * chRGB[k].rows;//統計每個灰度下的像素個數for (int i = 0; i < chRGB[k].rows; i++){uchar* p = chRGB[k].ptr<uchar>(i);for (int j = 0; j < chRGB[k].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.5for (int i = 0; i < 256; i++){gray_equal[i] = (uchar)(255 * gray_distribution[i] + 0.5);}//直方圖均衡化,更新原圖每個點的像素值for (int i = 0; i < chRGB[k].rows; i++){uchar* p = chRGB[k].ptr<uchar>(i);for (int j = 0; j < chRGB[k].cols; j++){p[j] = gray_equal[p[j]];}}}merge(chRGB, 3, output);return output; }int main(int argc, char * argv[]) {Mat Image = imread("D:\\Work\\OpenCV\\Workplace\\Test_1\\1.jpg");imshow("原圖", Image);imshow("原圖直方圖", getHistImage(Image));imshow("直方圖均衡化后的圖像", getEqualizeHistImage(Image));imshow("直方圖均衡化后的直方圖", getHistImage(getEqualizeHistImage(Image)));waitKey(0);return 0; }

總結

以上是生活随笔為你收集整理的【机器视觉学习笔记】直方图的绘制及直方图均衡化(C++)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。