jashliao 用 VC++ 實現 fanfuhan OpenCV 教學018 ~ opencv-018-彩色/灰階 圖像 直方圖均衡化 藉此提高圖像的質量(對比/清晰)
jashliao 用 VC++ 實現 fanfuhan OpenCV 教學018 ~ opencv-018-彩色/灰階 圖像 直方圖均衡化 藉此提高圖像的質量(對比/清晰)
資料來源: https://fanfuhan.github.io/
https://fanfuhan.github.io/2019/03/29/opencv-018/
GITHUB:https://github.com/jash-git/fanfuhan_ML_OpenCV
https://github.com/jash-git/jashliao-implements-FANFUHAN-OPENCV-with-VC
★前言:
★主題:
圖像直方圖均衡化可以用於圖像增強,對輸入圖像進行直方圖均衡化處理,增強後續對象檢測的準確率,在OpenCV人臉檢測的代碼演示中已經很常見。
圖像也經常通過直方圖均衡化來提升圖像質量。
OPENCV計算直方圖均衡化函數(equalizeHist),其介紹如下所列:
void cv::equalizeHist(cv::Mat src, cv::Mat dst);
src : source src must be a single-channel, 8-bit image.
dst : Output image
★C++
// VC_FANFUHAN_OPENCV018.cpp : 定義主控台應用程式的進入點。 // /* // Debug | x32 通用屬性 | C/C++ | | 一般 | | 其他 Include 目錄 -> C:\opencv\build\include | | 連結器 | |一一般 | | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib | | |一輸入 | | 其他相依性 -> opencv_world411d.lib;%(AdditionalDependencies) // Releas | x64 組態屬性 | C/C++ | | 一般 | | 其他 Include 目錄 -> C:\opencv\build\include | | 連結器 | |一般 | | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib | | |一輸入 | | 其他相依性 -> opencv_world411.lib;%(AdditionalDependencies) */ #include "stdafx.h" #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace std; using namespace cv; void showHistogram(InputArray src, cv::String StrTitle); void pause() { printf("Press Enter key to continue..."); fgetc(stdin); } int main() { Mat src = imread("../../images/test.png"); if (src.empty()) { cout << "could not load image.." << endl; pause(); return -1; } else { imshow("input", src); showHistogram(src, "Histogram"); vector<Mat> mv; // mv用于存储图像分离后各通道像素 split(src, mv); Mat B, G, R; equalizeHist(mv[0], B); equalizeHist(mv[1], G); equalizeHist(mv[2], R); vector<Mat> combined; combined.push_back(B); combined.push_back(G); combined.push_back(R); Mat dst_bgr; merge(combined, dst_bgr); imshow("input_eq", dst_bgr); showHistogram(dst_bgr, "Histogram_eq"); Mat src_gray, dst_gray; cvtColor(src, src_gray, COLOR_BGR2GRAY); imshow("input_gray", src_gray); showHistogram(src_gray, "Histogram_gray"); equalizeHist(src_gray, dst_gray); imshow("input_gray_eq", dst_gray); showHistogram(dst_gray, "Histogram_gray_eq"); waitKey(0); } return 0; } void showHistogram(InputArray src, cv::String StrTitle) { bool blnGray = false; if (src.channels() == 1) { blnGray = true; } // 三通道/單通道 直方圖 紀錄陣列 vector<Mat> bgr_plane; vector<Mat> gray_plane; // 定义参数变量 const int channels[1] = { 0 }; const int bins[1] = { 256 }; float hranges[2] = { 0, 255 }; const float *ranges[1] = { hranges }; Mat b_hist, g_hist, r_hist, hist; // 计算三通道直方图 if (blnGray) { split(src, gray_plane); calcHist(&gray_plane[0], 1, 0, Mat(), hist, 1, bins, ranges); } else { split(src, bgr_plane); calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges); calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges); calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges); } /* * 显示直方图 */ int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double)hist_w / bins[0]); Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); // 归一化直方图数据 if (blnGray) { normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1); } else { normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1); normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1); normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1); } // 绘制直方图曲线 for (int i = 1; i < bins[0]; ++i) { if (blnGray) { line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(hist.at<float>(i - 1))), Point(bin_w * (i), hist_h - cvRound(hist.at<float>(i))), Scalar(255, 255, 255), 2, 8, 0); } else { 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); } } imshow(StrTitle, histImage); }
★Python
import cv2 as cv import numpy as np from matplotlib import pyplot as plt def custom_hist(gray): h, w = gray.shape hist = np.zeros([256], dtype=np.int32) for row in range(h): for col in range(w): pv = gray[row, col] hist[pv] += 1 y_pos = np.arange(0, 256, 1, dtype=np.int32) plt.bar(y_pos, hist, align='center', color='r', alpha=0.5) plt.xticks(y_pos, y_pos) plt.ylabel('Frequency') plt.title('Histogram') plt.show() src = cv.imread("../images/test.png") gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) cv.namedWindow("input", cv.WINDOW_AUTOSIZE) cv.imshow("input", gray) dst = cv.equalizeHist(gray) cv.imshow("eh", dst) custom_hist(gray) custom_hist(dst) cv.waitKey(0) cv.destroyAllWindows()
★結果圖:
★延伸說明/重點回顧: