如何将 Tensorflow 数据集与 OpenCV 预处理一起使用?
How to use Tensorflow Dataset with OpenCV preprocessing?
我正在创建文本识别管道,我想使用 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)
形状未知,似乎预处理函数没有被解析。我该怎么办?
为了 运行 数据集 API 管道中的这个预处理函数,您需要用 tf.py_function
包装它,它是已弃用的 py_func
的继承者。主要区别在于它可以放在 GPU 上,并且可以与 eager tensors 一起工作。您可以在文档中阅读更多内容。
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()))
您的代码中有不少错误(或根据您提供的代码示例缺失)。首先,您需要迭代数据以实际调用解析函数。在急切模式下,您可以执行以下操作:
for x in dataset:
print(x)
其次,您不能直接在您的路径上调用您的 opencv imread
,因为它在那个阶段是 tf.Tensor
。查看 map 文档,它需要一个数据集作为输入,returns 另一个数据集。所以至少你需要像 str(path.numpy())
这样的东西来将它转换回你可以提供给 imread
的字符串。更好的建议是使用 tensorflow 内置函数读取文件,解码图像,然后将其转换为 numpy。查看 tf.io.decode_jpeg
注意:我已经使用 tensorflow 2-0-alpha
给你举了例子,所以根据你的 tf 版本,API 会略有变化,但想法是一样的
我正在创建文本识别管道,我想使用 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)
形状未知,似乎预处理函数没有被解析。我该怎么办?
为了 运行 数据集 API 管道中的这个预处理函数,您需要用 tf.py_function
包装它,它是已弃用的 py_func
的继承者。主要区别在于它可以放在 GPU 上,并且可以与 eager tensors 一起工作。您可以在文档中阅读更多内容。
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()))
您的代码中有不少错误(或根据您提供的代码示例缺失)。首先,您需要迭代数据以实际调用解析函数。在急切模式下,您可以执行以下操作:
for x in dataset:
print(x)
其次,您不能直接在您的路径上调用您的 opencv imread
,因为它在那个阶段是 tf.Tensor
。查看 map 文档,它需要一个数据集作为输入,returns 另一个数据集。所以至少你需要像 str(path.numpy())
这样的东西来将它转换回你可以提供给 imread
的字符串。更好的建议是使用 tensorflow 内置函数读取文件,解码图像,然后将其转换为 numpy。查看 tf.io.decode_jpeg
注意:我已经使用 tensorflow 2-0-alpha
给你举了例子,所以根据你的 tf 版本,API 会略有变化,但想法是一样的