在实际应用中,由于所处环境各异,包括各种采集设备的不同,采集到的液晶段码图像可能存在光照不均、倾斜、阴影、反光等各种问题,这些情况都会对液晶屏幕的定位和后续识别造成影响。为了解决这些问题,就需要对图像进行预处理操作,预处理的质量直接关系到后续的一系列操作。
图像预处理在数字图像处理中占有重要位置,它是图像处理的第一步也是图像处理的基础。本文设计了一种有效的图像预处理方法,能很好地处理光照不均的图像,为后续的液晶屏幕的定位奠定了坚实的基础。本文的图像预处理步骤可用下图表示:

图2-1 预处理流程图
2.1 灰度化
一个彩色图像可以抽象为一个三通道数组,在RGB颜色空间内,这三个通道分别R、G、B三个分量,为了降低运算量,通常要把彩色图像转换为只有一个通道的灰度图像。

函数原型:
void cv::cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0);
- src:输入图像,即源图像,你想要转换的图像。
- dst:输出图像,即目标图像,转换后的图像将存储在这里。
- code:转换类型,指定了从源颜色空间到目标颜色空间的转换方式。此时code=cv::COLOR_BGR2GRAY。
- dstCn:目标图像的通道数(可选)。
2.2 直方图均衡
当光照不均时,部分图像因亮度较低而导致对比度较低,为了增强图像局部的对比度,可对图像进行直方图均衡化操作。直方图均衡化就是把一个已知灰度概率密度分布的图像经过一种变换,使之演变为具有均匀灰度概率密度分布的新图像。过暗和过亮的图像在经过直方图均衡化后,图像会变得更加清晰。

函数原型:
void cv:: equalizeHist (InputArray src, OutputArray dst);
- src:输入图像,即源图像,你想要转换的图像。
- dst:输出图像,即目标图像,转换后的图像将存储在这里。
2.3 空间平滑滤波
直方图均衡化在增强图像的对比度和亮度的同时,也会将图像中的噪声或者一些细节凸显出来。后续的操作需要用到的边缘检测,而边缘检测算子对噪声十分敏感,因此要尽可能的去除这些噪声。
OpenCV为空间滤波提供了四种常用的滤波器:归一化块滤波器、高斯滤波器、中值滤波器、双边滤波器。在本文中,采用的是高斯滤波器。
- 归一化块滤波器:最简单的滤波器,输出的像素值是核窗口内像素值的均值(所有像素加权系数相等)。
函数原型:void cv::blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT);
- src: 输入图像。
- dst: 输出图像,其大小和类型与src相同。
- ksize: 卷积核的大小,以Size(width, height)的形式表示。核的大小必须是正数和奇数。
- anchor:锚点,默认(-1,-1),表示取核中心
- borderType: 边界推断方式,默认为BORDER_DEFAULT
- 高斯滤波器:是将输入数组的每个像素点与高斯内核卷积,将卷积和作为输出像素值。
函数原型:void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)
- src: 输入图像。
- dst: 输出图像,其大小和类型与src相同。
- ksize: 高斯核的大小,以Size(width, height)的形式表示。核的大小必须是正数和奇数。
- sigmaX: X方向上的高斯核标准差。如果为0,则从ksize.width和ksize.height自动计算。
- sigmaY: Y方向上的高斯核标准差。如果为0,则与sigmaX相同,或者从ksize.width和ksize.height自动计算。
- borderType: 边界推断方式,默认为BORDER_DEFAULT
- 中值滤波器:取当前及其周围临近总共奇数个像素点,将这些像素点排序,然后将位于中间位置的值作为当前的像素值,
函数原型:void medianBlur(InputArray src, OutputArray dst, int ksize)
- src: 输入图像。
- dst: 输出图像,其大小和类型与src相同。
- ksize: 表示内核的大小,必须是正数和奇数。
- 双边滤波器:其核心原理在于同时考虑像素的空间邻近度(空域)和像素值相似度(值域),通过两者的加权平均来计算滤波后像素值。这与传统线性滤波器(如高斯滤波)仅考虑空间距离有根本区别;在图像平坦区域,其效果类似高斯滤波,而在边缘区域,由于值域权重的作用,能有效保护边缘不被模糊。
函数原型:void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT);
- src:输入图像,支持 8 位或浮点型的单通道(灰度)或三通道(彩色)图像。
- dst:输出图像,与输入图像具有相同的尺寸和数据类型。
- d:滤波器邻域直径。若为非正数(如 -1 或 0),则根据 sigmaSpace 自动计算。
- sigmaColor:颜色空间的标准差,控制像素值相似度的权重。值越大,颜色差异较大的像素越可能被混合。
- sigmaSpace:坐标空间的标准差,控制空间邻域的影响范围。值越大,远处像素对中心像素影响越大。
- borderType(可选):边界处理模式,默认为 BORDER_DEFAULT。
2.4 二值化
二值化操作依赖于阈值,选取合适的阈值能够更好地实现二值化。常用的阈值化方法有全局阈值法和局部自适应阈值法。
大律法是一种经典的全局自适应阈值化方法,其核心思想是通过遍历灰度级,计算前景与背景的类间方差,选取使方差最大的灰度值为最佳阈值,自动将图像划分为黑白两部分。该算法无需人工设定参数,计算高效、分割效果稳定,广泛用于图像识别、OCR 文字提取、目标检测、缺陷检测等预处理环节。适用于灰度直方图呈明显双峰的图像,但对光照不均、灰度差异小的图像分割效果较差,常需结合局部阈值方法优化。
OpenCV可使用adaptiveThreshold对图像进行局部自适应二值化,该函数有两种自适应方法,分别是局部邻域块均值法和局部领域块的高斯加权和法。局部邻域块均值的方法是先对图像进行归一化滤波,然后再进行局部二值化。局部邻域块高斯加权和的方法是先对图像进行高斯滤波,然后再进行局部二值化。
函数原型:void cv::adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C);
- src :输入图像,必须为 8 位单通道灰度图像。
- dst:输出图像,与 src 大小和类型相同。
- maxValue:满足条件时像素被赋予的最大值(通常为 255)。
- adaptiveMethod :自适应阈值算法,可选:
- cv2.ADAPTIVE_THRESH_MEAN_C:使用邻域均值减去常数 C。
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C:使用邻域高斯加权平均减去常数 C。
- thresholdType :阈值类型,只能选择 :
- cv2.THRESH_BINARY:大于阈值为1 小于阈值为0
- cv2.THRESH_BINARY_INV:大于阈值为0 小于阈值为1
- blockSize :用于计算局部阈值的邻域块大小,必须为大于 1 的奇数(如 3、5、7...)。
- C:从均值或加权均值中减去的常数,可为正、负或零,用于微调阈值。
2.5 形态学降噪
通过上面的操作,已经将图像转换成二值图像,通过二值图像可以看出,无论在图像背景部分还是前景部分都存在较多的噪声,这些噪声不但增加图像处理的计算量,还会影响到图像定位的精度。要消除这些噪声,通常要采用形态学操作来处理。
用于图像降噪的形态学运算主要是开运算和闭运算,具体的选取要依据上文二值化后噪声的类型。
在实际的图像处理中,以黑色为目标,白色为背景。图像处理中开运算通常用以消除小块噪声、分离物体的纤细连接和平滑物体边界,同时又不明显改变物体面积。闭运算常用来填充物体内细小的黑色空洞、连接邻近物体、平滑其边界,同时又不明显改变体积。

2.6 程序源码
cpp
//得到灰度图
cvtColor(m_SrcImg, m_GrayImg, CV_BGR2GRAY);
//直方图均衡
equalizeHist(m_GrayImg, m_GrayImg);
//滤波处理
GaussianBlur(m_GrayImg, m_GrayImg, Size(5, 5), 0);
//二值化
adaptiveThreshold(m_GrayImg, m_BinaImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 31, 5);
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
//形态学---开运算
morphologyEx(m_BinaImg, m_MorpImg, MORPH_OPEN, kernel);
//形态学---闭运算
morphologyEx(m_MorpImg, m_MorpImg, MORPH_CLOSE, kernel);