Updates 2020.12.8
各位,别用「将 image 转成 .mat,然后 load mat」这种愚蠢的读图法,应该用 vl_imreadjpeg,速度差太多啦!不过要注意:需要重新处理一个 image mean pixel,见 [17]。
comparison
- 注意要将 string 用
char()
转成 char array(这两者居然不是同一种东西) - 好像是
image_batch(i, :, :, :) = img;
这句耗时?如果vl_imreadjpeg
不加Pack
参数,而是用这句手动拼的话,也会很慢。
cd matconvnet;
setup;
cd /home/tom/codes/test.matlab;
fprintf("--- load mat ---\n");
image_batch = [];
tic;
for i = 1 : 1000
img = load(fullfile("images.mat", strcat(num2str(i), ".mat")), "image");
img = img.image;
% fprintf("img:"), disp(size(img));
image_batch(i, :, :, :) = img; % 好像是这句很耗时?
% break;
end
toc; % Elapsed time is 158.847031 seconds.
fprintf("images:"), disp(size(image_batch)); % images: 1000 224 224 3
fprintf("--- vl_imreadjpeg ---\n");
tic;
a = {};
for i = 1 : 1000
a(i) = {char(fullfile("images", sprintf("%d.jpg", i)))};
end
img = vl_imreadjpeg(a, 'NumThreads', 4, 'Resize', [224, 224], 'Pack');
image_batch = img{1, 1};
fprintf("image:"), disp(size(image_batch)); % image: 224 224 3 1000
toc; % Elapsed time is 0.947701 seconds.
158.847031
s 和0.947701
的区别!
Notes
[1] 直接加载整个数据集,由于条件限制,需要将 image 改为分批读入。
Preprocess
之前做的数据见 [2, 3],当时存成 .npy,要处理成 .mat 给 matlab 读。
image 读出来转成 (224, 224, 3) 放在 image.mat/ 目录下,一幅图一个 .mat 文件,key 统一为image
。- 不处理 image,直接用
vl_imreadjpeg
读原图,见上面 Updates 2020.12.8。 - label、text 亦存成 .mat,不过可以装在一个文件内,key 分别为
labels
和texts
。 - index 一个 set 一个 .mat,key 统一为
index
。有 idx_test.npy、idx_labeled.npy、idx_unlabeled.npy、idx_ret.npy。 - 注意:python 索引是 0-base,而 matlab 是 1-base。此处 idx_*.npy 都是 0-base 的,所以 matlab 读入之后要
+1
转成 1-base 才能作为下标做 indexing。但是!前述 image.mat/ 的文件又是 0-base 的,所以后文load_images
要用 0-base 索引。
import os
import numpy as np
import scipy.io as sio
import cv2
from PIL import Image
P = "/home/dataset/nuswide"
SPLIT_P = os.path.join(P, "nuswide-tc21.100pc.500pc")
DEST_P = os.path.join(P, "matlab-data")
if not os.path.exists(DEST_P):
os.makedirs(DEST_P)
IMAGE_LIST = os.path.join(P, "ImageList/Imagelist.txt")
IMAGE_SRC = os.path.join(P, "Flickr")
IMAGE_DEST = os.path.join(DEST_P, "images.mat")
if not os.path.exists(IMAGE_DEST):
os.makedirs(IMAGE_DEST)
"""label, text"""
# clean_id = np.load(os.path.join(P, "clean_id.tc21.AllTags1k.npy"))
labels = np.load(os.path.join(P, "labels.tc-21.npy")).astype(np.uint8)
texts = np.load(os.path.join(P, "texts.AllTags1k.npy")).astype(np.uint8)
sio.savemat(os.path.join(DEST_P, "labels.tc-21.mat"), {"labels": labels}, do_compression=True)
sio.savemat(os.path.join(DEST_P, "texts.AllTags1k.mat"), {"texts": texts}, do_compression=True)
"""image
with open(IMAGE_LIST, "r") as f:
for sid, line in enumerate(f):
# if sid not in clean_id_list:
# continue
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))
img = cv2.imread(img_p)
if img is None:
img = np.asarray(Image.open(img_p))
if 2 == img.ndim:
img = np.repeat(img[:, :, np.newaxis], 3, axis=2)
else:
img = img[:, :, ::-1]
img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_LINEAR)
# image_list.append(img)
# 注意此处标号是 0-base 的
sio.savemat(os.path.join(IMAGE_DEST, "{}.mat".format(sid)), {"image": img})
if sid % 1000 == 0:
print(sid)
"""
"""index"""
idx_list = os.listdir(SPLIT_P)
# print(idx_list)
for f in idx_list:
idx = np.load(os.path.join(SPLIT_P, f))
new_f = f.replace(".npy", ".mat")
sio.savemat(os.path.join(P, new_f), {"index": idx})
Matlab Example
- 没有 matlab 高亮,借 lua 的。vs code 也要装 matlab 插件才有高亮。
- 行首
%
是行注释。 - 「字符数组」与「字符串」居然不是同一个东西,见 [11]。
- 函数一定要定义在文件尾。
P = "/home/tom/dataset/nuswide/matlab-data";
SPLIT_P = fullfile(P, "nuswide-tc21.100pc.500pc");
IMAGE_P = fullfile(P, "images.mat");
TEXT_P = fullfile(P, "texts.AllTags1k.mat");
LABEL_P = fullfile(P, "labels.tc-21.mat");
% 读数据划分
index_key = ["train", "test", "ret"];
index_set = containers.Map('KeyType', 'char', 'ValueType', 'any');
for k = index_key
% fprintf("key: %s\n", k);
if strcmp(k, "train") == 1
fn = "idx_labeled.mat";
else
fn = strcat("idx_", k, ".mat");
end
idx_f = fullfile(SPLIT_P, fn);
% fprintf("idx_f: %s\n", idx_f);
% index_set(char(k)) = cell2mat(struct2cell(load(idx_f)))';
index_set(char(k)) = load_mat(idx_f, "index")';
end
for k = index_key
fprintf("%s:", idx_name), disp(size(index_set(char(k))));
end
labels = load_mat(LABEL_P, "labels");
texts = load_mat(TEXT_P, "texts");
fprintf("labels:"), disp(size(labels));
fprintf("texts:"), disp(size(texts));
% 模拟训练
idx_train = index_set(char("train"));
% disp(size(idx_train));
N_TRAIN = length(idx_train);
% fprintf("#train: %d\n", N_TRAIN);
BATCH_SIZE = 128;
for iter = 1 : ceil(N_TRAIN / BATCH_SIZE)
fprintf("--- %d ---\n", iter);
meta_indices = randperm(N_TRAIN);
meta_index = meta_indices(1: BATCH_SIZE);
fprintf("batch size:"), disp(size(meta_index)); % (1, 128)
label_batch = labels(meta_index, :);
% DEPRECATED IMAGE READING METHOD, TOO SLOW
image_batch = load_images(idx_train(meta_index)); % 慢成狗,建议用 `vl_imreadjpeg`
text_batch = texts(meta_index, :);
fprintf("label size:"), disp(size(label_batch)); % (128, 21)
fprintf("image size:"), disp(size(image_batch)); % (128, 224, 224, 3)
fprintf("text size:"), disp(size(text_batch)); % (128, 1000)
% …此处训练…
break;
end % for iter
function image_batch = load_images(indices)
% 读一批 image %
global IMAGE_P
image_batch = [];
for i = 1 : length(indices)
idx = indices(i);
img_p = fullfile(IMAGE_P, strcat(num2str(idx), ".mat"));
% img = cell2mat(struct2cell(load(img_p)));
% img_ = load(img_p, "image");
% img = img_.image;
img = load_mat(img_p, "image");
image_batch(i, :, :, :) = img;
end
end % load_images
function data = load_mat(path, key)
st = load(path, key);
data = st.(key);
end % load_mat
References
- DCMH-CVPR2017/DCMH_matlab/DCMH_matlab/DCMH_demo.m
- NUS-WIDE数据集预处理
- NUS-WIDE数据集划分
- 遍历数组的两种方式
- Characters and Strings
- strcat
- strcmp
- if, elseif, else
- fullfile
- MATLAB查看变量的类型
- matlab之str与char:字符串数组与字符数组
- function
- Matlab equivalent of Python enumerate
- load
- 190311-3种方法Matlab结构体struct元素的索引
- MATLAB文件夹命名里的“+”和“@”是干什么用的#每天学习一点编程
- vl_imreadjpeg和cv2的resize结果不同