pil_openvcv_scikit-image_tensorflow四种读图方式对比

2023-11-20


本文于2022年5月15日进行更新,主要是对于tensorflow版本升级成tf2.8.win10系统,并使用cv2.cvtColor来处理通道问题,如评论中所说;另一部分是增加了使用tensorflow 转换png到jpg.
在深度学习解决计算机视觉问题时,python处理图像常用的库有PIL,opencv,scikit-image,主流的深度学习框架会使用这几个库来读取图像;但其中tensorflow有独自的处理图像的aip,读取图像方式不同,同一张图,得到的数据可能会不同,在做模型推理时,可能会产生完全不一样的结果,因此,本文将会对这四种图像读取的方未能及结果进行对比分析。
大多数的预训练模型都是基于一种图像库读取的图像来训练的,也就是说图像处理只用一种编解码方式,一种插值方式,比如tf 的bilinear,cv2 bicubic,pillow bicubic等,在推理时,不同的插值会使精度(top-1 on imagenet-1k)下降0.2-0.5%,强数据增强方法会使这种情况缓解。另外由于不同的库同样的其它运算也会有不同,所以也会影响结果,本文对此不做过多讨论,只会对他们读取方式做个简单比较

1、四种不同的库读取jpg图显示

用PIL,skimage,opencv,tf.image四种库来读取图片对比差异

from PIL import Image

from skimage import io

import cv2

import numpy as np

import tensorflow as tf 

import matplotlib.pyplot as plt



%matplotlib inline
def readimg(imgpath):

    print("==============================PIL=========================================")

    #PIL

    pil_img = Image.open(imgpath)

    imgtype = type(pil_img)

    shape = pil_img.size

    mode = pil_img.mode

    np_pil_img = np.array(pil_img)

    npimgshape=np_pil_img.shape

    print(f"format:{pil_img.format} type:{imgtype} shape:{shape} mode:{mode} npshape:{npimgshape} dtype:{np_pil_img.dtype}")

    # plt.imshow(np_pil_img)

    print("==============================skimage=========================================")

    #skimage

    sk_img = io.imread(imgpath)

    print(f"type:{type(sk_img)} shape:{sk_img.shape} dtype:{sk_img.dtype}")

    # plt.imshow(sk_img)

    print("==============================opencv=========================================")

    #opencv

    cv_img = cv2.imread(imgpath,-1)

    cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)

    print(f"type:{type(cv_img)} shape:{cv_img.shape} dtype:{cv_img.dtype}")

    # plt.imshow(cv_img)

    print("==============================tensorflow=========================================")

    #tensorflow

    im = tf.io.read_file(imgpath)

    # tf_img = tf.image.decode_image(im) #自动识别图片类型进行转码
    tf_img = tf.image.decode_jpeg(im) #自动识别图片类型进行转码

    tf_img = tf_img.numpy()

    print(f"type:{type(tf_img)} shape:{tf_img.shape} dtype:{tf_img.dtype}")

    # plt.imshow(tf_img)

    plt.figure(figsize=(20,5))

    for i,img in enumerate([np_pil_img,sk_img,cv_img,tf_img]):

        ax=plt.subplot(1,4,i+1)

        plt.imshow(img)

        plt.axis("off")

        ax.title.set_text(f"{i}")

    return np_pil_img,sk_img,cv_img,tf_img

    


    
imgpath='a.jpg'

np_pil_img,sk_img,cv_img,tf_img=readimg(imgpath)
==============================PIL=========================================
format:JPEG type:<class 'PIL.JpegImagePlugin.JpegImageFile'> shape:(720, 480) mode:RGB npshape:(480, 720, 3) dtype:uint8
==============================skimage=========================================
type:<class 'numpy.ndarray'> shape:(480, 720, 3) dtype:uint8
==============================opencv=========================================
type:<class 'numpy.ndarray'> shape:(480, 720, 3) dtype:uint8
==============================tensorflow=========================================
type:<class 'numpy.ndarray'> shape:(480, 720, 3) dtype:uint8    

在这里插入图片描述

2、评估所读图片的差异

显示效果是一样的,但我们还要看具体的数值是否一样

imgs = [np_pil_img,sk_img,cv_img,tf_img]

idx2name = {idx:name for idx,name in enumerate(['pil','sk','cv','tf'])}

for i in range(4):

    for j in range(i+1,4):

        try:

            np.testing.assert_almost_equal(imgs[i],imgs[j])

            print(f"{idx2name[i]}/{idx2name[j]} same")

        except:

            print(f"{idx2name[i]}/{idx2name[j]} difference")
pil/sk same
pil/cv same
pil/tf difference
sk/cv same
sk/tf difference
cv/tf difference

接着查看具体的差值

np.sum(np.abs(cv_img.astype(np.float32)-tf_img.astype(np.float32)))

1040874.0

np.sum(np.abs(tf_img.astype(np.float32)-cv_img.astype(np.float32)))

1040874.0

sum=0.0

for i in range(300):

    for j in range(480):

        for k in range(3):

            sum+=np.abs(float(cv_img[i,j,k])-float(tf_img[i,j,k]))

print(sum)

1040874.0

all_img = np.stack([np_pil_img,sk_img,cv_img,tf_img],0).astype(np.float32)#原类型是uint8,求和会溢出

# new_all_img = all_img.copy()

diff = np.abs(all_img[:,None,...]-all_img)

print(diff.shape)

print(diff.min())

print(diff.max())

(4, 4, 480, 720, 3)
0.0
5.0

idx2name = {idx:name for idx,name in enumerate(['pil','sk','cv','tf'])}

plt.figure(figsize=(20,20))

for i in range(diff.shape[0]):

    for j in range(diff.shape[1]):

        ax=plt.subplot(diff.shape[0],diff.shape[1],i*diff.shape[0]+j+1)

        plt.imshow(diff[i,j].astype(np.uint8))

        dif = np.sum(diff[i,j].astype(np.float32))

        plt.axis('off')

        ax.title.set_text(f"{idx2name[i]}/{idx2name[j]} diff:{dif}")

plt.tight_layout() 

在这里插入图片描述

3、简单说明有差异原因

从第二部分可以看出,tensorflow读图的结果与其它方式读图方式不同,这部分详细的可以查看https://towardsdatascience.com/image-read-and-resize-with-opencv-tensorflow-and-pil-3e0f29b992be,这篇内容对于读取图片和resize的说明了tensorflow的差异原因。读图时,差异原因是原文是“this difference is arising from the fact that OpenCV, by default, uses integer accurate decompression of the JPEG image. In contrast, TensorFlow uses Discrete Cosine Transform as default. This type of decoding is inaccurate and so to make it the same as OpenCV, we need to decode it by using integer accurate decompression. This can be done by setting the parameter dct_method=’INTEGER_ACCURATE’ as shown below.”

image_tf = tf.io.read_file(imgpath)

image_tf = tf.image.decode_jpeg(image_tf, channels=3, dct_method='INTEGER_ACCURATE')

image_tf = image_tf.numpy()
np.sum(np.abs(image_tf.astype(np.float32)-cv_img.astype(np.float32)))
0.0

总的来说,同样的神经网络,因为读图的不同,会导致结果完全不同,这点要注意

4、同样的流程对png图片进行处理

imgpath='b.png'
def readimg_png(imgpath):

    print("==============================PIL=========================================")

    #PIL

    pil_img = Image.open(imgpath)

    imgtype = type(pil_img)

    shape = pil_img.size

    mode = pil_img.mode

    np_pil_img = np.array(pil_img)

    npimgshape=np_pil_img.shape

    print(f"format:{pil_img.format} type:{imgtype} shape:{shape} mode:{mode} npshape:{npimgshape} dtype:{np_pil_img.dtype}")

    # plt.imshow(np_pil_img)

    print("==============================skimage=========================================")

    #skimage

    sk_img = io.imread(imgpath)

    print(f"type:{type(sk_img)} shape:{sk_img.shape} dtype:{sk_img.dtype}")

    # plt.imshow(sk_img)

    print("==============================opencv=========================================")

    #opencv

    cv_img = cv2.imread(imgpath,-1)

    cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGRA2RGBA)

    print(f"type:{type(cv_img)} shape:{cv_img.shape} dtype:{cv_img.dtype}")

    # plt.imshow(cv_img)

    print("==============================tensorflow=========================================")

    #tensorflow

    im = tf.io.read_file(imgpath)

    # tf_img = tf.image.decode_image(im) #自动识别图片类型进行转码
    tf_img = tf.image.decode_png(im) #自动识别图片类型进行转码

    tf_img = tf_img.numpy()

    print(f"type:{type(tf_img)} shape:{tf_img.shape} dtype:{tf_img.dtype}")

    # plt.imshow(tf_img)

    plt.figure(figsize=(20,5))

    for i,img in enumerate([np_pil_img,sk_img,cv_img,tf_img]):

        ax=plt.subplot(1,4,i+1)

        plt.imshow(img)

        plt.axis("off")

        ax.title.set_text(f"{i}")

    return np_pil_img,sk_img,cv_img,tf_img
np_pil_img,sk_img,cv_img,tf_img=readimg(imgpath)
==============================PIL=========================================
format:PNG type:<class 'PIL.PngImagePlugin.PngImageFile'> shape:(624, 480) mode:RGBA npshape:(480, 624, 4) dtype:uint8
==============================skimage=========================================
type:<class 'numpy.ndarray'> shape:(480, 624, 4) dtype:uint8
==============================opencv=========================================
type:<class 'numpy.ndarray'> shape:(480, 624, 4) dtype:uint8
==============================tensorflow=========================================
type:<class 'numpy.ndarray'> shape:(480, 624, 4) dtype:uint8

在这里插入图片描述

imgs = [np_pil_img,sk_img,cv_img,tf_img]

idx2name = {idx:name for idx,name in enumerate(['pil','sk','cv','tf'])}

for i in range(4):

    for j in range(i+1,4):

        try:

            np.testing.assert_almost_equal(imgs[i],imgs[j])

            print(f"{idx2name[i]}/{idx2name[j]} same")

        except:

            print(f"{idx2name[i]}/{idx2name[j]} difference")

pil/sk same
pil/cv same
pil/tf same
sk/cv same
sk/tf same
cv/tf same

all_img = np.stack([np_pil_img,sk_img,cv_img,tf_img],0).astype(np.float32)#原类型是uint8,求和会溢出

# new_all_img = all_img.copy()

diff = np.abs(all_img[:,None,...]-all_img)

print(diff.shape)

print(diff.min())

print(diff.max())

(4, 4, 480, 624, 4)
0.0
0.0

idx2name = {idx:name for idx,name in enumerate(['pil','sk','cv','tf'])}

plt.figure(figsize=(20,20))

for i in range(diff.shape[0]):

    for j in range(diff.shape[1]):

        ax=plt.subplot(diff.shape[0],diff.shape[1],i*diff.shape[0]+j+1)

        plt.imshow(diff[i,j].astype(np.uint8))

        dif = np.sum(diff[i,j].astype(np.float32))

        plt.axis('off')

        ax.title.set_text(f"{idx2name[i]}/{idx2name[j]} diff:{dif}")

plt.tight_layout() 

在这里插入图片描述

可以看到,对于png结果全部相同的.

5、png图片转jpg

5.1 使用PIL进行转换

from PIL import Image

im = Image.open('b.png')

if not im.mode == 'RGB':

    im = im.convert('RGB')

im.save('b_pil.jpg',quality=95)

5.2 使用Opencv进行转换

import cv2



# Loading .png image

png_img = cv2.imread('b.png')
png_img = cv2.cvtColor(png_img,cv2.COLOR_BGRA2RGBA)


# converting to jpg file

#saving the jpg file

cv2.imwrite('b_cv.jpg', png_img, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
True

5.3 使用Tensorflow 进行转换

import tensorflow as tf 
tf_img = tf.io.read_file('b.png')
tf_img = tf.image.decode_png(tf_img,channels=3)
t = tf.image.encode_jpeg(tf_img,quality=95)
tf.io.write_file('b_tf1.jpg',t)
cv2.imwrite('b_tf.jpg',tf_img.numpy()[:,:,::-1])

5.4 使用scikit-image进行转换

事实上,scikit-image使用的是其它库进行图像处理

import skimage.io as io
io.find_available_plugins()

{‘fits’: [‘imread’, ‘imread_collection’],
‘gdal’: [‘imread’, ‘imread_collection’],
‘gtk’: [‘imshow’],
‘imageio’: [‘imread’, ‘imsave’, ‘imread_collection’],
‘imread’: [‘imread’, ‘imsave’, ‘imread_collection’],
‘matplotlib’: [‘imshow’, ‘imread’, ‘imshow_collection’, ‘imread_collection’],
‘pil’: [‘imread’, ‘imsave’, ‘imread_collection’],
‘qt’: [‘imshow’, ‘imsave’, ‘imread’, ‘imread_collection’],
‘simpleitk’: [‘imread’, ‘imsave’, ‘imread_collection’],
‘tifffile’: [‘imread’, ‘imsave’, ‘imread_collection’]}

import skimage.io as io
io.use_plugin('pil')

这样就相当于使用pil了

5.3对比以上三种方法转换的图片是否相同

两种转换方法在quality都是95的情况下做对比,有关quality的取值,可以参看https://jdhao.github.io/2019/07/20/pil_jpeg_image_quality/

from PIL import Image
import numpy as np
pil_img = np.array(Image.open('b_pil.jpg'))
cv_img = np.array(Image.open('b_cv.jpg'))
tf_img = np.array(Image.open('b_tf.jpg'))
tf_img1 = np.array(Image.open('b_tf1.jpg'))

print(pil_img.shape)
print(cv_img.shape)
print(tf_img.shape)

np.testing.assert_equal(pil_img,cv_img)
np.testing.assert_equal(pil_img,tf_img)
np.testing.assert_equal(pil_img,tf_img1)

(480, 624, 3)
(480, 624, 3)
(480, 624, 3)

结果是完全相同的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pil_openvcv_scikit-image_tensorflow四种读图方式对比 的相关文章

随机推荐

  • 2021赣网杯网络安全大赛_部分Writeup

    目录 Web 1 checkin 2 gwb web easypop 3 gwb web2 挖洞大师 misc 1 decodemaster 2 gwb misc lovemath 3 gwb misc3 testcat Web 1 che
  • C++11智能指针之std::shared_ptr

    std shared ptr是在c 11中引入的一种智能指针 其特点是它所指向的资源具有共享性 即多个shared ptr可以指向同一份资源 在c 中使用shared ptr需要包含
  • Unity中UI框架的使用1-添加面板、显示Loading页面

    其中BasePanel和Canvas都是挂在面板的预制物上的 1 导入我们的UI框架 本篇文章中有用的是两个UIPanelType NUIManager和NBasePanel 会放在文章最后供大家使用 2 先将我们做好的Panel设置成预制
  • 有些变压器的中性点为何要装避雷器?

    有些变压器的中性点为何要装避雷器 答 当变压器的中性点接地运行时 是不需要装避雷器的 但是 由于运行方式的需要 为了防止单相接地事故时短路电流过大 220kV及以下系统中有部分变压器的中性点是断开运行的 在这种情况下 对于中性点绝缘不是按照
  • 6.js--布尔值和null

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 目录 1 布尔数据 boolean 2 null 3 null和undefined的意义 1 布尔数据 boolean var a true var b false
  • CSDN创作说明

    这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题 有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一个表格 设定内容居中 居左 居右 Sma
  • 计算机丢失MSVCR120.dll是什么意思,电脑找不到MSVCR120.dll如何修复?

    我们在玩游戏或者运行一些软件的时候 系统提示无法启动此程序 因为计算机中丢失MSVCR120 dll 尝试重新安装该程序以解决此问题 这个需要怎么修复呢 详细困扰着不少小伙伴 小编今天就把教程分享给大家 方法如下 首先是打开电脑浏览器后在顶
  • Java判断时间是否超过30天,java 字符串时间 判断是否在30天内

    时间是字符串类型时 比较大小的时候 先要 转化成 时间格式 然后在进行比较 字符串比较大小的规则 首先取出两个字符串的长度 比较较小的长度内 两者是否相等 若不相等 则直接返回该位置字符的ASCII码相减后的值 若各位置都相等 则将两个字符
  • 问题 A: 天天向上

    题目描述 假设某同学初始能力值为1 现在该同学学习10天 休息1天 学习一天 能力提升0 001 休息一天 能力下降0 001 问一年 365天 后该同学的能力是多少 输出 365天后该同学的能力是 保留小数点6位 分析 书上76页有类似的
  • STM32 串行FLASH文件系统FatFs

    目录 一 Windows系统为例 二 文件系统的结构与特性 为什么要应用文件分配表 三 FatFs文件系统 1 FatFs 文件系统源码介绍 2 FatFs在程序中的关系网 四 配置FatFs移植程序 1 配置diskio c文件 2 配置
  • MobaXterm x11-forwarding

    Linux系统也是有图像界面的 它的方式和Windows不一样 叫做 X Window 采用的是X11协议 X11 中的 X 指的就是 X 协议 11 指的是采用 X 协议的第 11 个版本 客户端是X server 用MobaXterm登
  • CocosCretor解决premultipliedAlpha黑边问题

    在官方文档中的说明 premultipliedAlpha 对于是否启动贴图预乘 当图片的透明区域出现色块时 需要关闭该选项 当图片的半透明区域颜色变黑时 需要启用该选项 之前在项目中导出的spine有黑边问题 也就是半透明区域颜色变黑 然后
  • 《软件测试的艺术》第五章 模块(单元)测试

    软件测试的艺术 第五章 模块 单元 测试 5 0 前言 5 1 测试用例设计 5 2 增量测试 5 3 自顶向下测试和自底向上测试 5 3 1 自顶向下的测试 5 3 2 自底向上的测试 5 3 3 比较 5 4 执行测试 5 5 小结 参
  • vite-svg-loader,在项目里轻松使用svg,ts项目需特别注意!

    前言 vite svg loader插件可以让我们像使用vue组件那样使用svg图 使用起来超级方便 安装 npm install vite svg loader save dev 使用 1 vite config ts配置 import
  • 解决Flutter键盘弹起导致与输入框有间距问题(Flutter键盘弹起Scaffold布局流程)解析

    一 在项目中遇到了个如下问题 当页面底部有个输入框 点击弹出键盘时 输入框与键盘之间有一段间距 通过排除 最后找到了问题根源所在 原因是使用了这个屏幕适配框架导致的 此框架通过直接修改FlutterViewConfiguration 的si
  • Spring boot中,feign远程调用api,用@SpringQueryMap接收GET请求参数,自定义QueryMapEncoder处理特殊类型的参数转换

    feign远程调用时 get请求时 如果有特殊的字段类型 用 SpringQueryMap接收参数时 会出现异常 需要自定义QueryMapEncoder 本文例举OffsetDateTime字段类型处理 1 OffsetDateTimeQ
  • 性能测试 —— Tomcat监控与调优:status页监控

    Tomcat服务器是一个免费的开放源代码的Web 应用服务器 Tomcat是Apache 软件基金会 Apache Software Foundation Jakarta 项目中的一个核心项目 由Apache Sun 和其他一些公司及个人共
  • 圆石说│彭一鸣:运用区块链技术赋能实体旅游产业;微软开放6万项专利包括一个开源区块链项目……

    智联招聘 区块链岗位需求主要集中在一线和新一线城市 智联招聘报告显示 从目前区块链职位的城市分布来看 该领域的岗位需求主要集中在一线和新一线城市中 其中 北京 上海和深圳位于第一梯队 职位占比分别达到24 20 和10 杭州 广州和成都紧随
  • spacemacs复制minibuffer的内容到buffer里

    spacemacs复制minibuffer的内容到buffer里 获取当前buffer的绝对路径 spacemacs复制minibuffer的内容到buffer里 不常用 但可以开阔一下视野 即 发现helm里 还有可进一步操作的命令 举例
  • pil_openvcv_scikit-image_tensorflow四种读图方式对比

    文章目录 1 四种不同的库读取jpg图显示 2 评估所读图片的差异 3 简单说明有差异原因 4 同样的流程对png图片进行处理 5 png图片转jpg 5 1 使用PIL进行转换 5 2 使用Opencv进行转换 5 3 使用Tensorf