Crowd Counting 系列NO4.—SwitchCNN(CVPR 2017)网络复现

文章目录

    • 引言
    • 简介
    • 环境配置
      • 1、numpy 安装
      • 2、matplotlib 安装
      • 3、cv2 安装,即opencv-python安装
      • 4、scipy 安装
      • 5、theano安装
      • 7、flip_filters不再支持
    • 数据问题
    • 密度图生成
    • 注意

引言

SwitchCNN是我看的比较早的一篇多列密集计数网络了,但是其网络实现因各种问题我一直没有复现,现如今因Crowd Counting综述讲解,我不禁又沉下心来继续对其进行复现,特此记录,避免后来者多走弯路。

简介

Article:Switching Convolutional Neural Network for Crowd Counting
Code: crowd-counting-cnn

环境配置

其实,环境配置我尝试比较久,因各种问题都歇菜了,从python 3.10 到3.6我都试了一遍,发现会出现各种问题。具体问题,尝试过的就知道了。最终,我也是在尝试中看到了有些错误,如cPickle等语言版本问题,才选择了python 2.7 环境实现了SwitchCNN的运行(不排除python3运行的可行性,但是修改我个人觉得有点麻烦)。

ok,我们开始代码的运行,首先,我们先把Anaconda 环境和Pycharm Project环境搭建好,Anaconda创建环境语句如下:
在这里插入图片描述

conda create -n SwitchCNN-Test python=2.7

Proceed: Y ,创建完毕。
在这里插入图片描述
Project-File-Setting-Project:Python Interpreter
在这里插入图片描述
搭建完基础环境后我们就开始运行,并为环境进行包的添加以及代码的修改。

开始之前,我们先看下README.TXT

SCNN README
-------------


To test SCNN on trained model:
	[1] Create test set by executing 'dataset/create_test_set.m'.
	[2] Run 'src/test_scnn.py'.

To train SCNN:
	[1] Create dataset by executing 'dataset/create_datasets.m'.
	[2] Run differential_train.py to perform differential training.
	[3] Run coupled_train.py to perform coupled training.

create_datasets.m代码如下:

create_test_set;
create_train_set;
system('python make_validation_set.py');

意思先进行数据的创建,但有个问题是我们打开dataset/create_train_set()后运行会出现:create_density()函数未定义的现象。m
文件代码如下:

% Creates train set

function create_train_set()

image_fold = './ST_part_A/train_data/images';
gt_fold = './ST_part_A/train_data/ground_truth';

final_image_fold = './train/images';
final_gt_fold = './train/gt';

mkdir(final_image_fold);
mkdir(final_gt_fold);

jpgFiles = dir([image_fold, '/*.jpg']);
numfiles = length(jpgFiles);

parfor i = 1: numfiles
    [~, f_1] = fileparts(jpgFiles(i).name);
    f = sprintf('%s.jpg',f_1);
    I = imread(fullfile(image_fold, f));
    file_name = f_1;
    mat_filename = sprintf('GT_%s.mat', file_name);

    ann = load(fullfile(gt_fold, mat_filename));
    gt = ann.image_info{1,1}.location;
    count = 1;

    % generate density map    
    d_map_h = floor(floor(double(size(I, 1)) / 2.0) / 2.0);
    d_map_w = floor(floor(double(size(I, 2)) / 2.0) / 2.0);

    % Density Map with Geometry-Adaptive Kernels (see MCNN code: 
    % Single-Image Crowd Counting via Multi-Column Convolutional 
    % Neural Network; CVPR 2017)
    d_map = create_density(gt / 4.0, d_map_h, d_map_w);

    p_h = floor(double(size(I, 1)) / 3.0);
    p_w = floor(double(size(I, 2)) / 3.0);
    d_map_ph = floor(floor(p_h / 2.0) / 2.0);
    d_map_pw = floor(floor(p_w / 2.0) / 2.0);

    % create overlapping patches of images and density maps
    py = 1;
    py2 = 1;
    for j = 1: 3
        px = 1;
        px2 = 1;
        for k = 1: 3
            final_image = double(I(py: py + p_h - 1, px: px + p_w - 1, :));
            final_gt = d_map(py2: py2 + d_map_ph - 1, px2: px2 + d_map_pw - 1);
            px = px + p_w;
            px2 = px2 + d_map_pw;
            if size(final_image, 3) < 3
                final_image = repmat(final_image, [1, 1, 3]);
            end
            image_name = sprintf('%s_%d.jpg', file_name, count);
            gt_name = sprintf('%s_%d.mat', file_name, count);
            imwrite(uint8(final_image), fullfile(final_image_fold, image_name));
            do_save(fullfile(final_gt_fold, gt_name), final_gt);
            count = count + 1;
        end
        py = py + p_h;
        py2 = py2 + d_map_ph;
    end
end

end


function do_save(gt_name, final_gt)

save(gt_name, 'final_gt');

end


其实,这个问题作者已经在github代码发布时解释了,解释如下:
在这里插入图片描述
也就是说创建密度图的代码需要大家自行添加。有现成的数据谁会再重新生成呢,因为我有自己的数据,因此,我就直接用了私有的数据,而没有用公共数据的数据,我的ground truth数据分辨率同输入图像数据(就是因为这个数据问题,致使我各种修改,这是后话)。

ok,让我们设置好数据的路径,然后开始我们复现的行程。
在这里插入图片描述

1、numpy 安装

在这里插入图片描述

pip install numpy

在这里插入图片描述

2、matplotlib 安装

在这里插入图片描述

pip install matplotlib

在这里插入图片描述

3、cv2 安装,即opencv-python安装

在这里插入图片描述
之前,我们安装opencv-python时碰到一些问题,这在‘cv2’、PIL、torch、torchivision一文中我们已经介绍了如何解决,如下
在这里插入图片描述
这里需要注意的是,我们的python=2.7,因此,opencv-python我们在安装时要匹配2.7,chatGPT给出了答案(真是至宝啊!!!):
在这里插入图片描述

安装命令如下:

pip install opencv-python==3.4.5.20

在这里插入图片描述

4、scipy 安装

在这里插入图片描述

pip install scipy

在这里插入图片描述

5、theano安装

在这里插入图片描述

pip install theano

在这里插入图片描述
6、lasagne安装
在这里插入图片描述

pip install lasagne

在这里插入图片描述
出现错误(来源与lasagne)
在这里插入图片描述
根据chatGPT给的建议,我首先采用了第一种方式,但是发现这种方法修改也会比较麻烦,并最终选择2,即降低lasagne的版本为1.0.5。
在这里插入图片描述

pip install theano==1.0.5

在这里插入图片描述
但运行仍然会出现上述错误,然后再次chatGPT发现答案又变化了~,耍我玩呢请添加图片描述
。这次给的建议时安装兼容的Theano和Lasagne。
在这里插入图片描述

pip install theano==0.8.2
pip install lasagne==0.1

在这里插入图片描述
嗯嗯,错误消除了。

7、flip_filters不再支持

**加粗样式**
这个问题chatGPT给出的解释是,现在的版本已经不再支持flip_filters这个参数了,因此,我们需要将networks.py文件中的这个参数全部删除掉。
在这里插入图片描述
为了方便,我这里直接将networks.py文件代码附上,方便大家直接复制粘贴:

# networks.py
# Defines all the networks of SCNN


import numpy as np
import theano
import theano.tensor as T
import lasagne

from lasagne.layers import InputLayer
from lasagne.layers import DenseLayer
from lasagne.layers import MaxPool2DLayer as PoolLayer
from lasagne.layers import Conv2DLayer as ConvLayer


def std_conv_layer(input, num_filters, filter_shape, pad = 'same'):
    return ConvLayer(input, num_filters, filter_shape,
                        pad = pad, 
                        W = lasagne.init.Normal(std = 0.01, mean = 0.0))


# 9x9 Regressor (R1)
class shallow_net_9x9():
    
    def __init__(self, input = None, name = 'shallow_9x9'):
        if input is None:
            input = T.tensor4()
        self.input = input
        self.name = name
        net = {}
        net['input'] = InputLayer(shape = (None, 1, None, None),
                                  input_var = self.input)
        net['conv1_1'] = std_conv_layer(net['input'], 16, 9)
        net['pool1'] = PoolLayer(net['conv1_1'], 2)
        net['conv1_2'] = std_conv_layer(net['pool1'], 32, 7)
        net['pool2'] = PoolLayer(net['conv1_2'], 2)
        net['conv1_3'] = std_conv_layer(net['pool2'], 16, 7)
        net['conv1_4'] = std_conv_layer(net['conv1_3'], 8, 7)
        net['conv'] = std_conv_layer(net['conv1_4'], 1, 1)
        self.net = net
        self.output_layer = net['conv']
        self.train_output = lasagne.layers.get_output(self.output_layer)
        self.test_output = lasagne.layers.get_output(self.output_layer,
                                deterministic = True)
        self.parameters = lasagne.layers.get_all_params(self.output_layer,
                                                        trainable=True)


# 7x7 Regressor (R2)
class shallow_net_7x7():
    
    def __init__(self, input = None, name = 'shallow_7x7'):
        if input is None:
            input = T.tensor4()
        self.input = input
        self.name = name
        net = {}
        net['input'] = InputLayer(shape = (None, 1, None, None),
                                  input_var = self.input)
        net['conv2_1'] = std_conv_layer(net['input'], 20, 7)
        net['pool2_1'] = PoolLayer(net['conv2_1'], 2)
        net['conv2_2'] = std_conv_layer(net['pool2_1'], 40, 5)
        net['pool2_2'] = PoolLayer(net['conv2_2'], 2)
        net['conv2_3'] = std_conv_layer(net['pool2_2'], 20, 5)
        net['conv2_4'] = std_conv_layer(net['conv2_3'], 10, 5)
        net['conv'] = std_conv_layer(net['conv2_4'], 1, 1)
        self.net = net
        self.output_layer = net['conv']
        self.train_output = lasagne.layers.get_output(self.output_layer)
        self.test_output = lasagne.layers.get_output(self.output_layer,
                                deterministic = True)
        self.parameters = lasagne.layers.get_all_params(self.output_layer,
                                                        trainable=True)


# 5x5 Regressor (R3)
class shallow_net_5x5():
    
    def __init__(self, input = None, name = 'shallow_5x5'):
        if input is None:
            input = T.tensor4()
        self.input = input
        self.name = name
        net = {}
        net['input'] = InputLayer(shape = (None, 1, None, None),
                                  input_var = self.input)
        net['conv3_1'] = std_conv_layer(net['input'], 24, 5)
        net['pool3_1'] = PoolLayer(net['conv3_1'], 2)
        net['conv3_2'] = std_conv_layer(net['pool3_1'], 48, 3)
        net['pool3_2'] = PoolLayer(net['conv3_2'], 2)
        net['conv3_3'] = std_conv_layer(net['pool3_2'], 24, 3)
        net['conv3_4'] = std_conv_layer(net['conv3_3'], 12, 3)
        net['conv'] = std_conv_layer(net['conv3_4'], 1, 1)
        self.net = net
        self.output_layer = net['conv']
        self.train_output = lasagne.layers.get_output(self.output_layer)
        self.test_output = lasagne.layers.get_output(self.output_layer,
                                deterministic = True)
        self.parameters = lasagne.layers.get_all_params(self.output_layer,
                                                        trainable=True)


# Switch classifier
class deep_patch_classifier():
    
    def __init__(self, input = None, name = 'deep_patch_classifier'):
        if input is None:
            input = T.tensor4()
        self.input = input
        self.name = name
        rgb_means = T.as_tensor_variable(\
                                np.array([104.008, 116.669, 122.675],
                                dtype = theano.config.floatX));
        mean_sub_input = T.tile(self.input, [1, 3, 1, 1])
        mean_sub_input -= rgb_means.dimshuffle('x', 0, 'x', 'x')
        net = {}
        net['input'] = InputLayer(shape = (None, 3, None, None),
                                  input_var = mean_sub_input)
        net['conv1_1'] = ConvLayer(
                    net['input'], 64, 3, pad=1,
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv1_2'] = ConvLayer(
                    net['conv1_1'], 64, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['pool1'] = PoolLayer(net['conv1_2'], 2)
        net['conv2_1'] = ConvLayer(
                    net['pool1'], 128, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv2_2'] = ConvLayer(
                    net['conv2_1'], 128, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['pool2'] = PoolLayer(net['conv2_2'], 2)
        net['conv3_1'] = ConvLayer(
                    net['pool2'], 256, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv3_2'] = ConvLayer(
                    net['conv3_1'], 256, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv3_3'] = ConvLayer(
                    net['conv3_2'], 256, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['pool3'] = PoolLayer(net['conv3_3'], 2)
        net['conv4_1'] = ConvLayer(
                    net['pool3'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv4_2'] = ConvLayer(
                    net['conv4_1'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv4_3'] = ConvLayer(
                    net['conv4_2'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['pool4'] = PoolLayer(net['conv4_3'], 2)
        net['conv5_1'] = ConvLayer(
                    net['pool4'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv5_2'] = ConvLayer(
                    net['conv5_1'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['conv5_3'] = ConvLayer(
                    net['conv5_2'], 512, 3, pad=1, 
                    W = lasagne.init.Normal(std=0.01, mean=0.0))
        net['pool5'] = PoolLayer(net['conv5_3'], 2)
        net['gap'] = lasagne.layers.GlobalPoolLayer(net['pool5'])
        net['fc'] = DenseLayer(net['gap'], num_units=512)
        net['softmax'] = DenseLayer(net['fc'], num_units=3,
                            nonlinearity=lasagne.nonlinearities.softmax)
        self.output_layer = net['softmax']
        self.net = net
        self.train_output = lasagne.layers.get_output(net['softmax'])
        self.test_output = lasagne.layers.get_output(net['softmax'], deterministic=True)
        self.parameters = lasagne.layers.get_all_params(net['softmax'],
                                                        trainable=True)
    

# Create and compile theano graph for all the networks
def create_network_functions(networks):
    momentum = 0.9
    weight_decay = 0.0005
    run_funcs = []
    test_funcs = []
    train_funcs = []
    print 'Compiling theano functions...'
    for i, net in enumerate(networks):
        print ' > ' + net.name + '...'
        run_funcs.append(theano.function(inputs = [net.input],
                                          outputs = net.test_output))
        if i == 0:
            Y = T.lvector()
            train_loss = lasagne.objectives.categorical_crossentropy(net.train_output, Y).mean()
            test_loss = lasagne.objectives.categorical_crossentropy(net.test_output, Y).mean()
        else:
            Y = T.tensor4()
            train_loss = lasagne.objectives.squared_error(net.train_output, Y).mean()
            test_loss = lasagne.objectives.squared_error(net.test_output, Y).mean()
        test_funcs.append(theano.function(inputs = [net.input, Y],
                                          outputs = [test_loss, net.test_output]))
        learning_rate = T.scalar()
        updates = lasagne.updates.momentum(
                    train_loss, net.parameters, learning_rate = learning_rate, momentum=0.9)
        train_funcs.append(theano.function(
                        inputs = [net.input, Y, learning_rate],
                        outputs = train_loss,
                        updates = updates))
    print 'Done'
    return (train_funcs, test_funcs, run_funcs)



数据问题

上述问题解决后,貌似网络可以运行了,但不幸的是又又出现了以下问题:

在这里插入图片描述
啥意思呢?这个问题其实困扰我蛮久的,我用chatGPT进行了咨询,得到了如下解释:
在这里插入图片描述
查看网络我们发现执行的是test_fn,这个函数是什么呢?这个函数在networks.py文件中的create_network_function()函数做了如下定义:

  Y = T.tensor4()
            train_loss = lasagne.objectives.squared_error(net.train_output, Y).mean()
            test_loss = lasagne.objectives.squared_error(net.test_output, Y).mean()
        test_funcs.append(theano.function(inputs = [net.input, Y],
                                          outputs = [test_loss, net.test_output]))

这里调用的是theano.function用于图计算函数,theano.function(…): 这是 Theano 中的一个函数,用于创建一个可以计算指定输入的输出的函数。你可以把它想象成一个将某些计算逻辑封装起来,以便可以在后续调用时执行的工具。那这个函数的具体功能就是计算test_loss,也就是说输入的两个参量应当是模拟值和真实值,错误表示两个输入的大小是不一致的。

其实这个问题在运行MCNN的时候是不存在的,即使我的ground truth数据没有进行下采样。但在SwitchCNN中需要将ground truth进行下采样,因为网络分类的时候是基于MCNN的,即存在两次池化,每次采用2*2的池化操作,这样我们模拟得到的GT应当是原来的1/4,换句话说,我们在生成密度图时需要将ground truth变为原来的1/4。

此外,我们还需要做的一点是,SwitchCNN也采用了MCNN中patch的操作方法,这一点在test_scnn.py代码中也有体现,如下:

def test_scnn(test_funcs, dataset, do_switching = True):
    num_patches = 9
    
    num_subnet = len(test_funcs) - 1
    losses = np.zeros(num_subnet + 2)
    count_losses = np.zeros_like(losses)
    mae_image = np.zeros_like(losses)
    switch_stat = np.zeros(num_subnet)
    pc_switch_stat = np.zeros(num_subnet)
    pc_switch_error = 0.0

    patch_count_accumulator_tmp = np.zeros((num_subnet + 2, 2))
    loss_tmp = np.zeros(num_subnet)
    count_tmp = np.zeros(num_subnet)
    patch_tmp = np.zeros((num_subnet, 2))
    patch_count = 0
    image_count = 0

    for i, (X, Y) in enumerate(dataset):
        for j, test_fn in enumerate(test_funcs[1: ]):
            loss_tmp[j], Y_subnet = test_fn(X, Y)
            patch_tmp[j, 0] = np.sum(Y_subnet)
            patch_tmp[j, 1] = np.sum(Y)
            patch_count_accumulator_tmp[1 + j, 0] += patch_tmp[j, 0] 
            patch_count_accumulator_tmp[1 + j, 1] += patch_tmp[j, 1] 
            count_tmp[j] = np.abs(patch_tmp[j, 0] - patch_tmp[j, 1])
            
        Y_pc = np.argmin(count_tmp)
        losses[-1] += loss_tmp[Y_pc]
        count_losses[-1] += count_tmp[Y_pc]
        patch_count_accumulator_tmp[-1, 0] += patch_tmp[Y_pc, 0]
        patch_count_accumulator_tmp[-1, 1] += patch_tmp[Y_pc, 1]

        # Switching
        if do_switching:
            switch_stat[Y_pc] += 1
            pc_loss, Y_pc_pred = test_funcs[0](X, np.array([Y_pc]))
            Y_pc_pred = np.argmax(Y_pc_pred, axis = 1)[0]
            pc_switch_stat[Y_pc_pred] += 1
            if Y_pc_pred != Y_pc:
                pc_switch_error += 1.0
            losses[0] += pc_loss
            patch_count_accumulator_tmp[0, 0] += patch_tmp[Y_pc_pred, 0]
            patch_count_accumulator_tmp[0, 1] += patch_tmp[Y_pc_pred, 1]

        losses[1: -1] += loss_tmp
        count_losses[1: -1] += count_tmp
        patch_count += 1

        # Compute MAE
        if patch_count >= num_patches:
            patch_count = 0
            mae_image += np.abs(patch_count_accumulator_tmp[:, 0] - \
                                patch_count_accumulator_tmp[:, 1])
            patch_count_accumulator_tmp[:, :] = 0
            image_count += 1

    assert(patch_count == 0)
    i += 1
    print i, image_count
    losses /= i
    count_losses /= i
    switch_stat /= i
    pc_switch_stat /= i
    pc_switch_error /= i
    mae_image /= image_count

    # Printing Results
    txt = ''
    loss_names = ['SCNN', 'R1', 'R2', 'R3', 'SCNN_ideal']
    if not do_switching:
        loss_names = loss_names[1: ]
        count_losses = count_losses[1: ]
        losses = losses[1: ]
        mae_image = mae_image[1: ]
    txt += '\n\tPer_Patch mae [l2 loss]: '
    for i, j, k in zip(loss_names, count_losses, losses):
        txt += ('%s: %.12f [%.12f], ' % (i, j, k))
    txt += '\n\tMAE_Stat: '
    for i, j in zip(loss_names, mae_image):
        txt += ('%s: %.12f, ' % (i, j))
    if do_switching:
        txt += '\n\tSwitch_Stat: '
        for i, j, k in zip(loss_names[1: -1], pc_switch_stat, switch_stat):
            txt += ('%s: %f%% [%f%%], ' % (i, j * 100.0, k * 100.0))
        txt += '\n\tSwitch_Error: %f%%' % (pc_switch_error * 100.0)
        return mae_image[0], mae_image[-1], txt
    return 0.0, mae_image[-1], txt

密度图生成

基于上述原因,我还是采用了在原有代码的基础上,对密度图的生成代码进行了复现,最简单的方式就是chatGPT,你懂的,不用白不用🐶。为了便于复现代码,我直接将数据创建代码粘贴如下:

% Creates train set

function create_train_set()

image_fold = './train/Images';
gt_fold = './train/anno';

final_image_fold = './train/patch_images';
final_gt_fold = './train/patch_gt_mat';

mkdir(final_image_fold);
mkdir(final_gt_fold);

jpgFiles = dir([image_fold, '/*.jpg']);
numfiles = length(jpgFiles);

parfor i = 1: numfiles
    [~, f_1] = fileparts(jpgFiles(i).name);
    f = sprintf('%s.jpg',f_1);
    I = imread(fullfile(image_fold, f));
    file_name = f_1;
    mat_filename = sprintf('%s.mat', file_name);

    ann = load(fullfile(gt_fold, mat_filename));
    gt = ann.image_info{1,1}.location;
    count = 1;

    % generate density map    
    d_map_h = floor(floor(double(size(I, 1)) / 2.0) / 2.0);
    d_map_w = floor(floor(double(size(I, 2)) / 2.0) / 2.0);
    
    % Density Map with Geometry-Adaptive Kernels (see MCNN code: 
    % Single-Image Crowd Counting via Multi-Column Convolutional 
    % Neural Network; CVPR 2017)
 
    d_map = create_density(gt / 4.0, d_map_h, d_map_w);
%     gt_name = sprintf('GT_%s.mat', file_name);
%     do_save(fullfile(final_gt_fold, gt_name), d_map);
    
    
    p_h = floor(double(size(I, 1)) / 3.0);
    p_w = floor(double(size(I, 2)) / 3.0);
    d_map_ph = floor(floor(p_h / 2.0) / 2.0);
    d_map_pw = floor(floor(p_w / 2.0) / 2.0);

   % create overlapping patches of images and density maps
    py = 1;
    py2 = 1;
    for j = 1: 3
        px = 1;
        px2 = 1;
        for k = 1: 3
            final_image = double(I(py: py + p_h - 1, px: px + p_w - 1, :));
            final_gt = d_map(py2: py2 + d_map_ph - 1, px2: px2 + d_map_pw - 1);
            px = px + p_w;
            px2 = px2 + d_map_pw;
            if size(final_image, 3) < 3
                final_image = repmat(final_image, [1, 1, 3]);
            end
            image_name = sprintf('%s_%d.jpg', file_name, count);
            gt_name = sprintf('%s_%d.mat', file_name, count);
            imwrite(uint8(final_image), fullfile(final_image_fold, image_name));
            do_save(fullfile(final_gt_fold, gt_name), final_gt);
            count = count + 1;
        end
        py = py + p_h;
        py2 = py2 + d_map_ph;
    end
end

end


function do_save(gt_name, final_gt)

save(gt_name, 'final_gt');

end



function density_map = create_density(gt, d_map_h, d_map_w)
    % 初始化密度图为全零矩阵
    density_map = zeros(d_map_h, d_map_w);
    
    % 获取注释点的数量
    num_gt_points = size(gt, 1);
    
    % 如果没有注释点,直接返回零密度图
    if num_gt_points == 0
        return;
    end
    
    % 如果只有一个注释点,将整个密度分布在该点上
    if num_gt_points == 1
        x = max(1, min(d_map_w, round(gt(1, 1))));
        y = max(1, min(d_map_h, round(gt(1, 2))));
        density_map(y, x) = 1;
        return;
    end
    
    % 根据注释点生成密度图
    for i = 1:num_gt_points
        % 获取当前注释点的坐标
        x = min(d_map_w, max(1, round(gt(i, 1))));
        y = min(d_map_h, max(1, round(gt(i, 2))));
        
        % 设置高斯核的大小,根据邻近点的平均距离调整
        size_gaussian = 15; % 默认高斯核大小
        distances = pdist2(gt, gt(i, :));
        distances = sort(distances);
        if num_gt_points > 3
            size_gaussian = floor(mean(distances(2:4)) / 2);
        end
        if size_gaussian < 0
            size_gaussian = 15;
        sigma = size_gaussian/4;
        % 生成高斯核
        gaussian = fspecial('gaussian', [size_gaussian, size_gaussian], sigma);
        
        % 计算高斯核在密度图中的位置
        x1 = max(1, x - floor(size_gaussian / 2));
        y1 = max(1, y - floor(size_gaussian / 2));
        x2 = min(d_map_w, x + floor(size_gaussian / 2));
        y2 = min(d_map_h, y + floor(size_gaussian / 2));
        
        % 调整高斯核的边界以避免越界
        g_x1 = max(1, 2 - (x - floor(size_gaussian / 2)));
        g_y1 = max(1, 2 - (y - floor(size_gaussian / 2)));
        g_x2 = g_x1 + (x2 - x1);
        g_y2 = g_y1 + (y2 - y1);
        
        % 确保子矩阵的大小一致并检查是否越界
        if g_x2 <= size(gaussian, 2) && g_y2 <= size(gaussian, 1) ...
                && (x2 - x1 + 1) == (g_x2 - g_x1 + 1) && (y2 - y1 + 1) == (g_y2 - g_y1 + 1)
            % 将高斯核添加到密度图中
            density_map(y1:y2, x1:x2) = density_map(y1:y2, x1:x2) + gaussian(g_y1:g_y2, g_x1:g_x2);
        end
    end
end


注意

代码运行时还会出现以下错误:
1、 保存文件若未创建文件夹,则需要在save_nets中对代码进行如下修改


# Save network weights
def save_nets(files, networks):
    print ('Saving nets...')
    for file_name in files:
        filepath = os.path.dirname(file_name)
        if not os.path.exists(filepath):
            os.makedirs(filepath)
    for file_name, net in zip(files, networks):
        fp = open(file_name, 'wb')
        params = lasagne.layers.get_all_param_values(net.output_layer)
        cPickle.dump(params, fp, protocol = cPickle.HIGHEST_PROTOCOL)
        print (' >', net.name)
        fp.close()
    print (' > Done.')


2、 matplotlib不支持jpg格式,需要在differential_train.py文件中进行如下代码修改:

        p1, = plt.plot(min_mae_history[: epoch + 1])
        # plt.savefig(os.path.join(log_path, 'min_mae_history.jpg'))  # matplotlib不支持jpg格式
        plt.savefig(os.path.join(log_path, 'min_mae_history.png'))
        plt.clf()

代码复现成功!!!😊😊😊
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901800.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

漏洞挖掘 | 基于mssql数据库的sql注入

前记 今天挖edu随意点开个站&#xff0c;发现存在mssql数据库的sql注入&#xff0c;在此分享下整个挖掘过程 目录 0x1 判断网站数据库类型 0x2 了解mssql数据库的主要三大系统表 0x3 了解mssql的主要函数 0x4 判断注入点及其注入类型 0x5 联合查询之判断列数 0x6 联合查询之…

Redis 哨兵 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 哨兵 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 哨兵 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis & 哨兵…

【成长day】NeRF学习记录1:预备知识nerf论文算法学习

个人知乎文章链接&#xff1a;https://zhuanlan.zhihu.com/p/3383996241 预备知识 NeRF重建 NeRF的全称是Neural Radiance Fields&#xff0c;即将场景表示为视场合成的神经辐射场&#xff0c;用神经网络来拟合辐射场&#xff0c;实现对三维场景的隐式表示。本质是完成了图形…

[项目详解][boost搜索引擎#2] 建立index | 安装分词工具cppjieba | 实现倒排索引

目录 编写建立索引的模块 Index 1. 设计节点 2.基本结构 3.(难点) 构建索引 1. 构建正排索引&#xff08;BuildForwardIndex&#xff09; 2.❗构建倒排索引 3.1 cppjieba分词工具的安装和使用 3.2 引入cppjieba到项目中 倒排索引代码 本篇文章&#xff0c;我们将继续项…

Android——事件冲突处理

当我们给列表的item设置了点击事件后&#xff0c;又给item中的按钮设置了点击事件&#xff0c;此时item的点击事件会失效。 解决 给item的布局xml中设置以下属性 android:descendantFocusability"blocksDescendants"<LinearLayout xmlns:android"http://sc…

005:航空力学基础、无人机操纵、飞机性能

摘要&#xff1a;本文详细介绍无人机稳定性、操控性、飞机性能等概念。 一、飞机的稳定性 概念&#xff1a; 飞机的稳定性&#xff08;安定性&#xff09;&#xff0c;是指在飞机受到扰动后&#xff0c;不经飞行员操纵&#xff0c;能恢复到受扰动前的原始状态&#xff08;即原…

Android系统架构

Android系统架构&#xff1a; Android系统架构是一个复杂的、分层的结构&#xff0c;旨在提供高度的灵活性和可扩展性。这个架构可以大致分为以下几个主要层次&#xff1a; Linux Kernel&#xff08;Linux内核&#xff09;&#xff1a; Linux内核是Android系统的底层&#xff0…

OAK相机的RGB-D彩色相机去畸变做对齐

▌低畸变标准镜头的OAK相机RGB-D对齐的方法 OAK相机内置的RGB-D管道会自动将深度图和RGB图对齐。其思想是将深度图像中的每个像素与彩色图像中对应的相应像素对齐。产生的RGB-D图像可以用于OAK内置的图像识别模型将识别到的2D物体自动映射到三维空间中去&#xff0c;或者产生的…

OpenSSL

OpenSSL 概述 OpenSSL 是一个开源的、安全传输协议实现工具&#xff0c;广泛应用于数据加密与解密、证书生成与管理以及其他安全性相关的任务。在现代网络安全中&#xff0c;OpenSSL 被用于构建和维护 SSL/TLS 通信&#xff0c;确保数据在传输过程中的机密性和完整性。 简单来…

西圣和绿联电容笔哪款好用?西圣、绿联和uhb电容笔真实避坑测评!

现在市面上的平替电容笔种类非常多&#xff0c;在购买的时候大多数人都没有非常确定的目标&#xff0c;这主要是因为大多数人对电容笔的认识程度不够。 作为一个有着多年数码产品测评经验的测评员&#xff0c;我刚好对电容笔也有比较深刻的理解&#xff0c;也借着大家问我关于…

ASP.NET MVC-font awesome-localhost可用IIS不可用

环境&#xff1a; win10, .NET 6.0&#xff0c;IIS 问题描述 本地IIS正常显示&#xff0c;但放到远程服务器上&#xff0c;每个icon都显示?。同时浏览器的控制台报错&#xff1a; fontawesome-webfont.woff2:1 Failed to load resource: the server responded with a statu…

【网络协议栈】Tcp协议(上)结构的解析 和 Tcp中的滑动窗口(32位确认序号、32位序号、4位首部长度、6位标记位、16为窗口大小、16位紧急指针)

绪论​ “没有那么多天赋异禀&#xff0c;优秀的人总是努力翻山越岭。”本章主要讲到了再五层网络协议从上到下的第二层传输层中使用非常广泛的Tcp协议他的协议字段结构&#xff0c;通过这些字段去认识其Tcp协议运行的原理底层逻辑和基础。后面将会再写一篇Tcp到底是通过什么调…

java实现的音视频格式转化器

一、前言 最近写了一款图形界面版的音视频格式转化器&#xff0c;可以实现将多种视频之间进行转化&#xff0c;非常好用&#xff0c;如将AVI转换为&#xff0c;TS&#xff0c;FLV&#xff0c;MP4等。音频可将MP3转成WAV。 二、实现 1.需引入相关maven依赖。 <!-- 核心包 -…

群控系统服务端开发模式-应用开发-业务架构逻辑开发准备工作

安装与仓库已经调整完毕&#xff0c;现在开发业务架构逻辑&#xff0c;其次再开发功能逻辑。业务架构逻辑开发与功能逻辑开发不是一回事&#xff0c;一定要明白。业务架构指的是做某一件事或是某一种类型的事的逻辑&#xff0c;在互联网web应用中通常指一套系统的外在逻辑&…

知识见闻 - 磁力片原理

磁力片是一种利用磁性原理设计的玩具&#xff0c;它的工作原理和磁性方向的排列方式非常有趣。让我们深入了解一下磁力片的核心原理和磁性方向的特点。 磁力片的基本原理 磁力片的工作原理基于磁铁的基本特性。每个磁力片都包含多个小磁铁&#xff0c;这些磁铁被精心排列&#…

强化学习数学原理学习(一)

前言 总之开始学! 正文 先从一些concept开始吧,有一个脉络比较好 state 首先是就是状态和状态空间,显而易见,不多说了 action 同理,动作和动作空间 state transition 状态转换,不多说 policy 策略,不多说 reward 奖励,不多说 MDP(马尔科夫) 这里需要注意到就是这个是无…

小程序视频SDK解决方案,提供个性化开发和特效定制设计

美摄科技作为视频处理技术的领航者&#xff0c;深知在这一变革中&#xff0c;每一个细微的创新都能激发无限可能。因此&#xff0c;我们精心打造了一套小程序视频SDK解决方案&#xff0c;旨在满足不同行业、不同规模客户的多元化需求&#xff0c;携手共创视频内容的璀璨未来。 …

守护头顶安全——AI高空抛物监测,让悲剧不再重演

在城市的喧嚣中&#xff0c;我们享受着高楼林立带来的便捷与繁华&#xff0c;却往往忽视了那些隐藏在高空中的危险。近日&#xff0c;震惊全国的高空抛物死刑案件被最高院核准并执行。案件中被告人多次高空抛物的举动&#xff0c;夺去了无辜者的生命&#xff0c;也让自己付出了…

Leetcode11:盛水最多的容器

原题地址&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳…

Docker本地安装Minio对象存储

Docker本地安装Minio对象存储 1. 什么是 MinIO&#xff1f; MinIO 是一个开源的对象存储服务器。这意味着它允许你在互联网上存储大量数据&#xff0c;比如文件、图片、视频等&#xff0c;而不需要依赖传统的文件系统。MinIO 的特点在于它非常灵活、易于使用&#xff0c;同时…