从二值图像中移除特征

1 投票
3 回答
1807 浏览
提问于 2025-04-18 00:14

我写了一个小脚本,可以把黑板的照片处理成我可以打印出来并做标记的格式。

我处理的图片是这样的:

在这里输入图片描述

我会自动裁剪这个图片,并把它变成黑白的。下面是脚本处理后的结果:

在这里输入图片描述

我想把图片中最大的黑色区域去掉。有简单的方法可以做到这一点吗?

我在想可以先把图片“侵蚀”一下,这样就能去掉文字,然后再把处理后的图片从原来的黑白图片中减掉,但我总觉得还有更合适的方法。

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);

在这里输入图片描述

将来,你可以了解一下自适应阈值和如何在局部采样颜色。我个人觉得在图像梯度的正交方向上采样二值颜色(也就是在两侧采样)是很有用的。这样,白色和黑色的样本大小是相等的,这一点很重要,因为通常背景颜色会更多,从而影响估计结果。使用SWTMSER可能会给你更多关于文本分割的思路。

撰写回答