【问题标题】:How to clean binary image using horizontal projection?如何使用水平投影清理二进制图像?
【发布时间】:2020-06-02 18:09:05
【问题描述】:

我想使用二进制过滤器从车牌中删除除文本以外的任何内容。

我在每个轴上都有投影,但我不知道如何应用它。我的想法是消除白色轮廓。

这是我现在正在工作的图像:

这是 X 轴上的投影:

from matplotlib import pyplot as plt
import pylab

(rows,cols)=img.shape
h_projection = np.array([ x/255/rows for x in img.sum(axis=0)])
plt.plot(range(cols), h_projection.T)

结果如下:

正如您在图表中看到的那样,线的末端是由白色轮廓拍摄的。

如何擦除照片某个阈值处的所有内容?感谢您的每一次帮助

【问题讨论】:

  • 你检查thresholding operator from OpenCV了吗?我认为这是在您要求的某个阈值处擦除所有内容。否则,如果您需要缩小白色部分以获得更清晰的图像,我可以建议检查morphological operators in OpenCV
  • 谢谢,如果我检查了文档,实际上二进制图像使用了一系列过滤器,包括阈值。问题是当程序捕获车牌时,它会留下轮廓,所以当我想分割字符时,它会使结果变得困难。根据文档,作为分割阶段的一部分,使用垂直和水平直方图是去除边缘的好方法。
  • 好的。也许您可以在直方图上再次使用阈值?我不确定你到底想要达到什么目标,你有一个例子吗?我不确定轮廓、轮廓和边缘的确切含义(据我了解,侵蚀形态算子应该有所帮助,但也许我弄错了)。或者你能指出水平和垂直直方图的文档吗?
  • 我想用 CNN 分割字符以读取它们,我在这部分 miro.medium.com/max/704/1*P4GoiHrMfvGcf-lGkXMstQ.png
  • 是的,但为什么不再次设置阈值呢?这次只是在一个维度上。如果你的数组是 numpy 数组,np.where(data < 0.25) 会给你一个数组,True 用于所有低于 0.25 的值,False 用于其余的。然后你发现了字母之间的黑色部分,如图所示,绿色突出显示的部分。如果您想要更复杂,您可以使用scipy.signal.findpeaks 在您的函数(黑色部分所在的位置)中查找局部最小值,只需使用1-your_signal 作为输入。

标签: python opencv image-processing


【解决方案1】:

因此,您想提取白色字符中的黑色区域。 例如,您可以选择直方图中值小于某个阈值的列(或行)。

from matplotlib import pyplot as plt
import pylab
import numpy as np


img = plt.imread('binary_image/iXWgw.png')
(rows,cols)=img.shape
h_projection = np.array([ x/rows for x in img.sum(axis=0)])
threshold = (np.max(h_projection) - np.min(h_projection)) / 4
print("we will use threshold {} for horizontal".format(threshold))
# select the black areas
black_areas = np.where(h_projection < threshold)
fig = plt.figure(figsize=(16,8))
fig.add_subplot(121)
for j in black_areas:
    img[:, j] = 0
    plt.plot((j, j), (0, 1), 'g-')
plt.plot(range(cols), h_projection.T)

v_projection = np.array([ x/cols for x in img.sum(axis=1)])
threshold = (np.max(v_projection) - np.min(v_projection)) / 4
print("we will use threshold {} for vertical".format(threshold))
black_areas = np.where(v_projection < threshold)
fig.add_subplot(122)
for j in black_areas:
    img[j, :] = 0
    plt.plot((0,1), (j,j), 'g-')
plt.plot(v_projection, range(rows))
plt.show()

# obscurate areas on the image
plt.figure(figsize=(16,12))
plt.subplot(211)
plt.title("Image with the projection mask")
plt.imshow(img)

# erode the features
import scipy
plt.subplot(212)
plt.title("Image after erosion (suggestion)")
eroded_img = scipy.ndimage.morphology.binary_erosion(img,  structure=np.ones((5,5))).astype(img.dtype)
plt.imshow(eroded_img)
plt.show()

现在你有了水平和垂直投影,看起来像这样

然后你可以应用掩码:有几种方法可以做到这一点,在代码中已经应用了 for 循环,我们为列设置img[:,j] = 0,为行设置img[j,:] = 0。这很简单,我认为很直观,但你可以寻找其他方法。 作为一个建议,我想说你可以查看erosion 的形态运算符,它可以帮助分离白色部分。 所以输出应该是这样的。

不幸的是,上下部分仍然显示白色区域。您可以手动将行设置为白色img[:10,:] = 0, img[100:,:] = 0,但这可能不适用于您拥有的所有图像(如果您尝试训练神经网络,我假设您有很多,所以您需要有一个代码适用于所有这些。

所以,既然您现在也要求进行细分,这就打开了另一个话题。分割是一项复杂的任务,它不像二进制掩码那样简单。我强烈建议你在不理解的情况下应用一些东西之前阅读一些关于这方面的材料。例如here a guide on image processing with scipy,但您可以寻找更多。 作为一个建议和一个小的 sn-p 使其工作,您可以使用来自 scipy.ndimage 的标签。 这里有一小部分代码(来自guide

label_im, nb_labels = scipy.ndimage.label(eroded_img)
plt.figure(figsize=(16,12))
plt.subplot(211)
plt.title("Segmentation")
plt.imshow(label_im)   
plt.subplot(212)
plt.title("One Object as an example")
plt.imshow(label_im == 6)   # change number for the others!

将输出:

作为一个例子,我展示了S 字母。如果您更改label_im == 6,您将收到下一封信。正如您将看到的那样,它并不总是正确的,图像的其他小块也被视为对象。所以你将不得不在这方面多做一些工作。

【讨论】:

  • 谢谢,现在我必须将它应用于车牌图像,我应该使用遮罩吗?
  • 这已经应用于车牌图像,我刚刚下载了您在问题上发布的图像。它托管在 imgur here 哪个面具?您想删除图片的一部分(如下面的智利文字)?
  • 我的目标是能够分割字符,没有边缘使识别复杂化(白色边框部分),有些车牌有一个小螺丝,可以将它确认到汽车,当将图像转换为二进制时,像这样的东西仍然存在:prnt.sc/ss7pct(它并不总是发生,但它可能发生),在这些情况下,它使字符分割变得困难。然后我想到了直方图的想法,让图像保持干净而没有边界问题,以便能够很好地分割字符
  • 所以通过应用直方图投影我可以使字符分割更容易和更有效,但现在我必须知道如何做到这一点(每条水平线分隔每个字符,省去图像的白色边框)
  • 别担心。很高兴为您提供帮助,希望很快见到您提出新的具体问题(:
猜你喜欢
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 2020-11-27
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多