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四种读图方式对比 的相关文章

  • 有没有办法使用纯Python释放纯函数的GIL?

    我想我一定错过了什么 这看起来很正确 但我看不出有什么办法可以做到这一点 假设你有一个 Python 纯函数 from math import sin cos def f t x 16 sin t 3 y 13 cos t 5 cos 2
  • Python - 定义常量列表或字典的最佳/最简洁的方法

    第一次使用堆栈溢出 我很高兴来到这里 简介 我最近开始了 Python 编程世界的神奇冒险 我喜欢它 现在 在我从 C 语言的尴尬过渡中 一切都进展顺利 但我在创建与标头文件 h 同义的内容时遇到了麻烦 问题 我有中等大小的字典和列表 大约
  • Flask/Apache 提交按钮用于文件上传

    我有一个在 apache 后面运行的 Flask 应用程序 在我的 index html 页面上有一个文件上传按钮和一个提交按钮 如下所示
  • pandas python 根据一个或多个其他列的子集更新 A 列的子集

    Edit我修改了下面的部分描述 以澄清 功能 和 组 的含义 修复拼写错误 并包含我尝试过的其他代码 我的熊猫df有 450 万行和 23 列 下表显示了几行df2这是从生成的df 它显示了两组 eeskin and hduquant 和三
  • PyQt4 信号和槽

    我正在使用 PyQt4 编写我的第一个 Python 应用程序 我有一个 MainWindow 和一个 Dialog 类 它是 MainWindow 类的一部分 self loginDialog LoginDialog 我使用插槽和信号 这
  • 类型错误:只有长度为 1 的数组可以转换为 Python 标量

    我是 openCV 的初学者 正在尝试分析数独求解器的现有代码 有这一段代码会引发错误 samples np float32 np loadtxt feature vector pixels data responses np float3
  • 不使用 graphviz/web 可视化决策树

    由于某些限制 我无法使用 graphviz webgraphviz com 可视化决策树 工作网络与另一个世界是封闭的 问题 是否有一些替代实用程序或一些 Python 代码用于至少非常简单的可视化可能只是决策树的 ASCII 可视化 py
  • 生产环境的 Flask-Login 与 Flask-Security

    我正在构建一个功能 供用户注册 登录 验证和授权自己 特别是使用 Python Flask 作为后端 我找到了一些解决方案 例如flask login and flask security 据我了解 flask login实际上并没有进行任
  • Python控制台默认十六进制显示

    我在 Python 控制台中做了很多工作 其中大部分都涉及地址 我更喜欢以十六进制形式查看地址 So if a 0xBADF00D 当我简单地输入Python gt a进入控制台查看其值 我更喜欢 python 回复0xBADF00D代替1
  • 如何对嵌套函数进行单元测试? [复制]

    这个问题在这里已经有答案了 您将如何对嵌套函数进行单元测试f1 在下面的例子中 def f def f1 return 1 return 2 或者需要测试的函数不应该嵌套吗 有一个类似的问题这个链接 https stackoverflow
  • 使用 python 写入 aws lambda 中的 /tmp 目录

    Goal 我正在尝试将 zip 文件写入 python aws lambda 中的 tmp 文件夹 因此我可以在压缩之前提取操作 并将其放入 s3 存储桶中 Problem 操作系统 Errno30 只读文件系统 这段代码在我的计算机上进行
  • 如何在 scikit-learn 的 SVM 中使用非整数字符串标签? Python

    Scikit learn 具有相当用户友好的用于机器学习的 python 模块 我正在尝试训练用于自然语言处理 NLP 的 SVM 标记器 其中我的标签和输入数据是单词和注释 例如 词性标记 而不是使用双精度 整数数据作为输入元组 1 2
  • Mac 上的 Errno 13 权限被拒绝

    我只是测试如何从一个 py 文件调用外部 py 文件 我有 2 个 py 文件 都在同一目录中 这是主要代码 runext py 假设调用 ext py import subprocess subprocess call Users tra
  • Celery 设计帮助:如何防止并发执行任务

    我对 Celery AMQP 相当陌生 正在尝试提出一个任务 队列 工作人员设计来满足以下要求 我有多种类型的 每用户 任务 例如 TaskA TaskB TaskC 这些 每用户 任务中的每一个都为系统中的一个特定用户读取 写入数据 因此
  • Python:如何使用生成器来避免 sql 内存问题

    我有以下方法来访问 mysql 数据库 并且查询在服务器中执行 我无权更改有关增加内存的任何内容 我对生成器很陌生 并开始阅读更多有关它的内容 并认为我可以将其转换为使用生成器 def getUNames self globalUserQu
  • 在 Django 中翻译文件时的 Git 命令

    我在 Django 中有一个现有的应用程序 我想在页面上添加翻译 在页面上我有 trans Projects 在 po 文件中我添加了 templates staff site html 200 msgid Projects msgid P
  • Numba jitclass 不适用于 python 列表

    我在用python 3 6 and numba 0 36 这个问题有一个sister https stackoverflow com questions 48159360 numba custom stack class and pop f
  • 使用 Tweepy 获取推文时出错

    我有一个用于获取推文的 Python 脚本 在脚本中我使用该库 Tweepy 我使用有效的身份验证参数 运行此脚本后 一些推文存储在我的 MongoDB 中 有些则被 if 语句拒绝 但我仍然收到错误 requests packages u
  • “ModuleNotFoundError:我的 Docker 容器中没有名为 的模块”

    我正在尝试在 Docker 容器中运行 python 脚本 但我不知道为什么 python 找不到任何 python 模块 我认为它与 PYTHONPATH 环境变量有关 所以我尝试将其添加到 Dockerfile 中 如下所示 ENV P
  • 透视包含字符串的 Pandas Dataframe - “没有要聚合的数字类型”错误

    关于此错误有很多问题 但环顾四周后 我仍然无法找到 解决解决方案 我正在尝试用字符串旋转数据框 以使一些行数据变成列 但到目前为止还没有成功 我的 df 的形状

随机推荐

  • 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