一、算法目标:
实现这种背景去除增强的效果,特别是在“全能扫描王”中该算法得到了典型的应用。
二、使用PS进行模拟
图像处理算法很多时候就是对成熟经验的模拟和复现。首先我们来看PS下的处理。
1.手机拍一张需要电子版的纸质文件:
2.打开PS,复制背景,得到图层1:
3.对图层1使用滤镜:高斯模糊,半径100像素:
4.改变图层1混合模式:划分:
5.添加曲线调整层,压暗文字:
图像A,B,为同一场景在不一样的光照拍摄图片,那么: 光照分布 L = A / B 如果已知 A, L ,则 B = A / L (B 为A去光照的结果) 这里L约等于 gaussFilter(A, 大核)
Mat src = imread("t1.jpeg"); src.convertTo(src,CV_32FC3,1.0/255); Mat gauss; Mat dst = src.clone(); cv::GaussianBlur(src,gauss,Size(101,101),0); //划分 //如果混合色与基色相同则结果色为白色 //如混合色为白色则结果色为基色不变 //如混合色为黑色则结果色为白色 dst = src/gauss; waitKey();
//USM图像增 void ImageSharp(Mat &src,Mat &dst,int nAmount = 1000) { double sigma = 3; int threshold = 1; float amount = nAmount/100.0f; Mat imgBlurred; GaussianBlur(src, imgBlurred, Size(), sigma, sigma); Mat lowContrastMask = abs(src-imgBlurred)<threshold; dst = src*(1+amount)+imgBlurred*(-amount); src.copyTo(dst, lowContrastMask); } int main() { Mat src = imread("E:\未来项目\白板增强\images\t1.jpeg"); src.convertTo(src,CV_32FC3,1.0/255); Mat gauss; Mat dst1 = src.clone(); Mat dst2 = src.clone(); cv::GaussianBlur(src,gauss,Size(101,101),0); dst1 = src/gauss; blur(src,gauss,Size(101,101)); dst2 = src/gauss; //划分 ImageSharp(dst2,dst2,101); waitKey(); return 0; }
“这个算法在此类图像中能够成功的核心是:在原图中比较黑的文字部分,占用的整体是比较少的,当大半径模糊时,模糊的值是接近纸张之类的颜色的,也就是比较靠近白色,所以结果基本上没什么变化,而纸张那些地方的颜色,因为模糊的值和他们的原始值基本差不多,所以Src/Blur基本接近1,在乘以255,所以结果就变为白色了。”
divide Performs per-element division of two arrays or a scalar by an array. C++: void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1) C++: void divide(double scale, InputArray src2, OutputArray dst, int dtype=-1) Python: cv2.divide(src1, src2[, dst[, scale[, dtype]]]) → dst Python: cv2.divide(scale, src2[, dst[, dtype]]) → dst C: void cvDiv(const CvArr* src1, const CvArr* src2, CvArr* dst, double scale=1) Python: cv.Div(src1, src2, dst, scale=1) → None Parameters: src1 – first input array. src2 – second input array of the same size and type as src1. scale – scalar factor. dst – output array of the same size and type as src2. dtype – optional depth of the output array; if -1, dst will have depth src2.depth(), but in case of an array-by-array division, you can only pass -1 when src1.depth()==src2.depth(). The functions divide divide one array by another: or a scalar by an array when there is no src1 : When src2(I) is zero, dst(I) will also be zero. Different channels of multi-channel arrays are processed independently.