对彩色图像进行直方图均衡化,一般是通过对HSV色彩空间的V通道进行直方图均衡化,再合并H,S,V三个通道后转化为RGB空间。(其实V通道简单来说就是图像明暗通道,增加V通道值的效果等同于windows照片编辑中的光线调整,如下图,S通道则相当于windows照片编辑中的颜色调整(饱和度))
彩色图像直方图均衡化示例代码为:
import cv2
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
img = cv2.imread("pic.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
v2 = cv2.equalizeHist(v)
img2 = cv2.merge([h, s, v2])
rgb = cv2.cvtColor(img2, cv2.COLOR_HSV2RGB)
plt.imshow(rgb)
plt.show()
但是一定要注意应用目的,在图像整体都是偏亮时,这样直方图均衡化会导致图像最终颜色失真。
遇到的问题描述:
Easypr项目中通过颜色定位车牌(colorMatch函数),但是却无法正确识别出颜色,效果如下:
将图片裁剪后却能识别(裁掉背景区域),效果如下:
最终检查,问题出在代码中的直方图均衡化:在不存在较暗区域的图片中进行v通道的直方图均衡化后,会导致原先符合V阈值的蓝色区域,其V值被拉伸到了低于阈值的部分,因此颜色识别失败。(原项目中的车牌图像数据集所包含的场景大多为车身+周围环境,但是目前我的实验数据集有一部分是只有车牌+车牌附近的区域,因此出现了这种问题)
原项目有问题部分的代码(core_func.hpp->colorMatch())如下,在注释equalizeHist那一行之后,蓝色车牌部分能够被正确识别:
Mat colorMatch(const Mat &src, Mat &match, const Color r,
const bool adaptive_minsv) {
/*去掉了很多其余代码*/
/*阈值设定...*/
Mat src_hsv;
// convert to HSV space
cvtColor(src, src_hsv, CV_BGR2HSV);
std::vector<cv::Mat> hsvSplit;
split(src_hsv, hsvSplit);
// 这种操作不适用于所有图片
equalizeHist(hsvSplit[2], hsvSplit[2]);
merge(hsvSplit, src_hsv);
for (int i = 0; i < nRows; ++i) {
p = src_hsv.ptr<uchar>(i);
for (int j = 0; j < nCols; j += 3) {
int H = int(p[j]); // 0-180
int S = int(p[j + 1]); // 0-255
int V = int(p[j + 2]); // 0-255
bool colorMatched = false;
if (H > min_h && H < max_h) {
// 同理,因为equalizeHist不适用,因此对V进行比较意义也不大
// 因为有些拍照环境光线都很暗
if ((S > min_sv && S < max_sv) && (V > min_sv && V < max_sv))
colorMatched = true;
}
if (colorMatched == true) {
p[j] = 0;
p[j + 1] = 0;
p[j + 2] = 255;
}
else {
p[j] = 0;
p[j + 1] = 0;
p[j + 2] = 0;
}
}
}
Mat src_grey;
std::vector<cv::Mat> hsvSplit_done;
split(src_hsv, hsvSplit_done);
src_grey = hsvSplit_done[2];
match = src_grey;
return src_grey;
}