一種基於Opencv文檔圖像增強算法的實現


因爲項目需要對文檔圖像進行增強,也就是對於模糊、亮度偏暗或不均勻的文檔進行處理方便後續的識別。傳圖圖像增強方法主要分爲兩方面:空間域和頻域。空間閾中增強方法,顏色的增強,如:直方圖均衡化,對比度以及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;
}

參考連接:

camscanner(掃描全能王)功能解析與復現

掃描效果圖像增強


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章