在网上查询资料后发现OpenCV有内置函cv::inpaint(),其功能主要是修复图像中的污损区域,修复效果较好,故尝试使用。
但是在仔细查阅使用文档后发现,该函数的使用需要一个掩膜才能对图像处理,而获取掩膜的难度大,不易实现,所以放弃了这种方法。
在仔细看过待处理图片后,发现图片的待处理区域与其他区域对比度大,灰度值差距多,故采用阈值分割的方法对图片进行处理,并取得较好的结果。
通过迭代的方法获得了全局阈值T1,并对三个通道分别处理,对阈值小于T1的不做处理(灰度值低,代表正常深色区域,保留);而对大于T1的像素值置为255(设置为白色)。三个通道做上述相同处理,代码及实现结果如下:
Mat interatethreshold(Mat image)
{
Mat img = image.clone();
vector<Mat>channels;
split(img, channels);
cout << "begin to find the threshold" << endl;
for(int I = 0; I < 3; ++I)
{
double T1 = 0;
double n1 = 0, count1 = 0, n2 = 0, count2 = 0;
double T2 = 255; // 防止分母为0
while(true)
{
for(int i = 0; i < (channels[I]).rows; ++i)
{
for(int j = 0; j < (channels[I]).cols; ++j)
{
if(double((channels[I]).at<uchar>(i, j)) >= T1)
{
++n1;
count1 += double((channels[I]).at<uchar>(i, j)); // 统计阈值两边的像素值和个数
}
else
{
++n2;
count2 += double((channels[I]).at<uchar>(i, j));
}
}
}
double temp1 = count1 / n1;
double temp2 = count2 / n2;
T2 = (temp1 + temp2) / 2.0;
if(abs(T2 - T1) <= 1e-3)
break;
else
{
T1 = T2;
}
}
for(int i = 0; i < (channels[I]).rows; ++i)
{
for(int j = 0; j < (channels[I]).cols; ++j)
{
if((double)(channels[I]).at<uchar>(i, j) > T2)
(channels[I]).at<uchar>(i, j) = 255;
}
}
}
merge(channels, img);
return img;
}
可以看出效果已经非常好,达到了要求,但是仔细观察可发现图片中的横线不是很清晰,也有一些没有处理完的痕迹,所以进行第二步操作;
利用灰度线性变换提高图片的清晰度,并将灰度范围提升至_[0, 255]_之间,实现代码及效果如下:
Mat linearTransform(Mat image)
{
Mat image_1 = image.clone();
//首先遍历图片,找出现在灰度值范围
//首先检测是否是多通道图片
//多通道图片需要分通道变换
double channel = image_1.channels();
int rows = image.rows, cols = image.cols;
//如果是单通道图片
if(image.channels()==1)
{
double max = 0;
double min = 255;
double c = 0, d = 255;
//统计现在灰度分布
for(int i=0;i<rows;i++)
for(int j = 0; j<cols;j++)
{
double temp = image_1.at<uchar>(i,j);
// cout<
if(temp > max)
max = temp;
if(temp < min)
min = temp;
}
cout<<min<<" "<<max<<endl;
//进行线性灰度变换
for ( int i = 0; i<rows; i++)
for ( int j = 0; j<cols; j++)
{
double temp= ( d - c )/( max - min ) * (double(image_1.at<uchar>(i,j))- min)+c;
image_1.at<uchar>(i,j) = (temp);
}
return image_1;
}
//如果是三通道的图片,需要对每个通道分别处理
else
{
//cout<<"hhhhh"<
vector<Mat>channels;
split(image_1,channels);
int count = 0;//记录当前通道数
while(count!=channel)
{
double c = 0, d = 255;
double max = 0 , min = 255;
for(int i = 0; i<rows;i++)
for (int j = 0; j<cols; j++)
{
double temp =channels[count].at<uchar>(i,j);
// cout<
if(temp > max)
max = temp;
if(temp < min)
min = temp;
}
for(int i = 0; i<rows;i++)
for (int j = 0; j<cols; j++)
{
double temp= ( d - c )/( max - min ) * (double(channels[count].at<uchar>(i,j))- min)+c;
channels[count].at<uchar>(i,j) = temp;
}
count++;
}
merge(channels, image_1);
return image_1;
}
}
经过两次尝试后在阈值分割方法得到了几乎完美的结果,实现源码如下:
#include
#include
#include
using namespace std;
using namespace cv;
// 图片路径
const string path = "/home/xz/coding/imageprocess/finalproject/test.jpg";
/**
* @param image 待处理图像
*
* 本函数用于处理图像扫描后背景有干扰内容
*/
Mat interatethreshold(Mat img);
/**
* @param image 待变换图像
*
* 本函数用以进行灰度线性变换,变换至0~255之间
*/
Mat linearTransform(Mat image);
int main()
{
Mat img = imread(path);
Mat thres = interatethreshold(img); //寻找阈值
Mat result = linearTransform(thres); // 增强处理后的图片
cout << "successfully processed" << endl;
imshow("original", img);
imshow("test_cut", thres);
imshow("result", result);
waitKey(0);
destroyAllWindows();
imwrite("/home/xz/coding/imageprocess/finalproject/nice.jpg", result);
imwrite("/home/xz/coding/imageprocess/finalproject/_1.jpg", thres);
return 0;
}
Mat interatethreshold(Mat image)
{
Mat img = image.clone();
vector<Mat>channels;
split(img, channels);
cout << "begin to find the threshold" << endl;
for(int I = 0; I < 3; ++I)
{
double T1 = 0;
double n1 = 0, count1 = 0, n2 = 0, count2 = 0;
double T2 = 255; // 防止分母为0
while(true)
{
for(int i = 0; i < (channels[I]).rows; ++i)
{
for(int j = 0; j < (channels[I]).cols; ++j)
{
if(double((channels[I]).at<uchar>(i, j)) >= T1)
{
++n1;
count1 += double((channels[I]).at<uchar>(i, j)); // 统计阈值两边的像素值和个数
}
else
{
++n2;
count2 += double((channels[I]).at<uchar>(i, j));
}
}
}
double temp1 = count1 / n1;
double temp2 = count2 / n2;
T2 = (temp1 + temp2) / 2.0;
if(abs(T2 - T1) <= 1e-3)
break;
else
{
T1 = T2;
}
}
for(int i = 0; i < (channels[I]).rows; ++i)
{
for(int j = 0; j < (channels[I]).cols; ++j)
{
if((double)(channels[I]).at<uchar>(i, j) > T2)
(channels[I]).at<uchar>(i, j) = 255;
}
}
}
merge(channels, img);
return img;
}
Mat linearTransform(Mat image)
{
Mat image_1 = image.clone();
//首先遍历图片,找出现在灰度值范围
//首先检测是否是多通道图片
//多通道图片需要分通道变换
double channel = image_1.channels();
int rows = image.rows, cols = image.cols;
//如果是单通道图片
if(image.channels()==1)
{
double max = 0;
double min = 255;
double c = 0, d = 255;
//统计现在灰度分布
for(int i=0;i<rows;i++)
for(int j = 0; j<cols;j++)
{
double temp = image_1.at<uchar>(i,j);
// cout<
if(temp > max)
max = temp;
if(temp < min)
min = temp;
}
cout<<min<<" "<<max<<endl;
//进行线性灰度变换
for ( int i = 0; i<rows; i++)
for ( int j = 0; j<cols; j++)
{
double temp= ( d - c )/( max - min ) * (double(image_1.at<uchar>(i,j))- min)+c;
image_1.at<uchar>(i,j) = (temp);
}
return image_1;
}
//如果是三通道的图片,需要对每个通道分别处理
else
{
//cout<<"hhhhh"<
vector<Mat>channels;
split(image_1,channels);
int count = 0;//记录当前通道数
while(count!=channel)
{
double c = 0, d = 255;
double max = 0 , min = 255;
for(int i = 0; i<rows;i++)
for (int j = 0; j<cols; j++)
{
double temp =channels[count].at<uchar>(i,j);
// cout<
if(temp > max)
max = temp;
if(temp < min)
min = temp;
}
for(int i = 0; i<rows;i++)
for (int j = 0; j<cols; j++)
{
double temp= ( d - c )/( max - min ) * (double(channels[count].at<uchar>(i,j))- min)+c;
channels[count].at<uchar>(i,j) = temp;
}
count++;
}
merge(channels, image_1);
return image_1;
}
}