You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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范围再处理就行,同时还有几个小优化可以让代码更可靠:

  1. 关键修改:添加归一化步骤
    把原来的:

    image_as_float = tf.cast(image, dtype = tf.float32)
    

    改成:

    image_as_float = tf.cast(image, dtype=tf.float32) / 255.0
    
  2. 用tf.image.decode_jpeg替代decode_image
    后者会自动推断图像格式,但明确指定decode_jpeg(如果你的图像都是JPEG的话)能确保通道顺序和shape更稳定。

  3. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:52:36