Crowd counting的数据集包括两部分:图像部分和标签部分
标签部分主要包括每个人头的坐标点:(x, y);
常见的标签格式例如:ShanghaiTech数据集中的格式,用mat文件存储每个人头的坐标点,一张图像对应一个mat文件;
当我们自己制作数据集时,需要经历以下几个步骤:
1)拍摄图像或者视频;视频需要切分成帧;
2)在图像上进行标点,标点的同时会记录下坐标点;
3)根据这些坐标点生成每张图像对应的.mat文件;
4)在训练时,将mat文件中的坐标转换为density map;
以下是每个步骤中所需要用到的py文件:
1)拍摄图像,如果是视频的话需要切分为视频帧:
将视频切分为视频帧:
import imageio
filename = "E:\video.MP4"
vid = imageio.get_reader(filename, 'ffmpeg')
try:
for num, im in enumerate(vid):
if (num / 50) and (num % 50) == 0: # 控制图像的输出张数;
imageio.imwrite('E:\save_photo_from_video\{}.jpg'.format(num // 50), im)
else:
continue
except imageio.core.format.CannotReadFrameError or RuntimeError:
pass
2)在图像上进行标注:
有一些现有的工具也可以完成相应的操作,这里我们用一段py代码来实现在图像上打点并将图像上人头的坐标点写入txt文件中,已备下一步使用:
打点代码:
import cv2
import os
"""
This code is used to:
1)对图片进行标注
2)生成对应的包含坐标信息的.txt文件
"""
imgs_path = "E:/images/" # 存放图像的文件夹
txt_path = "E:/txt/" # 存放txt文件的文件夹
files = os.listdir(imgs_path)
img = 0
coordinates = []
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, (x, y), 4, (0, 255, 0), thickness=-1)
coordinates.append([x, y])
print([x,y])
cv2.imshow("image", img)
for file in files: # for i in range(80, len(files)):
coordinates = []
img = cv2.imread(imgs_path+file)
cv2.namedWindow("image")
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.imshow("image", img)
cv2.waitKey(0)
with open(txt_path+file.replace("jpg","txt"), "w+") as f:
for coor in coordinates:
f.write(str(coor[0])+" "+str(coor[1])+"\n") # 记录每个人头的坐标点
f.write(str(len(coordinates))) # 记录一张图像中的人头总数
print(file+" is ok !"+"\n")
使用这个打点代码时,点击运行,会出现第一张图像,然后用鼠标在上面打点,标注完一张图像后,点击右上角的×关闭这张图像,开始对第二张图像打点,直到所有图像结束;
如果中途有图像发现点错了,可以记录下错误的图像名称,待全部点完之后再进行处理;如果图像太多,一次性标注不完,建议分批进行处理;
以上就是名为0.jpg的图像打点的过程以及生成对应的0.txt,第三张图可以看到txt中的内容,为人头的坐标,最后一行为人头总数;
3)通过这些txt文件中的坐标点,形成mat文件;(注:使用ShanghaiTech数据集中的同样的格式)
将txt文件转换为mat文件:
import numpy as np
import scipy.io as io
import os
txt_path = "E:/txts/"
save_path = "E:/mats/"
files = os.listdir(txt_path)
for file in files:
print(file)
with open(txt_path+file, "r") as f:
datas = f.readlines()
list = []
for i in range(0, len(datas) - 1):
line = datas[i].strip('\n')
ele = line.split( )
list.append(ele)
data_length = np.array([[datas[len(datas) - 1]]], dtype=np.uint8)
data = np.array(list, dtype=np.float64)
dt = np.dtype([('location', np.ndarray), ('number', np.ndarray)])
data_combine = np.array([(data, data_length)], dtype=dt)
image_info = np.array([data_combine], dtype=[('location', 'O'),('number', 'O')]) # [[(data, data_length)]]
image_info = np.array([[image_info]], dtype=object)
__header__ = b'MATLAB 5.0 MAT-file Platform: nt, Created on: 2021'
__version__ = '1.0'
__globals__ = '[]'
dict = {'__header__': __header__, '__version__': __version__, '__globals__': __globals__, 'image_info':image_info}
gt = dict["image_info"][0,0][0,0][0]
io.savemat(save_path+file.replace("txt","mat"), dict)
通过这个步骤,我们就可以得到每张图像对应的mat文件;
4)根据mat文件制作训练时需要的density map
此处使用matlab进行实现:
a)preapre_World_10.m
clc; clear all;
fileFolder=fullfile('F:\label');
dirOutput=dir(fullfile(fileFolder,'*'));
fileNames={dirOutput.name}';
standard_size = [384,512]; # 可以修改大小
dataset_name = ['WorldExpo10'];
original_path = ['F:/dataset/'];
output_path = 'F:/data/';
att = 'test';
train_path_img = strcat(output_path, 'train_frame/');
mkdir(train_path_img);
for ii = 3:105
gt_path = ['F:/train_label/' fileNames{ii} '/'];
train_path_den = strcat(output_path, 'train_lable/', fileNames{ii}, '/');
mkdir(train_path_den);
matFolder=fullfile(gt_path);
matdirOutput=dir(fullfile(matFolder,'*'));
matNames={matdirOutput.name}';
num_images=length(matdirOutput)-1;
disp(num_images)
for idx = 3:num_images
i = idx;
if (mod(idx,10)==0)
fprintf(1,'Processing %3d/%d files\n', idx, num_images);
end
load(strcat(gt_path, matNames{idx}));
input_img_name = strcat(original_path,'train_frame/',strrep(matNames{idx}, 'mat', 'jpg'));
disp(input_img_name)
im = imread(input_img_name);
[h, w, c] = size(im);
annPoints = point_position;
rate_h = standard_size(1)/h;
rate_w = standard_size(2)/w;
im = imresize(im,[standard_size(1),standard_size(2)]);
annPoints(:,1) = annPoints(:,1)*double(rate_w);
annPoints(:,2) = annPoints(:,2)*double(rate_h);
im_density = get_density_map_gaussian(im,annPoints);
im_density = im_density(:,:,1);
imwrite(im, [output_path 'train_frame/' strrep(matNames{idx}, 'mat', 'jpg')]);
csvwrite([output_path 'train_lable/' fileNames{ii} '/' strrep(matNames{idx}, 'mat', 'csv')], im_density);
end
end
b)get_density_map_gaussian()实现:
function im_density = get_density_map_gaussian(im,points)
im_density = zeros(size(im));
[h,w] = size(im_density);
if(length(points)==0)
return;
end
if(length(points(:,1))==1)
x1 = max(1,min(w,round(points(1,1))));
y1 = max(1,min(h,round(points(1,2))));
im_density(y1,x1) = 255;
return;
end
for j = 1:length(points)
f_sz = 15;
sigma = 4.0;
H = fspecial('Gaussian',[f_sz, f_sz],sigma);
x = min(w,max(1,abs(int32(floor(points(j,1))))));
y = min(h,max(1,abs(int32(floor(points(j,2))))));
if(x > w || y > h)
continue;
end
x1 = x - int32(floor(f_sz/2)); y1 = y - int32(floor(f_sz/2));
x2 = x + int32(floor(f_sz/2)); y2 = y + int32(floor(f_sz/2));
dfx1 = 0; dfy1 = 0; dfx2 = 0; dfy2 = 0;
change_H = false;
if(x1 < 1)
dfx1 = abs(x1)+1;
x1 = 1;
change_H = true;
end
if(y1 < 1)
dfy1 = abs(y1)+1;
y1 = 1;
change_H = true;
end
if(x2 > w)
dfx2 = x2 - w;
x2 = w;
change_H = true;
end
if(y2 > h)
dfy2 = y2 - h;
y2 = h;
change_H = true;
end
x1h = 1+dfx1; y1h = 1+dfy1; x2h = f_sz - dfx2; y2h = f_sz - dfy2;
if (change_H == true)
H = fspecial('Gaussian',[double(y2h-y1h+1), double(x2h-x1h+1)],sigma);
end
im_density(y1:y2,x1:x2) = im_density(y1:y2,x1:x2) + H;
end
end
至此,自己制作crowd counting数据集完毕。