从二值图像中移除特征
我写了一个小脚本,可以把黑板的照片处理成我可以打印出来并做标记的格式。
我处理的图片是这样的:
我会自动裁剪这个图片,并把它变成黑白的。下面是脚本处理后的结果:
我想把图片中最大的黑色区域去掉。有简单的方法可以做到这一点吗?
我在想可以先把图片“侵蚀”一下,这样就能去掉文字,然后再把处理后的图片从原来的黑白图片中减掉,但我总觉得还有更合适的方法。
3 个回答
1
这里有一个用Python和numpy实现的方法,使用了我自己的mahotas库,跟最优答案的方法差不多,我觉得:
import mahotas as mh
import numpy as np
用标准的缩写导入了mahotas和numpy
im = mh.imread('7Esco.jpg', as_grey=1)
加载图像并转换为灰度图
im2 = im[::2,::2]
im2 = mh.gaussian_filter(im2, 1.4)
对图像进行下采样和模糊处理(这样可以加快速度并去除噪声)。
im2 = 255 - im2
将图像反转
mean_filtered = mh.convolve(im2.astype(float), np.ones((9,9))/81.)
均值滤波是通过卷积手动实现的。
imc = im2 > mean_filtered - 4
你可能需要调整这里的数字4
,不过这个数字对这张图像效果很好。
mh.imsave('binarized.png', (imc*255).astype(np.uint8))
将图像转换为8位并保存为PNG格式。
2
我试了这个:
import numpy as np
import cv2
im = cv2.imread('image.png')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
grayout = 255*np.ones((im.shape[0],im.shape[1],1), np.uint8)
blur = cv2.GaussianBlur(gray,(5,5),1)
thresh = cv2.adaptiveThreshold(blur,255,1,1,11,2)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
wcnt = 0
for item in contours:
area =cv2.contourArea(item)
print wcnt,area
[x,y,w,h] = cv2.boundingRect(item)
if area>10 and area<200:
roi = gray[y:y+h,x:x+w]
cntd = 0
for i in range(x,x+w):
for j in range(y,y+h):
if gray[j,i]==0:
cntd = cntd + 1
density = cntd/(float(h*w))
if density<0.5:
for i in range(x,x+w):
for j in range(y,y+h):
grayout[j,i] = gray[j,i];
wcnt = wcnt + 1
cv2.imwrite('result.png',grayout)
你需要平衡两件事,一方面要去掉黑点,另一方面又不能丢失板子上的内容。我得到的结果是这个:
7
当然,你可以通过使用找轮廓(findContours)或填充(floodFill)的方法来获取某些大小的连通区域,然后把它们擦除,留下些许痕迹。不过,如果你想做得更好,就得想想为什么一开始会有黑色区域。
你没有使用自适应阈值(也就是局部自适应),这导致你的输出对阴影很敏感。试着在一开始就避免出现黑色区域,可以尝试运行类似下面的代码:
Mat img = imread("desk.jpg", 0);
Mat img2, dst;
pyrDown(img, img2);
adaptiveThreshold(255-img2, dst, 255, ADAPTIVE_THRESH_MEAN_C,
THRESH_BINARY, 9, 10); imwrite("adaptiveT.png", dst);
imshow("dst", dst);
waitKey(-1);
将来,你可以了解一下自适应阈值和如何在局部采样颜色。我个人觉得在图像梯度的正交方向上采样二值颜色(也就是在两侧采样)是很有用的。这样,白色和黑色的样本大小是相等的,这一点很重要,因为通常背景颜色会更多,从而影响估计结果。使用SWT和MSER可能会给你更多关于文本分割的思路。