因为项目需要对文档图像进行增强,也就是对于模糊、亮度偏暗或不均匀的文档进行处理方便后续的识别。传图图像增强方法主要分为两方面:空间域和频域。空间阈中增强方法,颜色的增强,如:直方图均衡化,对比度以及gama增强等;模糊,如:均值滤波等;锐化,如:局部标准差实现对比度增强。频域方法,如:小波变换,在图像的某个变换域内,对图像的变换系数进行运算,然后通过逆变换获得图像增强效果。一般来说,对于实际项目中,可能用其中一种或几种方法来进行图像增强效果一般会很差,我们更多的是对这些算法进行融合,来达到我们想要的效果。
1、基于划分模式的图像增强
假设我们有图像A、B,分别为同一场景在不一样的光照拍摄图片,其中A表示基色 ,B表示混合色。那么我们对该场景下的光照分布进行建模得到,划分模式的计算公式:结果色 = (基色 / 混合色) *255。
- 具体什么意思呢?
我们分析每个通道的数值,并基于基色进行增强,如果基色数值大于或等于混合色,那么结果色就为白色;如果基色小于混合色,结果会比基色更暗。
- 这个算法为什么比较适合文档图像增强?
我们知道文档图像一般主要有文字和背景组成。其中文字为黑色,背景为白色。如果单纯的进行对比度之类的增强,对于较亮或较暗的图像确实有效,但对于文档,这种方法反而使得文本部分缺失,反而没有达到增强的效果。基于划分模式的图像增强,正是考虑这点,他对于暗的,如:字体,会变的更暗,对于亮的,如:背景,会变的更亮。
- 具体怎么实现?
问题规范为图像A,B,为同一场景在不一样的光照拍摄图片,那么:
光照分布 L = A / B
如果已知 A, L ,则 B = A / L (B 为A去光照的结果)
这里,A表示我们需要增强的图片,B表示经过高斯滤波后的图片。那么,我们进行A/B就得到增强后的图像了。是不是很简单。
2、基于c++ OpenCV的实现
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat image = imread("./pic/raw.png");
//划分算法
//如果混合色与基色相同则结果色为白色
//如混合色为白色则结果色为基色不变
//如混合色为黑色则结果色为白色
Mat src = image.clone();
src.convertTo(src, CV_32FC3, 1.0 / 255);
Mat gauss;
Mat dst = src.clone();
GaussianBlur(src, gauss, Size(101, 101), 0);
dst = src / gauss;
dst.convertTo(dst, CV_8UC3, 255);
imshow("dst", dst);
waitKey();
return 0;
}
结果展示:
3、辅助增强算法
我们看到部分图像处理的并不好,如第1、3行,处理后的结果存在大量的黑色噪声,所以后续可以使用其它增强的算法来辅助进行。这里我们选择gamma对比度增强算法。具体实现如下:
//Gamma校正 fGamaa=0.45是常用值
void GammaCorrection(Mat& src, Mat& dst, float fGamma)
{
CV_Assert(src.data);
// accept only char type matrices
CV_Assert(src.depth() != sizeof(uchar));
// build look up table
unsigned char lut[256];
for (int i = 0; i < 256; i++)
{
lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
}
dst = src.clone();
const int channels = dst.channels();
switch (channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
*it = lut[(*it)];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)
{
(*it)[0] = lut[((*it)[0])];
(*it)[1] = lut[((*it)[1])];
(*it)[2] = lut[((*it)[2])];
}
break;
}
}
}
完整代码如下:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//Gamma校正 fGamaa=0.45是常用值
void GammaCorrection(Mat& src, Mat& dst, float fGamma)
{
CV_Assert(src.data);
// accept only char type matrices
CV_Assert(src.depth() != sizeof(uchar));
// build look up table
unsigned char lut[256];
for (int i = 0; i < 256; i++)
{
lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
}
dst = src.clone();
const int channels = dst.channels();
switch (channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
*it = lut[(*it)];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)
{
(*it)[0] = lut[((*it)[0])];
(*it)[1] = lut[((*it)[1])];
(*it)[2] = lut[((*it)[2])];
}
break;
}
}
}
int main(int argc, char** argv)
{
Mat image = imread("./pic/raw.jpg");
划分算法
//如果混合色与基色相同则结果色为白色
//如混合色为白色则结果色为基色不变
//如混合色为黑色则结果色为白色
Mat src = image.clone();
src.convertTo(src, CV_32FC3, 1.0 / 255);
Mat gauss;
Mat dst = src.clone();
GaussianBlur(src, gauss, Size(101, 101), 0);
dst = src / gauss;
dst.convertTo(dst, CV_8UC3, 255);
gamma变换
Mat matGamma;
GammaCorrection(dst.clone(), matGamma,1.5);
//显示最终结果
//namedWindow("Soure", 0);
namedWindow("dst", 0);
imshow("Soure", image);
imshow("dst", matGamma);
waitKey();
return 0;
}
参考连接:
来源:oschina
链接:https://my.oschina.net/u/4330033/blog/4906391