判别数字图片能否「一笔完成」

每张给定的数字图片只有2种像素值,即0和255,如下所示:
实例1
现给定全黑的一张背景图,用一支笔可以连续地在上下左右斜对角共8个方向移动,可以允许重复地经过一处。笔经过处像素值会变为0,即变成白色。如果这样操作后能得到一张如上所示的数字图片,则称该数字图片可以「一笔完成」。

下面是不能「一笔完成」的数字图片例子:
实例2
因为要完成“6”中间部分的「白圈」,必须要把「笔」拿起来放到对应的位置移动。

将数字“6”用pandas可视化如下所示,这里去掉像素值全为0的部分列:

也就说,需要给定一个程序判断是否有一堆「0」被一堆「255」围住,如果是的话,这张数字图片就是不能「一笔完成」的。我这里用的办法是深度搜索,往上下左右4个方向深搜,判断图片中有几堆「0」。如果仅有1堆,那么这个数字图片可以「一笔完成」;反之。

代码

mnist.npz的百度云盘,密码bwn1

import numpy as np

# 读取函数,数据都被保存在mnist.npz
def load_data():
    data = np.load('./mnist.npz')
    X = data['X']
    return X

def DFS(X, row, col, visited):
    visited[row][col] = 1
    if X[row][col] == 255:
        return
    if row+1 < 28 and visited[row+1][col] == 0:
        DFS(X, row+1, col, visited)
    if col+1 < 28 and visited[row][col+1] == 0:
        DFS(X, row, col+1, visited)
    if row-1 >= 0 and visited[row-1][col] == 0:
        DFS(X, row-1, col, visited)
    if col-1 >= 0 and visited[row][col-1] == 0:
        DFS(X, row, col-1, visited)

if __name__ == '__main__':
    X = load_data()
    # X.shape = (10000, 28, 28)
    success = 0  # 可以「一笔完成」的数字图片总数
    for t in range(10000):
        blocks = 0  # 数字图片中存在几堆「0」
        visited = np.zeros((28, 28))  # 标记数组
        for i in range(28):
            for j in range(28):
                if X[t][i][j] == 0 and visited[i][j] == 0:
                    DFS(X[t], i, j, visited)
                    blocks += 1
        if blocks == 1:
            success += 1

    print(success)
posted @ 2019-06-01 23:56  小王点点  阅读(264)  评论(0编辑  收藏  举报