使用image_dataset_from_directory生成tfrecords后解码图像失真如何解决
问题原因
- 编码阶段类型转换逻辑错误:
tf.image.convert_image_dtype默认会将浮点型输入视为[0, 1]范围,乘以255后映射为uint8的[0, 255]区间。但image_dataset_from_directory默认无rescale配置,返回的float32类型图像像素本身就是[0, 255]范围,经过convert_image_dtype转换后,所有大于1的像素值都会被截断为255,直接导致图像过曝、色彩失真。 - 解码阶段重复缩放:编码阶段已经通过
image_dataset_from_directory的image_size参数将图像缩放到固定尺寸,解码后又执行了一次tf.image.resize操作,二次插值会额外引入精度损失,如果两次设置的尺寸不一致还会导致图像拉伸变形,进一步加重失真。
修复方案
- 修正编码阶段的类型转换逻辑,将
process_image函数中的tf.image.convert_image_dtype替换为直接强转,可选设置JPEG最高质量减少压缩损耗:
def process_image(image, label): # 替换convert_image_dtype为tf.cast,适配[0,255]范围的float32输入 image = tf.cast(image, dtype=tf.uint8) image = tf.io.encode_jpeg(image, quality=100) label = tf.one_hot(label, NUM_CLASSES) return image, label
- 移除解码阶段不必要的resize操作,除非业务确实需要修改图像尺寸:
def _parse_image_function(example): image_feature_description = { 'image': tf.io.FixedLenFeature([], tf.string), 'label': tf.io.FixedLenFeature([40], tf.float32), } features = tf.io.parse_single_example(example, image_feature_description) image = tf.image.decode_jpeg(features['image'], channels=3) # 移除多余的resize步骤 label = features['label'] return image, label
- 如果确实需要在解码阶段调整图像尺寸,展示时要先将resize后的float32类型数据正确转换为uint8:
plt.imshow(tf.cast(images[i], tf.uint8).numpy())
内容的提问来源于stack exchange,提问作者SinkingTitanic
相关产品推荐
相关产品推荐

