如何从图像中分离出手写数字候选?

2024-06-29 01:14:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我实现了一个基于MNIST dataset识别手写数字的神经网络。我正在使用裸python/numpy,现在我想在网络上测试我自己的手写图像。不过,我想自动化裁剪和缩放过程,这样我就可以提供一个由智能手机拍摄的图像,并获得一个mnist格式的numpy数组。你知道吗

到目前为止,我已经取得了一些成功,但我真的不知道如何从这里开始。 这是两个示例图像,位于各自的遮罩图像下方,遮罩图像是原始图像大小的一半,用于缩小搜索范围:

image of a 4image of a 7

Processed Image of a 4Processed Image of a 7

正如你所看到的,发生了一些事情,但并不令人满意。如果我把“4”和“7”分割得很好,也不知道该怎么处理。如何获得精确的位置,以便我可以裁剪并缩小到28x28像素?

生成这些图像的代码如下所示。它基本上是计算x和y像素空间轴的空间直方图,然后将所有不包含足够黑色的东西都涂黑。 plot()和hist()只是一些方便的函数,但确实会生成您看到的图像,所以我将它们包括在内。你知道吗

import matplotlib.pyplot as plt
from matplotlib.ticker import NullFormatter
import numpy as np
from PIL import Image

def hists(x, y):

    histx,_ = np.histogram(np.arange(len(x)), bins=len(x), weights=x)
    histy,_ = np.histogram(np.arange(len(y)), bins=len(y), weights=y)
    return histx, histy

def plot(ndimg):

    w, h = ndimg.shape

    x = np.mean(ndimg, axis=0)
    x -= np.mean(x)
    y = np.mean(ndimg, axis=1)
    y -= np.mean(y)

    nullfmt = NullFormatter()

    left, width = 0.1, 0.65*h/w if w > h else 0.65
    bottom, height = 0.1, 0.65*w/h if h > w else 0.65
    left_h = left + width + 0.02
    bottom_h = bottom + height + 0.02

    rect_img = [left, bottom, width, height]
    rect_histx = [left, bottom_h, width, 0.2]
    rect_histy = [left_h, bottom, 0.2, height]

    plt.figure(1, figsize=(8, 8))

    axImg = plt.axes(rect_img)
    axHistx = plt.axes(rect_histx)
    axHisty = plt.axes(rect_histy)

    axHistx.xaxis.set_major_formatter(nullfmt)
    axHisty.yaxis.set_major_formatter(nullfmt)

    axImg.imshow(ndimg, cmap=plt.get_cmap('gray'))

    axHistx.hist(np.arange(len(x)), bins=int(0.03*len(x)), weights=x)
    axHisty.hist(np.arange(len(y)), bins=int(0.03*len(y)), weights=y, 
                 orientation='horizontal')

    axHistx.set_xlim(axImg.get_xlim())
    axHisty.set_ylim(axImg.get_ylim())

    plt.show()

def mask(ndimg, bw_threshhold=0.6, mask_threshhold=5e-3):
    ndimg = ndimg / np.max(ndimg)
    ndimg = np.where(ndimg < bw_threshhold, 0.0, 1.0)
    #ndimg = np.exp(-np.logaddexp(0, -10*(ndimg-0.6)))

    x = np.mean(ndimg, axis=0)
    #x = x - np.mean(x)
    y = np.mean(ndimg, axis=1)
    #y = y - np.mean(y)

    histx, histy = hists(x, y)
    histx = histx - np.mean(histx)
    histy = histy - np.mean(histy)
    #histx -= (histx.max() + histx.min())/2
    #histy -= (histy.max() + histy.min())/2

    maskx = np.where(histx < mask_threshhold, False, True)
    masky = np.where(histy < mask_threshhold, False, True)

    ndimg[masky, :] = 0.
    ndimg[:, maskx] = 0.
    return ndimg

img = Image.open('C:/Users/maxid/Desktop/Pics/7_1.jpg')
                 .convert(mode='L')
w, h = img.size
img = img.crop((0.25*w, 0.25*h, 0.75*w, 0.75*h))
ndimg = np.asarray(img)
plot(ndimg)
ndimg = mask(ndimg, )
plot(ndimg)
a, b = hists(np.mean(ndimg, axis=0), np.mean(ndimg, axis=1))
print((a.max()+a.min())/2, np.mean(a), np.median(a))
plt.plot(a)

所以,我想以一个手写数字的正方形图像结束,这个图像大致显示在图片的中间。对于这一点,它可能足以得到中间的数字,但我想不出一个简单和半可靠(不一定是生产级)的方法来做到这一点。你知道吗


Tags: rect图像imglenplotnppltmask