对单数进行字符识别的方法相当容易。但这是当图像只包含一位数时。
当图像包含多个数字时,我们不能使用相同的算法,因为整个位图是不同的。我们如何处理图像来分割它,这样我们就可以“模块化”在每个单独数字上的OCR操作?
发布于 2017-07-16 09:17:20
但是您要执行的是图像分割问题,而不是数字分类问题。就像@VitaliPro说的。两者都是OCR问题,但是(在一个大简化中)第一个问题是“这个字符是什么”,第二个问题是“我在这里有多少个字符”。你已经知道如何解决第一个问题了,左看第二个问题是如何解决的。
您希望将图像分割为字符(在分割中称为“区域”),然后将数字分类应用于每个区域。一种方法是执行分水岭分割,它使用颜色的梯度来区分边缘和区域。
对于eaxmple,Python的numpy/scipy/skimage可以完成一个简单的分水岭:
#!/usr/bin/env python
from PIL import Image
import numpy as np
from scipy import ndimage
from skimage import morphology as morph
from skimage.filter import rank
def big_regions(lb, tot):
l = []
for i in range(1, tot+1):
l.append(((i == lb).sum(), i))
l.sort()
l.reverse()
return l
def segment(img, outimg):
img = np.array(Image.open(img))
den = rank.median(img, morph.disk(3))
# continuous regions (low gradient)
markers = rank.gradient(den, morph.disk(5)) < 10
mrk, tot = ndimage.label(markers)
grad = rank.gradient(den, morph.disk(2))
labels = morph.watershed(grad, mrk)
print 'Total regions:', tot
regs = big_regions(labels, tot)
在这里,我使用了来自skimage
的skimage
模块的分水岭分割。
大多数情况下,对于分水岭,您应该将区域放置在图像的顶部,以获得该区域的实际内容,而我在上面的代码中并没有这样做。然而,对于数字或大多数文本来说,这是不需要的,因为预计它是黑白的。。
分水岭使用颜色梯度来识别边缘,但也可以使用Canny或Sobel滤波器。请注意,我正在执行图像的去噪(轻微模糊),以防止发现非常小的区域,因为这些很可能是伪影或噪音。使用Canny或Sobel滤波器可能需要更多的去噪步骤,因为滤波器会产生清晰的边缘。
分割不仅用于字符分割,还常用于图像中的重要区域(即外观非常相似的大区域)的分割。例如,如果我在上面添加了一些matplotlib
tot,并更改了段函数,例如:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def plot_seg(spr, spc, sps, img, cmap, alpha, xlabel):
plt.subplot(spr, spc, sps)
plt.imshow(img, cmap=cmap, interpolation='nearest', alpha=alpha)
plt.yticks([])
plt.xticks([])
plt.xlabel(xlabel)
def plot_mask(spr, spc, sps, reg, lb, regs, cmap, xlabel):
masked = np.ma.masked_array(lb, ~(lb == regs[reg][1]))
plot_seg(spr, spc, sps, masked, cmap, 1, xlabel)
def plot_crop(spr, spc, sps, reg, img, lb, regs, cmap):
masked = np.ma.masked_array(img, ~(lb == regs[reg][1]))
crop = masked[~np.all(masked == 0, axis=1), :]
crop = crop[:, ~np.all(crop == 0, axis=0)]
plot_seg(spr, spc, sps, crop, cmap, 1, '%i px' % regs[reg][0])
def segment(img, outimg):
img = np.array(Image.open(img))
den = rank.median(img, morph.disk(3))
# continuous regions (low gradient)
markers = rank.gradient(den, morph.disk(5)) < 10
mrk, tot = ndimage.label(markers)
grad = rank.gradient(den, morph.disk(2))
labels = morph.watershed(grad, mrk)
print 'Total regions:', tot
regs = big_regions(labels, tot)
spr = 3
spc = 6
plot_seg(spr, spc, 1, img, cm.gray, 1, 'image')
plot_seg(spr, spc, 2, den, cm.gray, 1, 'denoised')
plot_seg(spr, spc, 3, grad, cm.spectral, 1, 'gradient')
plot_seg(spr, spc, 4, mrk, cm.spectral, 1, 'markers')
plot_seg(spr, spc, 5, labels, cm.spectral, 1, 'regions\n%i' % tot)
plot_seg(spr, spc, 6, img, cm.gray, 1, 'composite')
plot_seg(spr, spc, 6, labels, cm.spectral, 0.7, 'composite')
plot_mask(spr, spc, 7, 0, labels, regs, cm.spectral, 'main region')
plot_mask(spr, spc, 8, 1, labels, regs, cm.spectral, '2nd region')
plot_mask(spr, spc, 9, 2, labels, regs, cm.spectral, '3rd region')
plot_mask(spr, spc, 10, 3, labels, regs, cm.spectral, '4th region')
plot_mask(spr, spc, 11, 4, labels, regs, cm.spectral, '5th region')
plot_mask(spr, spc, 12, 5, labels, regs, cm.spectral, '6th region')
plot_crop(spr, spc, 13, 0, img, labels, regs, cm.gray)
plot_crop(spr, spc, 14, 1, img, labels, regs, cm.gray)
plot_crop(spr, spc, 15, 2, img, labels, regs, cm.gray)
plot_crop(spr, spc, 16, 3, img, labels, regs, cm.gray)
plot_crop(spr, spc, 17, 4, img, labels, regs, cm.gray)
plot_crop(spr, spc, 18, 5, img, labels, regs, cm.gray)
plt.show()
(这个示例本身不运行,您需要将上面的其他代码示例添加到它的顶部。)
我可以对任何图像进行相当好的分割,例如,上面的结果:
第一行是segmentation
函数的步骤,第二行是区域,第三行是图像顶部用作掩码的区域。
(是的,情节代码很难看,但很容易理解和改变)
发布于 2017-07-16 08:39:06
遵循以下步骤:
https://stackoverflow.com/questions/44964115
复制