#生成离散密度图 ,其实就是一个二维数组
def gen_discrete_map(im_height, im_width, points):
"""
func: generate the discrete map.
points: [num_gt, 2], for each row: [width, height]
"""
discrete_map = np.zeros([im_height, im_width], dtype=np.float32) # 首先初始化一下,高、宽和image一样 这里假设为400 * 300 里面4个人
h, w = discrete_map.shape[:2] # 表示从序列的开始提取直到索引 2 的元素(不包括索引 2) shape返回元组(400,300)就是h=400 宽 = 300
num_gt = points.shape[0] # shape返回元组(4,2) 取第一个索引 也就是4
if num_gt == 0:
return discrete_map #没有人头直接返回初始化的图 也就是全0的二维矩阵
# fast create discrete map
# 将点坐标四舍五入变整数 np.array将points变成numpy数组(这一步多余了)以为points本来就是numoy数组 .round()对每一个数字四舍五入 .astype将float变int
points_np = np.array(points).round().astype(int)
#这两个p_h 、p_w 是为了调整x和y,保证x和y不会超过边界
#points_np[:, 1]对取整后的二维矩阵 选取所有行(:表示选取所有行),仅选择每行的第一个元素(1表示选取第一个元素)即y 比如[20 30 100 200]
# np.array([2]*3) 意味着生成[2 2 2]
# np.minimum 比较两个数组,选择每个位置的最小值
p_h = np.minimum(points_np[:, 1], np.array([h-1]*num_gt).astype(int))
#oints_np[:, 0]提取所有x 就是那四个人头的x坐标 比如[2 4 6 10]
p_w = np.minimum(points_np[:, 0], np.array([w-1]*num_gt).astype(int))
# 将二维坐标映射的一维数组 用y*宽度+x 作为一维的索引 并转换为张量
p_index = torch.from_numpy(p_h* im_width + p_w).to(torch.int64)
# 创建一维0张量,索引处点1,.view(im_height, im_width) 将一维张量重新构形成原始的二维图像尺寸,再变成numpy数组
discrete_map = torch.zeros(im_width * im_height).scatter_add_(0, index=p_index, src=torch.ones(im_width*im_height)).view(im_height, im_width).numpy()
''' slow method
for p in points:
p = np.round(p).astype(int)
p[0], p[1] = min(h - 1, p[1]), min(w - 1, p[0])
discrete_map[p[0], p[1]] += 1
'''
#这个断言是一个安全检查,确保没有点丢失或多计算。如果断言失败(即,如果离散图的总和与点的数量不相符),Python 将抛出一个 AssertionError,这有助于调试和确保函数的正确性。
assert np.sum(discrete_map) == num_gt
return discrete_map
以上为作者源码
自我复现一遍,以自己标记的数据为例
import os
import torch
os.environ['KMP_DUPLICATE_LIB_OK']='True'
from datasets.crowd import random_crop,gen_discrete_map
from PIL import Image
import scipy.io
import numpy as np
import matplotlib.pyplot as plt
image_path = r'F:\crowd_data_self\img_1.jpg'
image = Image.open(image_path)
im_width, im_height = image.size
print(f'im_w:{im_width},im_h:{im_height}')
mat_file_path = r'F:\CCTrans-main\img_1.mat'
mat = scipy.io.loadmat(mat_file_path)
points = mat['image_info'][0][0][0]
print(points)
print(points.shape)
print(type(points))
discrete_map = np.zeros([im_height, im_width], dtype=np.float32)
points_round = np.array(points).round().astype(int)
y = points_round[:, 1]
x = points_round[:,0]
num = points.shape[0]
print(f'x坐标为:{x}')
print(f'y坐标为:{y}')
y_l = np.minimum(y,[im_height-1]*num)
x_l = np.minimum(x,[im_width-1]*num)
print(f'y坐标为:{y_l}')
print(f'x坐标为:{x_l}')
p_index = torch.from_numpy(y_l * im_width + x_l).to(torch.int64)
print(f'坐标点转换为一维索引:{p_index}')
discrete_map = torch.zeros(im_width*im_height).scatter_add_(0,index=p_index,src=torch.ones(im_width*im_height)).view(im_height,im_width).numpy()
print(discrete_map)
首先,提取到image_info,形如:
然后用切片操作拿到x和y坐标,并处理一下(四舍五入、不超过边界)、再转换为一维索引
最后创建一个height*weight的空tensor,索引处标1,再转换成二维数组,得到离散密度图
重点学习到的操作
1、.shape[:2]切片操作
因为.shape会返回 行*列的元组,比如(400,300) 再提取该元组从0-2(不包括2)的元素,就可以得到height和width
h,w = discrete_map.shape[:2]
这里也是同理 拿到shape的第一个元素,即行
目的是拿到总人头数:
num_gt = points.shape[0] # shape返回元组(4,2) 取第一个索引 也就是4
2、.round()对每一个元素四舍五入 astype转换类型
points_np = np.array(points).round().astype(int)
3、拿到所有x坐标和y坐标,也是用切片操作
points_np是二维数组,:表示选取所有行,1表示拿第一个元素(从0开始,这里就是y)
points_np[:, 1]
print(points_np) #会得到所有y,如下