调用:
cv::Mat ref_glass, src_glass; cv::Mat dst_glass = cv::Mat::zeros(src_glass.rows, src_glass.cols, src_glass.type()); HistSpecify(src_glass, ref_glass, dst_glass);
class Histogram1D { private: int histSize[1]; // 项的数量 float hranges[2]; // 统计像素的最大值和最小值 const float* ranges[1]; int channels[1]; // 仅计算一个通道 public: Histogram1D() { // 准备1D直方图的参数 histSize[0] = 256; hranges[0] = 0.0f; hranges[1] = 255.0f; ranges[0] = hranges; channels[0] = 0; } cv::Mat getHistogram(const cv::Mat &image) { cv::Mat hist; // 计算直方图 calcHist(&image,// 要计算图像的 1, // 只计算一幅图像的直方图 channels, // 通道数量 cv::Mat(), // 不使用掩码 hist, // 存放直方图 1, // 1D直方图 histSize, // 统计的灰度的个数 ranges); // 灰度值的范围 return hist; } cv::Mat getHistogramImage(const cv::Mat &image) { cv::Mat hist = getHistogram(image); //查找最大值用于归一化 double maxVal = 0; minMaxLoc(hist, NULL, &maxVal); //绘制直方图的图像 cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255)); // 设置最高点为最大值的90% double hpt = 0.9 * histSize[0]; //每个条目绘制一条垂直线 for (int h = 0; h < histSize[0]; h++) { //直方图的元素类型为32位浮点数 float binVal = hist.at<float>(h); int intensity = static_cast<int>(binVal * hpt / maxVal); line(histImg, cv::Point(h, histSize[0]), cv::Point(h, histSize[0] - intensity), cv::Scalar::all(0)); } return histImg; } }; /** * @brief HistSpecify 对灰度图像进行直方图规定化 * @param src 输入图像 * @param ref 参考图像,解析参考图像的直方图并用于规定化 * @param result 直方图规定化后的图像 * @note 手动设置一个直方图并用于规定化比较麻烦,这里使用一个参考图像来进行 */ static void HistSpecify(const cv::Mat &src, const cv::Mat &ref, cv::Mat &result) { Histogram1D hist1D; cv::Mat src_hist = hist1D.getHistogram(src); cv::Mat dst_hist = hist1D.getHistogram(ref); float src_cdf[256] = { 0 }; float dst_cdf[256] = { 0 }; // 直方图进行归一化处理 src_hist /= (src.rows * src.cols); dst_hist /= (ref.rows * ref.cols); // 计算原始直方图和规定直方图的累积概率 for (int i = 0; i < 256; i++) { if (i == 0) { src_cdf[i] = src_hist.at<float>(i); dst_cdf[i] = dst_hist.at<float>(i); } else { src_cdf[i] = src_cdf[i - 1] + src_hist.at<float>(i); dst_cdf[i] = dst_cdf[i - 1] + dst_hist.at<float>(i); } } // 累积概率的差值 float diff_cdf[256][256]; for (int i = 0; i < 256; i++) for (int j = 0; j < 256; j++) diff_cdf[i][j] = fabs(src_cdf[i] - dst_cdf[j]); // 构建灰度级映射表 cv::Mat lut(1, 256, CV_8U); for (int i = 0; i < 256; i++) { // 查找源灰度级为i的映射灰度 // 和i的累积概率差值最小的规定化灰度 float min = diff_cdf[i][0]; int index = 0; for (int j = 1; j < 256; j++) { if (min > diff_cdf[i][j]) { min = diff_cdf[i][j]; index = j; } } lut.at<uchar>(i) = static_cast<uchar>(index); } // 应用查找表,做直方图规定化 LUT(src, lut, result); }