【问题标题】:How to use Tensorflow Dataset with OpenCV preprocessing?如何在 OpenCV 预处理中使用 Tensorflow 数据集?
【发布时间】:2019-08-31 13:54:04
【问题描述】:

我正在创建一个用于文本识别的管道,我想使用 Tensorflow Dtatasets 通过 OpenCV 的一些预处理来加载数据

我正在学习本教程 https://www.tensorflow.org/guide/datasets#applying_arbitrary_python_logic_with_tfpy_func 我有这个预处理功能:

def preprocess(path, imgSize=(1024, 64), dataAugmentation=False):

    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)

    kernel = np.ones((3, 3), np.uint8)
    th, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV + 
    cv2.THRESH_OTSU)
    img = cv2.dilate(img, kernel, iterations=1)

    # create target image and copy sample image into it
    (wt, ht) = imgSize
    (h, w) = img.shape
    fx = w / wt
    fy = h / ht
    f = max(fx, fy)
    newSize = (max(min(wt, int(w / f)), 1),
               max(min(ht, int(h / f)), 1))  # scale according to f (result at 
    least 1 and at most wt or ht)
    img = cv2.resize(img, newSize)

    # add random padding to fit the target size if data augmentation is true
    # otherwise add padding to the right
    if newSize[1] == ht:
        if dataAugmentation:
            padding_width_left = np.random.random_integers(0, wt-newSize[0])
            img = cv2.copyMakeBorder(img, 0, 0, padding_width_left, wt-newSize[0]-padding_width_left, cv2.BORDER_CONSTANT, None, (0, 0))
        else:
            img = cv2.copyMakeBorder(img, 0, 0, 0, wt - newSize[0], cv2.BORDER_CONSTANT, None, (0, 0))
    else:
        img = cv2.copyMakeBorder(img, int(np.floor((ht - newSize[1])/2)), int(np.ceil((ht - newSize[1])/2)), 0, 0, cv2.BORDER_CONSTANT, None, (0, 0))

    # transpose for TF
    img = cv2.transpose(img)

    return img

但是如果我用这个

list_images = os.listdir(images_path)
image_paths = []
for i in range(len(list_images)):
    image_paths.append("iam-database/images/" + list_images[i])

dataset = tf.data.Dataset.from_tensor_slices(image_paths)
dataset = dataset.map(lambda filename: tuple(tf.py_function(preprocess, [filename], [tf.uint8])))
print(dataset)

我的形状未知,似乎没有解析预处理函数。我该怎么办?

【问题讨论】:

  • 你在哪里迭代你的数据?
  • 你得到什么错误?这行dataset = dataset.map(lambda filename: tuple(tf.py_func(preprocess, [filename], [tf.uint8]))) 没有显示任何错误。我执行了您的代码,但没有看到错误。你的意思是<MapDataset shapes: (<unknown>,), types: (tf.uint8,)> 吗?
  • @borarak 在底部脚本中。我不需要一个包含 tf.data.Dataset.from_tensor_slices() 中路径的数组吗?
  • @MohanRadhakrishnan 我没有收到任何错误。但是,如果我打印数据集,我会得到未知的形状,并且不会解析预处理函数

标签: python opencv tensorflow tensorflow-datasets


【解决方案1】:

您的代码中有很多错误(或根据您提供的代码示例缺失)。首先,您需要迭代数据以实际调用 parse 函数。在渴望模式下,您可以执行以下操作:

for x in dataset:
    print(x)

其次,您不能直接在您的路径上调用您的 opencv imread,因为在那个阶段它是 tf.Tensor。查看map 文档,它将一个数据集作为输入并返回另一个数据集。所以至少你需要像str(path.numpy()) 这样的东西来将它转换回你可以提供给imread 的字符串。更好的建议是使用 tensorflow 内置函数来读取文件,解码图像,然后将其转换为 numpy。查看tf.io.decode_jpeg

注意:我使用tensorflow 2-0-alpha 为您提供示例,因此根据您的 tf 版本,API 会略有变化,但想法是相同的

【讨论】:

  • tf.io.decode_jpeg返回张量,不能直接和opencv一起使用
  • 是的,我想我已经说清楚了“更好的建议是使用 tensorflow 内置函数来读取文件,解码图像,然后将其转换为 numpy。查看 tf.io.decode_jpeg” ,所以他仍然必须将其转换为 numpy,然后再将其提供给 opencv
  • 问题是转换你必须评估张量。但是你是对的,坚持原生 TF 预处理总是更好,除非使用其他库是绝对必要的
【解决方案2】:

为了在数据集 API 管道中运行这个预处理函数,您需要用 tf.py_function 包装它,它是已弃用的 py_func 的继承者。主要区别在于它可以在 GPU 上运行,并且可以与热切张量一起使用。您可以在文档中阅读更多内容。

def preprocess(path, imgSize = (1024, 64), dataAugmentation = False):
    path = path.numpy().decode("utf-8") # .numpy() retrieves data from eager tensor
    img = cv2.imread(path)
    ...
    return img

此时 img 是一个 .其余功能由您决定

此解析函数是数据集管道的包装器。它接收文件名作为张量,里面有字节串。

def parse_func(filename):
    out = tf.py_function(preprocess, [filename], tf.uint8)
    return out


dataset = tf.data.Dataset.from_tensor_slices(path)
dataset = dataset.map(pf).batch(1)
iterator = dataset.make_one_shot_iterator()
sess = tf.Session()
print(sess.run(iterator.get_next()))

【讨论】:

  • 如果我不运行tf.enable_eager_execution(),那么我不能运行.numpy(),这意味着我不能使用OpenCV 进行预处理,对吧?
  • 你仍然可以使用opencv,但是如果你使用的是TF1.x你需要py_func
猜你喜欢
  • 1970-01-01
  • 2023-03-15
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 2019-12-07
  • 1970-01-01
相关资源
最近更新 更多