使用TensorFlow和PIL保存图像时颜色反转问题求助
解决TensorFlow绘制边界框后图像颜色反转的问题
嘿,我一眼就看出问题出在哪了——你在将uint8格式的图像转成float32时,直接用了tf.cast却没有做归一化,导致后续的类型转换步骤错误地缩放了像素值,最终呈现出负片效果。
问题根源
tf.cast(image, tf.float32)会把原图像0-255的uint8数值直接转换成0-255的float32,但tf.image.convert_image_dtype在把float32转回uint8时,默认假设输入的float值范围是0-1,所以会自动执行value * 255的缩放操作。这就导致原本的255变成255×255=65025,超出uint8的取值范围后会被截断或溢出,最终看起来就像颜色完全反转了。
修复方案
只需要把图像归一化到0-1的float32范围再处理就行,同时还有几个小优化可以让代码更可靠:
关键修改:添加归一化步骤
把原来的:image_as_float = tf.cast(image, dtype = tf.float32)改成:
image_as_float = tf.cast(image, dtype=tf.float32) / 255.0用
tf.image.decode_jpeg替代decode_image
后者会自动推断图像格式,但明确指定decode_jpeg(如果你的图像都是JPEG的话)能确保通道顺序和shape更稳定。用
tf.squeeze替代硬编码reshape
手动指定[940, 650, 3]不够灵活,用squeeze可以自动去掉batch维度,适配任意尺寸的图像。
修改后的完整代码
import tensorflow as tf import numpy as np from PIL import Image def read_processed_data(filename, num_show): """ Reads in the processed data file and displays the given number of images, along with the bounding boxes. """ with open(filename, 'r') as f: i = 0 while i < num_show: for line in f: filename = line.rstrip() next_line = f.readline() num_faces = int(next_line.rstrip()) # 注意:原代码只读取了第一个边界框,若有多框需添加循环读取 bb_line = f.readline().rstrip() y1, x1, y2, x2 = bb_line.split(',') box = [float(y1), float(x1), float(y2), float(x2)] return box, filename with tf.Session() as sess: bb, fn = read_processed_data("processed.txt", 1) # 明确解码JPEG图像,指定3通道RGB image = tf.image.decode_jpeg(tf.read_file(fn), channels=3) # 归一化到0-1的float32范围 image_as_float = tf.cast(image, dtype=tf.float32) / 255.0 image_4d = tf.expand_dims(image_as_float, 0) bb_2d = tf.expand_dims(bb, 0) bb_3d = tf.expand_dims(bb_2d, 0) bb_image = tf.image.draw_bounding_boxes(image_4d, bb_3d) # 转换回uint8,开启saturate确保值在合法范围内 bb_image_uint = tf.image.convert_image_dtype(bb_image, dtype=tf.uint8, saturate=True) # 自动去掉batch维度,无需硬编码图像尺寸 bb_image_uint_3d = tf.squeeze(bb_image_uint, axis=0) data = bb_image_uint_3d.eval() base_fn = fn.split('.')[0] Image.fromarray(data).save(base_fn + "_bb.jpg")
额外提示
- 我注意到你的
read_processed_data函数只读取了第一个边界框,如果你的标注文件里有多个人脸框,记得添加循环来读取所有框,不然会丢失后续的标注信息哦。 - 加上
saturate=True可以确保转换过程中超出范围的像素值被截断到0-255之间,避免溢出导致的奇怪颜色问题。
内容的提问来源于stack exchange,提问作者Makcheese
相关产品推荐
相关产品推荐

