tfrecord数据集读取问题,tf.image.decode_image解码前后出现数值不一样

博客指出自制图像分割label.png文件,以二进制编码打开后标签全变为0的问题。其原因在于制作标签时,需注意图像存储模式,是RGB还是灰度模式(L)。

问题描述:
自己制作的图像分割label.png,二进制编码打开png图像源文件后,标签全部变为0
原因:
制作标签时,注意图像的存储模式,是RGB还是灰度模式(L)

from PIL import Image
import tensorflow as tf
import numpy as np
#img_path='F:\\VOC2012\\SegmentationClassAug\\2007_000032.png'
img_path='00.png'

#原label.png
img=Image.open(img_path)
img_array=np.asarray(img)
print('1')
print(np.sum(np.int32(img_array==1)))

#二进制打开png图片,再解码
with tf.gfile.GFile(img_path, 'rb') as fid:
  encoded_jpg0 = fid.read()
with tf.Session() as s:
  label0 = tf.image.decode_image(encoded_jpg0,1)
  #label0=tf.decode_raw(encoded_jpg0,out_type=tf.uint8)
  print('2')
  print(np.sum(np.int32(s.run(label0)==1)))

#原label.png
img=Image.open(img_path).convert('L')
img.save('01.png')

img_path1='01.png'
#二进制打开png图片,再解码
with tf.gfile.GFile(img_path1, 'rb') as fid:
  encoded_jpg0 = fid.read()
with tf.Session() as s:
  label0 = tf.image.decode_image(encoded_jpg0,1)
  print('3')
  print(np.sum(np.int32(s.run(label0)==1)))
1
866
2
0
3
866
<think> 我们之前使用TensorFlow调整了图像的亮度、对比度、饱和度和色调,并保存了调整后的图片。但是用户反映调整亮度后保存的图片发灰,希望优化代码使图片效果更好。 分析问题:图片发灰通常是因为对比度足。在调整亮度后,图片的像素值范围可能被压缩,导致看起来灰蒙蒙的。我们可以通过后续的对比度调整或者直方图均衡化来改善。 解决方案: 1. 在调整亮度后,增加对比度调整,使图像更生动。 2. 使用直方图均衡化来增强图像对比度(但注意,直方图均衡化可能适用于所有图像,特别是自然场景图像可能会产生自然的效果)。 3. 或者,在保存前对图像进行自动对比度调整(即线性拉伸像素值到整个范围[0,255])。 由于用户已经使用了对比度调整,但可能参数够合适,我们可以尝试以下两种方法改进: 方法一:在亮度调整后,使用一个固定的对比度因子(大于1)来增强对比度。 方法二:对图像进行自动对比度调整(将当前图像的最小值映射到0,最大值映射到255)。 考虑到用户已经使用过随机对比度调整(代码中注释了),我们可以选择在亮度调整后,进行一个自动对比度调整,这样能有效解决发灰问题。 自动对比度调整(线性拉伸)的数学原理: 设调整前的图像像素值范围为$[min\_val, max\_val]$,我们希望将其线性映射到$[0, 255]$。 变换公式为: $$adjusted\_pixel = \frac{pixel - min\_val}{max\_val - min\_val} \times 255$$ 在TensorFlow中,我们可以这样实现: 1. 计算图像的最小值和最大值(注意:图像可能是整型或浮点型,需要先转换为浮点型进行计算)。 2. 应用线性变换。 但是注意:自动对比度调整可能会过度拉伸,特别是当图像中有一个很暗和一个很亮的点时,其他像素的对比度会被拉大,但整体效果通常较好。 另外,我们也可以使用`tf.image.per_image_standardization`进行标准化(减去均值再除以标准差),但这样得到的图像可能是我们期望的对比度增强,且会改变图像的亮度。所以这里使用标准化。 我们选择:在亮度调整后,进行自动对比度调整(线性拉伸至[0,255]),然后再保存。 步骤: 1. 将图像转换为浮点型(以便计算)。 2. 计算图像中的最小值和最大值。 3. 应用线性变换。 4. 将图像转换回uint8类型。 注意:如果图像已经是浮点型(0-1范围),则需要转换,但我们的图像是从JPEG读入的,为uint8(0-255)。我们在调整亮度后,图像可能变成浮点型(因为调整亮度函数返回浮点型)?查看TensorFlow文档:`tf.image.adjust_brightness`返回类型与输入相同。但输入是uint8,调整亮度后可能超出0-255范围,而且返回类型仍然是uint8吗?实际上,`adjust_brightness`会将结果裁剪到0-255,并保持uint8类型?,实际上:如果输入是uint8,那么调整亮度(加上一个浮点数)会返回浮点数。我们需要显式转换为uint8。 因此,我们之前的代码在保存前转换为uint8是正确的。但发灰的原因可能是亮度调整后像素值被压缩在一个较小的范围内,所以我们需要先拉伸再转换。 具体修改:在亮度调整后,进行自动对比度调整(线性拉伸),然后再转换为uint8。 代码示例(以亮度调整后的图像为例): 注意:我们假设调整后的图像可能是浮点型(即使输入是uint8,调整亮度也会返回float32)。 步骤: brightened = tf.image.random_brightness(image, max_delta=0.4) # 返回float32 # 自动对比度调整(线性拉伸) # 将图像归一化到[0,1]?,我们直接拉伸到0-255 # 计算当前图像的最小值和最大值 min_val = tf.reduce_min(brightened) max_val = tf.reduce_max(brightened) # 防止除零,加上一个小的epsilon epsilon = 1e-5 stretched = (brightened - min_val) / (max_val - min_val + epsilon) * 255.0 # 然后转换为uint8 stretched = tf.cast(stretched, tf.uint8) 这样,拉伸后的图像对比度就会增强,避免发灰。 但是,这个方法有一个缺点:如果图像中有一个极端暗点和极端亮点,那么其他像素的对比度会被拉伸,可能效果并好。但在大多数情况下,它能够改善发灰的现象。 另一种方案:使用直方图均衡化。TensorFlow没有内置的直方图均衡化函数,我们可以使用OpenCV,但用户要求使用TensorFlow。因此,我们可以自己实现直方图均衡化,但这比较复杂,而且对于RGB图像,通常是在HSV空间的V通道进行,然后再转换回来。 考虑到简单性,我们先用线性拉伸。 另外,我们也可以尝试使用伽马校正来改善。伽马校正可以调整图像的亮度曲线,使得暗部细节更明显或亮部更明显。伽马值小于1会使图像变亮(压缩暗部),大于1会使图像变暗(压缩亮部)。我们可以选择一个合适的伽马值(例如1.2)来增强对比度。 但用户的问题是发灰(对比度低),所以伽马校正一定能直接解决,而线性拉伸是最直接的。 因此,我们将线性拉伸作为解决方案。 修改原有代码:在亮度调整后,加入线性拉伸步骤。 注意:线性拉伸可能会改变图像的整体亮度,但我们的目的是将整个动态范围用满,从而提高对比度。 此外,我们也可以对其他调整(如对比度、饱和度、色调)后的图像进行线性拉伸,因为调整后也可能出现发灰问题。 但是,用户特别指出是调整亮度后保存的图片发灰,因此我们主要修改亮度调整的部分。 优化后的代码示例(仅针对亮度调整后的图像进行拉伸): 我们将保存亮度调整后的图像改为保存拉伸后的图像。 修改后的代码: 步骤: 1. 读取图片 2. 调整亮度 3. 线性拉伸(自动对比度调整) 4. 保存拉伸后的图像(而是直接保存调整亮度后的图像) 其他调整(对比度、饱和度、色调)可以保持变,或者也做类似处理?根据用户反馈,目前只有亮度调整后发灰,所以我们先处理亮度调整。 注意:线性拉伸必须在转换为uint8之前进行,因为浮点型才能进行线性运算。 完整代码修改(仅针对亮度调整部分): 原来的: brightened = tf.image.random_brightness(image, max_delta=0.4) # 然后直接保存brightened(转换为uint8后) 修改为: brightened = tf.image.random_brightness(image, max_delta=0.4) # 进行线性拉伸 min_val = tf.reduce_min(brightened) max_val = tf.reduce_max(brightened) epsilon = 1e-5 stretched_brightened = (brightened - min_val) / (max_val - min_val + epsilon) * 255.0 stretched_brightened = tf.cast(stretched_brightened, tf.uint8) # 保存stretched_brightened 另外,对于其他调整(对比度、饱和度、色调)后的图像,如果也出现发灰,可以同样处理。 但是,我们注意到对比度调整本身就是为了改变对比度,所以可能需要。而饱和度和色调调整通常会导致发灰(因为它们主要改变颜色成分,而是亮度)。 因此,我们只对亮度调整后的图像进行线性拉伸。 最后,我们还需要注意:线性拉伸会将图像的动态范围拉满,可能会使得原本较暗或较亮的区域丢失细节(因为拉伸后,原本接近最小值的像素变为0,接近最大值的像素变为255),但这是提高对比度的常用方法。 如果用户希望保留更多细节,可以使用自适应直方图均衡化(如CLAHE),但这在TensorFlow中实现较为复杂,可能需要借助其他库(如OpenCV)或自定义操作。 由于用户要求使用TensorFlow,我们提供线性拉伸方案。 现在,我们修改原代码,保存亮度调整后的图像时,改为保存线性拉伸后的图像。 同时,为了展示效果,我们仍然显示原来的亮度调整图像和拉伸后的图像?或者用户只要求保存?根据用户需求,他要求保存图片。 因此,在保存步骤,我们使用拉伸后的图像。 修改后的代码(仅展示亮度调整部分,其他调整保持变): 我们将原来的brightened保存改为保存stretched_brightened。 另外,在可视化部分,为了对比,我们可以同时显示拉伸前和拉伸后的亮度调整图像?用户原代码中有5个子图(原始、亮度、对比度、饱和度、色调)。现在,我们将亮度调整后的图像替换为拉伸后的图像?或者保留两个(一个拉伸前,一个拉伸后)?但这样就需要6个子图了。 根据用户需求,他要求保存图片,所以我们需要保存拉伸后的图像。在可视化部分,我们可以选择显示拉伸后的图像作为亮度调整的结果(即替换原来的亮度调整图像),或者增加一个子图显示拉伸前的亮度调整图像(发灰的)以作对比。 这里为了改变原有子图数量(5个),我们可以将亮度调整后的图像(拉伸后)作为第二个子图。同时,为了对比,我们可以在保存文件时,同时保存发灰的版本和拉伸后的版本?但用户要求保存效果更好的图片,所以我们只保存拉伸后的版本。 因此,修改如下: 1. 在亮度调整后,进行线性拉伸得到stretched_brightened。 2. 在保存时,使用stretched_brightened。 3. 在可视化部分,第二个子图显示stretched_brightened(即效果改善后的亮度调整图像)。 这样,用户看到的亮度调整图像就是拉伸后的,会发灰。 另外,我们也可以对对比度调整后的图像进行线性拉伸?原代码中对比度调整使用随机对比度,可能也会导致发灰。但用户没有提到,我们暂且做。 完整代码修改(仅亮度调整部分)如下: 注意:由于线性拉伸需要浮点数计算,而brightened是浮点数(调整亮度后),所以直接计算。 修改后的代码: 我们将原来的: brightened = tf.image.random_brightness(image, max_delta=0.4) # 然后直接显示和保存brightened(转换为uint8后) 改为: brightened = tf.image.random_brightness(image, max_delta=0.4) # 返回float32 # 线性拉伸 min_val = tf.reduce_min(brightened) max_val = tf.reduce_max(brightened) epsilon = 1e-5 stretched_brightened = (brightened - min_val) / (max_val - min_val + epsilon) * 255.0 stretched_brightened = tf.cast(stretched_brightened, tf.uint8) 然后,在保存和显示时,对于亮度调整后的图像,我们使用stretched_brightened。 其他调整(对比度、饱和度、色调)保持变,因为它们的输出我们同样需要转换为uint8(饱和度和色调调整返回的也是浮点数,所以也需要转换,但需要线性拉伸,因为用户没有反映发灰)。 但是,为了统一,我们在保存任何调整后的图像前,都转换为uint8(使用线性拉伸?,只对亮度调整后的进行拉伸,其他的直接转换)。 具体修改: 原来的代码中,我们在显示的时候除以255(因为显示要求0-1的浮点数)。但是,我们保存的图片需要是uint8。 修改后的完整代码: 注意:我们只对亮度调整后的图像进行线性拉伸(解决发灰),其他调整后的图像仍然直接转换为uint8(拉伸)。 代码结构: 1. 读取图像(已经是uint8) 2. 亮度调整(brightened,返回float32) -> 线性拉伸 -> 转换为uint8(stretched_brightened) 3. 对比度调整(返回float32) -> 直接转换为uint8(因为用户没有要求,且对比度调整本身就会改变对比度,可能需要拉伸) 4. 饱和度调整(返回float32) -> 转换为uint8 5. 色调调整(返回float32) -> 转换为uint8 在保存时,我们保存的是这些uint8的图像。 修改后的代码(包含保存和可视化)如下: 由于用户要求保存图片,我们在每个调整后都保存一个文件。 例如: 保存亮度调整后的图像:brightened_stretched.jpg 保存对比度调整后的图像:contrast.jpg 等等。 下面给出修改后的完整代码(包括保存每个调整后的图像): </think> 针对调整亮度后保存的图片发灰问题,我们需要在保存前对图像进行对比度优化处理。以下是优化后的代码方案,包含自动对比度调整和伽马校正两种方法: ```python import tensorflow as tf import matplotlib.pyplot as plt import numpy as np # 1. 读取图像 image = tf.io.read_file('/home/jiayucui/work/Project/image_enhance/20250911-110800.jpg') image = tf.image.decode_jpeg(image, channels=3) # 2. 图像增强处理 def enhance_image(image): """优化图像对比度和色彩表现""" # 方法1: 自动对比度调整(线性拉伸) min_val = tf.reduce_min(image) max_val = tf.reduce_max(image) auto_contrast = (image - min_val) / (max_val - min_val + 1e-5) * 255.0 # 方法2: 伽马校正(改善中间色调) gamma = 0.8 # 0.8-1.2之间效果最佳 gamma_corrected = tf.image.adjust_gamma(auto_contrast, gamma=gamma) return tf.cast(gamma_corrected, tf.uint8) # 3. 应用图像处理 brightened = tf.image.random_brightness(image, max_delta=0.4) brightened = enhance_image(brightened) # 优化亮度调整后的图像 contrast = tf.image.random_contrast(image, lower=1.0, upper=1.5) contrast = enhance_image(contrast) # 优化对比度调整后的图像 saturation = tf.image.random_saturation(image, lower=0.6, upper=1.0) saturation = enhance_image(saturation) # 优化饱和度调整后的图像 hue = tf.image.random_hue(image, 0.5) hue = enhance_image(hue) # 优化色调调整后的图像 # 4. 保存优化后的图像 def save_image(tensor, filename): """保存TensorFlow张量为图像文件""" tensor = tf.cast(tensor, tf.uint8) encoded = tf.image.encode_jpeg(tensor, quality=95) tf.io.write_file(filename, encoded) save_image(brightened, '/home/jiayucui/work/Project/image_enhance/brightened_enhanced.jpg') save_image(contrast, '/home/jiayucui/work/Project/image_enhance/contrast_enhanced.jpg') save_image(saturation, '/home/jiayucui/work/Project/image_enhance/saturation_enhanced.jpg') save_image(hue, '/home/jiayucui/work/Project/image_enhance/hue_enhanced.jpg') # 5. 可视化对比 plt.figure(figsize=(15,5)) plt.subplot(151); plt.imshow(tf.cast(image, tf.uint8).numpy()); plt.title('Original') plt.subplot(152); plt.imshow(brightened.numpy()); plt.title('Brightened') plt.subplot(153); plt.imshow(contrast.numpy()); plt.title('Contrast') plt.subplot(154); plt.imshow(saturation.numpy()); plt.title('Saturation') plt.subplot(155); plt.imshow(hue.numpy()); plt.title('Hue') plt.savefig('/home/jiayucui/work/Project/image_enhance/comparison.png', dpi=300) plt.show() ``` ### 核心优化说明: 1. **自动对比度调整**: - 公式:$$I_{\text{enhanced}} = \frac{I - I_{\min}}{I_{\max} - I_{\min}} \times 255$$ - 作用:将图像像素值线性拉伸到0-255全范围,解决发灰问题[^1] - 添加微小值$10^{-5}$防止除零错误 2. **伽马校正**: - 公式:$$I_{\gamma} = 255 \times \left(\frac{I}{255}\right)^{\gamma}$$ - 原理:$\gamma < 1$时提升暗部细节,$\gamma > 1$时抑制高光过曝 - 推荐值:$\gamma = 0.8$(提升暗部细节)或$\gamma = 1.2$(抑制高光) 3. **保存优化**: - 使用高JPEG质量参数(quality=95)减少压缩伪影 - 单独保存每个处理结果便于后续分析 - 保存对比图时指定DPI=300获得高质量输出 ### 参数调整建议: 1. **亮度补偿**: ```python # 亮度调整后补偿对比度损失 compensated = tf.image.adjust_contrast(brightened, 1.2) ``` 2. **自适应伽马值**: ```python # 根据图像平均亮度自动计算伽马值 mean_brightness = tf.reduce_mean(tf.image.rgb_to_grayscale(image)) gamma = tf.clip_by_value(1.5 - mean_brightness/255.0, 0.7, 1.3) ``` 3. **HSL空间优化**: ```python # 转换到HSL空间进行专业色彩调整 hsl = tf.image.rgb_to_hsv(image) hsl = tf.stack([hsl[...,0], hsl[...,1], tf.sqrt(hsl[...,2])], axis=-1) enhanced = tf.image.hsv_to_rgb(hsl) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值