前言:
在令人讨厌的的自动屏保中突然看到一张漂亮的图片(懂就行!),就想赶紧按了键盘上的截屏键,当发现无法去掉上面的文字。
于是乎,图像处理的我就和邱邱一起研究如何将其去掉。
思路:
该图片上的文字和特别,特别在其实白色的。白色——在cv中简直就是最大的特征——三通道全是255!!
开始进行:将制定文字区域截取出来,直接上我的嘴子奥西最小值滤波。
效果:
代码:
代码就非常简单了,使用了两个函数:(1)最小值滤波;(2)区域截取与复制
//功能:截取图像IntImg的指定区域,区域为:从(x_stare,y_stare)坐标开始,截取大小为 x_dustance, y_dustance(x和y方向的尺寸)
//返回:指定区域已经被去掉字符
Mat FilerMinEraseTxt(Mat IntImg, int x_stare, int y_stare, int x_dustance, int y_dustance)
{
auto rect = cv::Rect(x_stare, y_stare, x_dustance, y_dustance );//( 1107.291)
Mat image_roi = IntImg(rect);
Mat ert = MinFilterForColor(image_roi, 5);
Mat roi = ert;
//设置画布绘制区域并复制
cv::Rect roi_rect = cv::Rect(x_stare, y_stare, x_dustance, y_dustance);
roi.copyTo(IntImg(roi_rect));//将ert这个很小的区域图像,复制到IntImg这个大图像中,具体的复制坐标位置为:roi_rect这个区域
return IntImg;
}
//功能:最小值滤波__彩色(针对白色字体的去除)
//输入:彩色图像,最小值滤波的滤波核大小
Mat MinFilterForColor(Mat src, int kernel)
{
vector<Mat>m;
split(src, m); //提取通道信息,但是当未把其他通道设置为0时显示为灰度图,但各通道信息不同
Mat R = m[0].clone();
Mat G = m[1].clone();
Mat B = m[2].clone();
int r = (kernel - 1) / 2;
Mat dst(src.size(), CV_8UC1);
Mat dst1(src.size(), CV_8UC1);
Mat dst2(src.size(), CV_8UC1);
//for (int p=0;p<2;p++)
{
Mat dst_ex;
copyMakeBorder(R, dst_ex, r, r, r, r, BORDER_CONSTANT, Scalar(255));
for (int i = r; i < dst_ex.rows - r; i++)
{
for (int j = r; j < dst_ex.cols - r; j++)
{
int minVal = dst_ex.at<uchar>(i, j);
for (int s = -r; s < r + 1; s++)
{
for (int t = -r; t < r + 1; t++)
{
if (dst_ex.at<uchar>(i + s, j + t) < minVal)
{
minVal = dst_ex.at<uchar>(i + s, j + t);
}
}
}
dst.at<uchar>(i - r, j - r) = minVal;
}
}
}
//for (int p=0;p<2;p++)
{
Mat dst_ex;
copyMakeBorder(G, dst_ex, r, r, r, r, BORDER_CONSTANT, Scalar(255));
for (int i = r; i < dst_ex.rows - r; i++)
{
for (int j = r; j < dst_ex.cols - r; j++)
{
int minVal = dst_ex.at<uchar>(i, j);
for (int s = -r; s < r + 1; s++)
{
for (int t = -r; t < r + 1; t++)
{
if (dst_ex.at<uchar>(i + s, j + t) < minVal)
{
minVal = dst_ex.at<uchar>(i + s, j + t);
}
}
}
dst1.at<uchar>(i - r, j - r) = minVal;
}
}
}
//for (int p=0;p<2;p++)
{
Mat dst_ex;
copyMakeBorder(B, dst_ex, r, r, r, r, BORDER_CONSTANT, Scalar(255));
for (int i = r; i < dst_ex.rows - r; i++)
{
for (int j = r; j < dst_ex.cols - r; j++)
{
int minVal = dst_ex.at<uchar>(i, j);
for (int s = -r; s < r + 1; s++)
{
for (int t = -r; t < r + 1; t++)
{
if (dst_ex.at<uchar>(i + s, j + t) < minVal)
{
minVal = dst_ex.at<uchar>(i + s, j + t);
}
}
}
dst2.at<uchar>(i - r, j - r) = minVal;
}
}
}
vector<Mat>mn;
mn.push_back(dst);
mn.push_back(dst1);
mn.push_back(dst2);
Mat Rchannels;
merge(mn, Rchannels);
return Rchannels;
}
调用方法:
int main()
{
Mat src1 = cv::imread("C:\\Users\\Administrator\\Downloads\\11.bmp");
imshow("含有文字图像", src1);
Mat r= FilerMinEraseTxt(src1, 827, 267, 200, 24);
Mat r1 = FilerMinEraseTxt(r, 1026, 268, 100, 24);
Mat r2 = FilerMinEraseTxt(r1, 907, 314, 1041 - 907, 338 - 314);
imshow("去掉文字图像",r2);
waitKey(0);
}
写在最后:
这个过程是非常简单的,不登大雅之堂,但是其思路和方法值得初学者思考。
整个代码也没有做任何优化,健壮性也没有测试。