解决tensorflow图片处理遇到的读写坑

tensorflow 2处理图片十分简便,其内部的tensorflow.image工具包更是十分强大。

当然opencv也很强大,但opencv对于pngjpg解析出来的格式是不一致的,一种是归一化的值,一种是非归一化的值,后续处理仍然很麻烦.

因而用tensorflow.image.decode_png()tensorflow.image.decode_jpeg()tensorflow.image.encode_png()tensorflow.image.encode_jpeg()来操作图片就是一个明智选择。

但是不免有的图片挂羊头卖狗肉,明明后缀是jpg,但是用decode_jpeg就是不能读或写,就是给你报错。用图片查看器打开也正常,又不见什么问题,我们怎么处理呢?

结论

最好的办法是单独把图片拿出来另存一遍替换掉。

问题1复现

lfpw数据集中,有几张图片是有坑的。
诸如读图报错的lfpw_testImage_102.jpg、写图报错的lfpw_testImage_339.jpg等等,最好的办法是单独把图片拿出来另存一遍替换掉,否则使用如下代码读图会出现错误。

import tensorflow as tf
path1 = '/xxxxxx/lfpw_trainImage_339.jpg'  #原图片

img = tf.io.read_file(path1)
img_tf = tf.image.decode_jpeg(img)
print(img_tf)

报错:
InvalidArgumentError: Expected image (JPEG, PNG, or GIF), got unknown format starting with xxxxxxxxx
一般来讲,这是传入文件path并非jpg格式造成的,删除对应的文件即可,但是!!!
我是加了格式检测的!!!

suffix = new_path.split('.')[-1].lower()
if suffix not in ['jpeg','jpg']:
    print(f"仅支持jpg、jpeg后缀的图片,而你竟想生成后缀为{suffix}的图片")
    exit()

我这张图片确实是jpg格式的,而且用图片查看器也没有问题。

原因还是在与图片本身,往往图片查看器会根据图片格式来打开图片,但是如果你将jpg文件重命名成其他格式,图也是可以打开的,因为一个图片查看器有试错机制,能够打开挂羊头卖狗肉的图片。

问题2复现

lfpw_testImage_102.jpg则是另外一个问题,
你把它resize以后再次存储,会有这个问题:

import tensorflow as tf
path1 = '/xxxxxx/lfpw_trainImage_102.jpg'  #原图片
new_path = 'xxxxxxx.jpg'  #图片保存路径
# 读
img = tf.io.read_file(path1)
img_tf = tf.image.decode_jpeg(img)

#resize
tf.image.resize(img_tf, [12, 12], antialias=True)

#写入
new_img = tf.image.encode_jpeg(img_tf)
with tf.io.gfile.GFile(new_path, 'wb') as file:
    file.write(new_img.numpy())

写入时候回报错:image must have 1 or 3 channels, got [12,12,4] [Op:EncodeJpeg],
这是通道数的问题了。

综上所述

用图片查看器打开图片,重新保存图片,保存时候,格式选择原来的格式即可,注意不要更改长宽。