vl_imreadjpeg和cv2的resize结果不同

2022-07-26,

matlab 用 vl_imreadjpeg 读图并 resize 到 [224, 224],与 python 用 cv2 做同样操作,得到的结果不同

  • 在用 vl_imreadjpeg 读图的 matlab 程序想做 zero mean 操作,能直接白嫖之前 python 用 cv2 处理的 image mean pixel,而要重新处理一个 mean pixel。

Environment

  • matlab R2018a
  • matconvnet-1.0-beta25
  • opencv-python-headless 4.4.0.42

Data

用 nuswide 测试,见 [1],用以下程序将 image 放到同一个目录,方便读取:

  • 效果:在 images/ 下,image 软链接名形如 n.jpg,n 是 sample id。
import os


P = "/home/dataset/nuswide"
print("current dir:", os.getcwd())

print("--- image ---")
IMAGE_LIST = os.path.join(P, "ImageList/Imagelist.txt")
IMAGE_SRC = os.path.join(P, "Flickr")
IMAGE_DEST = os.path.join(os.getcwd(), "images")
if not os.path.exists(IMAGE_DEST):
    os.makedirs(IMAGE_DEST)

with open(IMAGE_LIST, "r") as f:
    for sid, line in enumerate(f):
        line = line.replace('\\/'.replace(os.sep, ''), os.sep).strip()
        img_p = os.path.join(IMAGE_SRC, line)
        new_img_p = os.path.join(IMAGE_DEST, "{}.jpg".format(sid))
        os.system("ln -s {} {}".format(img_p, new_img_p))
        if sid % 1000 == 0:
            print(sid)

Comparison

对比思路:先 matlab 用 vl_imreadjpeg 读一张图,存成 .mat 文件,然后 python 用 cv2 读同一张图比较。这里以 1.jpg 为例,可以换成其它 image。

without resize

用 resize 操作时,两者读出的结果相同

  • matlab + vl_imreadjpeg
cd matconvnet;
setup;
cd /home/tom/codes/test.matlab;


%1.jpg 为例,可以换成 2.jpg、3.jpg……
a = {char(fullfile("images", "1.jpg"))};
img = vl_imreadjpeg(a);  % 读图,不用 resize
img = uint8(img{1, 1});
disp(size(img));  % (181, 240, 3)
save("image_vl.1.mat", "img");
  • python + cv2
import os
import numpy as np
import scipy.io as sio
import cv2
from PIL import Image


P = "images"


def load_image(idx):
    img_p = os.path.join(P, "{}.jpg".format(idx))
    img = cv2.imread(img_p)#[:, :, ::-1]
    if img is None:  # cv2 读不了,就改用 PIL.Image 读
        img_f = Image.open(img_p)
        img = np.asarray(img_f)
        img_f.close()
        if 2 == img.ndim:  # 缺 channel
            img = np.repeat(img[:, :, np.newaxis], 3, axis=2)
    else:
        img = img[:, :, ::-1]
    # 不用 resize
    # img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_LINEAR)
    return img


img_vl = sio.loadmat("image_vl.mat")["img"].astype(np.int64)  # 读刚才 matlab 存的图
img_py = load_image(1).astype(np.int64)  # 同样是 1.jpg
print(img_vl.shape, img_py.shape)  # (181, 240, 3) (181, 240, 3),相同
print(img_vl.sum(), img_py.sum())  # 19504976 19504976,相同
print("diff:", np.abs(img_vl - img_py).sum())  # diff: 0

with resize

还是刚才的代码,只不过两者都加上 resize 操作:统一 resize 成 224 x 224,结果就同了。

  • matlab + vl_imreadjpeg
cd matconvnet;
setup;
cd /home/tom/codes/test.matlab;


% 还是 1.jpg 为例
a = {char(fullfile("images", "1.jpg"))};
img = vl_imreadjpeg(a, 'Resize', [224, 224]);  % 这次加上 resize
img = uint8(img{1, 1});
disp(size(img));  % (224224, 3)
save("image_vl.1.mat", "img");
  • python + cv2
import os
import numpy as np
import scipy.io as sio
import cv2
from PIL import Image
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt


P = "images"


def load_image(idx):
    img_p = os.path.join(P, "{}.jpg".format(idx))
    img = cv2.imread(img_p)#[:, :, ::-1]
    if img is None:  # cv2 读不了,就改用 PIL.Image 读
        img_f = Image.open(img_p)
        img = np.asarray(img_f)
        img_f.close()
        if 2 == img.ndim:  # 缺 channel
            img = np.repeat(img[:, :, np.newaxis], 3, axis=2)
    else:
        img = img[:, :, ::-1]
    # 用上 resize
    img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_LINEAR)
    return img


img_vl = sio.loadmat("image_vl.mat")["img"].astype(np.int64)  # 读刚才 matlab 存的图
img_py = load_image(1).astype(np.int64)  # 同样是 1.jpg
print(img_vl.shape, img_py.shape)  # (224, 224, 3) (224, 224, 3),相同
print(img_vl.sum(), img_py.sum())  # 22847441 22509472,不同!!!
print("diff:", np.abs(img_vl - img_py).sum())  # diff: 10933205,不同!!!

# 画出来看区别
fig, ax = plt.subplots(1, 2)
ax[0].imshow(img_vl);
ax[0].set_title("vl_imreadjpeg")

ax[1].imshow(img_py)
ax[1].set_title("cv2")
fig.savefig("compare_load.png")
plt.close(fig)
  • 画图结果

…vl_imreadjpeg 这个难道不是叫「crop」?

Conclusion

所以 vl_imreadjpeg 和 cv2 两种读图方式,在 resize 时结果相同,但用 resize 之后两者结果同!

而令人迷惑的是:vl_imreadjpeg 的官网介绍[3]说它 resize 用的是「bilinear interpolation」;而我在 python 调 cv2 时用的 cv2.INTER_LINEAR 也是「bilinear interpolation」[4]

References

  1. NUS-WIDE数据集预处理
  2. docker命令行安装matlab R2018a、matconvnet、gpu环境
  3. vl_imreadjpeg
  4. cv2.INTER_LINEAR
  5. opencv: 图像缩放(cv2.resize)

本文地址:https://blog.csdn.net/HackerTom/article/details/110926141

《vl_imreadjpeg和cv2的resize结果不同.doc》

下载本文的Word格式文档,以方便收藏与打印。