人群计数-CsrNet-caffe实现

CsrNet论文介绍

此处介绍推荐以下博客:
博客1
博客2

CsrNet论文复现-caffe

2019-12-18更新训练好的模型:
shanghaiTech-ParB训练好的模型

数据集制作

  • lmdb-密度图label制作
  1. 生成人群密度图
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
  1. 生成lmdb
#include "ml.h"
#include <stdio.h>
#include "caffe/caffe.hpp"
#include <iostream>
#include <lmdb.h>
#include <stdint.h>
#include <fstream>  // NOLINT(readability/streams)
#include <string>
#include <sys/stat.h>
#include "caffe/proto/caffe.pb.h"// 解析caffe中proto类型文件的头文件

#include <opencv2/ml/ml.hpp>

using namespace std;
using namespace cv;
void serialize_label(const char* lmdb_path,const std::string csv_list,std::string ground_truth_csv)
{
	MDB_env *mdb_env;//数据库环境的“不透明结构”,不透明类型是一种灵活的类型,他的大小是未知的
	MDB_dbi mdb_dbi;//在数据库环境中的一个独立的数据句柄
	MDB_val mdb_key, mdb_data;//用于从数据库输入输出的通用结构
	MDB_txn *mdb_txn;//不透明结构的处理句柄,所有的数据库操作都需要处理句柄,处理句柄可指定为只读或读写
	LOG(INFO) << "Opening lmdb " << lmdb_path;
	CHECK_EQ(mkdir(lmdb_path, 0744), 0) << "mkdir " << lmdb_path << " failed";
	CHECK_EQ(mdb_env_create(&mdb_env), MDB_SUCCESS) << "mdb_env_create failed";// 创建一个lmdb环境句柄,此函数给mdb_env结构分配内存;
	CHECK_EQ(mdb_env_set_mapsize(mdb_env, 1073741824), MDB_SUCCESS) << "mdb_env_set_mapsize failed";// 设置当前环境的内存映射(内存地图)的尺寸。
	CHECK_EQ(mdb_env_open(mdb_env, lmdb_path, 0, 0664), MDB_SUCCESS) << "mdb_env_open failed";//打开环境句柄
	CHECK_EQ(mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn), MDB_SUCCESS) << "mdb_txn_begin failed";//在环境内创建一个用来使用的“处理”transaction句柄
	CHECK_EQ(mdb_open(mdb_txn, NULL, 0, &mdb_dbi), MDB_SUCCESS) << "mdb_open failed. Does the lmdb already exist? ";
	ifstream infile; 
	std::string file = csv_list;//CSV文件名
    infile.open(file.data());   //将文件流对象与文件连接起来 
    assert(infile.is_open());   //若失败,则输出错误消息,并终止程序运行 
    std::string filename ;
	CvMLData mlData;//opencv2
	//Ptr<ml::TrainData> train_data;//opencv3
	const int kMaxKeyLength = 10;
	char key_cstr[kMaxKeyLength];
	std::string value;
	int count = 0;
	while(getline(infile,filename))
	{
		filename = ground_truth_csv +filename;//ground_truth 
		printf("%s\n",filename.data());
		//opencv2
		mlData.read_csv(filename.data());//读取csv文件 opencv2
		cv::Mat map = cv::Mat(mlData.get_values(), true);	
		//opencv3
		//train_data = ml::TrainData::loadFromCSV(filename,0);
		//cv::Mat map_L = train_data->getTrainSamples();
		//cv::Mat map_R = train_data->getTrainResponses();
		//cv::Mat map;
		//hconcat(map_L,map_R,map);
		printf("row = %d,col = %d\n",map.rows,map.cols);
		//map
		caffe::Datum datum;
		datum.set_channels(1); 
		datum.set_encoded(false); 
		datum.set_height(map.rows);
		datum.set_width(map.cols);
		float *ptr = map.ptr<float>();
		for (int i = 0; i < map.cols * map.rows; i++)
			datum.add_float_data(ptr[i]);
		 // serialize
		datum.SerializeToString(&value);
		snprintf(key_cstr, kMaxKeyLength, "%08d", count);
		count++;
		std::string keystr(key_cstr);
		mdb_data.mv_size = value.size();//获取value的字节长度,类似sizeof()函数	
		mdb_data.mv_data = reinterpret_cast<void*>(&value[0]);// 把 value 的首个字符地址转换成空类型的指针
		mdb_key.mv_size = keystr.size();
		mdb_key.mv_data = reinterpret_cast<void*>(&keystr[0]);	
		CHECK_EQ(mdb_put(mdb_txn, mdb_dbi, &mdb_key, &mdb_data, 0), MDB_SUCCESS) << "mdb_put failed";// 通过 mdb_put 函数把 mdb_key 和 mdb_data 所指向的数据, 写入到 mdb_dbi
		CHECK_EQ(mdb_txn_commit(mdb_txn), MDB_SUCCESS) << "mdb_txn_commit failed";//感觉是通过mdb_txn_commit函数把mdb_txn中的数据写入到硬盘
		CHECK_EQ(mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn), MDB_SUCCESS) << "mdb_txn_begin failed";// 重新设置 mdb_txn 的写入位置, 追加(继续)写入
	}
	mdb_close(mdb_env, mdb_dbi);// 关闭 mdb 数据对象变量
	mdb_env_close(mdb_env);// 关闭 mdb 操作环境变量
}
int main(int argc, char *argv[])
{	
	if(argc != 7)
	{
		printf("error usage!\n");
		printf("usage: ./csv2lmdb --lmdb_path <lmdb output path> --csv_list <readPicList generate label.txt> --ground_truth_path <ground_truth_csv path>\n");
		return -1;
	char* lmdb_path = argv[2];
	std::string csv_list = argv[4];
	std::string ground_truth_path = argv[6];	
	printf("lmdb_path :%s,csv_list :%s,ground_truth_path : %s",
	lmdb_path,csv_list,ground_truth_path);
	serialize_label(lmdb_path,csv_list,ground_truth_path);	
	return 0;
}



  • lmdb-训练照片制作
#!/usr/bin/en sh  
DATA1=/home/zzy/test
DATA2=/home/zzy/test/ShanghaiTech_Crowd_Counting_Dataset/part_A_final/train_data/images/
#rm -rf $DATA1/img_train_den_lmdb  
/home/zzy/caffe/build/tools/convert_imageset $DATA2 $DATA1/readPicList/img_train.txt $DATA1/lmdb/images/ 

训练-caffe

net: "./train.prototxt"
display: 500
base_lr:  1e-6
average_loss: 2000
lr_policy: "multistep"
gamma: 0.1
stepvalue: 50000
stepvalue: 200000
max_iter: 2400000
momentum: 0.95
weight_decay: 0.0005
snapshot: 1000
snapshot_prefix: "./result/pretrain"
solver_mode: GPU 
  • train.sh
#!/bin/bash
LOG=log/molo-train-`date +%Y-%m-%d-%H-%M-%S`.log
/home/nis8013/project/yolo/MobileNet-YOLO/build/tools/caffe train --solver yolov3_solver.prototxt --snapshot=result1/head_iter_4000.solverstate --gpu=0 2>&1 | tee $LOG

*测试脚本

clear all; close all;
%lib = 'LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libopencv_core.so.2.4:/usr/lib/x86_64-linux-gnu/libopencv_highgui.so.2.4:/usr/lib/x86_64-linux-gnu/libopencv_imgproc.so.2.4 ';
lib='';
%'LD_LIBRARY_PATH=/your/hdf5/path/hdf5-1.8.14/build/install/lib/:/data1/install/cuda-7.5/lib64/:/usr/local/lib/:/d/install/mdb-mdb/libraries/liblmdb:/d/install/leveldb-1.15.0:/usr/local/opencv-2.4.10/lib/:/d/home/darwinli/tools/cuda-7.5/lib64/:/d/home/darwinli/tools/anaconda/lib:/d/runtime/gcc-4.8.4/lib64:/d/runtime/cudnn-7.5-linux-x64-v5.0/lib64/:/data1/install/cuda-7.5/lib64/:/usr/local/lib/:/d/install/mdb-mdb/libraries/liblmdb:/d/install/leveldb-1.15.0:/usr/local/opencv-2.4.10/lib/:/d/home/darwinli/tools/cuda-7.5/lib64/:/d/home/darwinli/tools/anaconda/lib:/d/runtime/gcc-4.8.4/lib64:/d/runtime/cudnn-7.5-linux-x64-v5.0/lib64/:/d/runtime/nccl-1.2.3-1-cuda7.5/lib ';
caffe_path = '/home/zzy/caffe/build/tools/extract_features';
caffe_model = '/home/zzy/test/result/shanghaiA.caffemodel';
lmdb2txt = '/home/zzy/caffe/build/tools/lmdb2txt';
root_dir = '/home/zzy/test/ShanghaiTech_Crowd_Counting_Dataset/part_A_final/';
image_dir = [root_dir 'test_data/images_resize/'];
image_list = dir([image_dir '*.jpg']); 
gt_dir = [root_dir 'test_data/ground_truth/'];
gt_list = dir([gt_dir '*.mat']);
test_dir = [root_dir 'test_data/test_img/'];
dataPrepare=false;
if exist(test_dir)
    dataPrepare=true;
    %rmdir(test_dir, 's')
end
if exist('estdmap.db')
   rmdir('estdmap.db', 's')
   delete('estdmap.txt')
end
if dataPrepare==false
    mkdir(test_dir);
    fid = fopen([test_dir 'list.txt'], 'w');
else
    fid = fopen([test_dir 'list.txt'], 'r');
end
gpu_id = 0;

nImg = length(image_list);
gtcc = zeros(nImg,1);
for kk = 1:nImg
  test_image = imread([image_dir image_list(kk).name]);
  load([gt_dir gt_list(kk).name]);
  if dataPrepare==false
    test_img = test_image;
     imsize_ori = size(test_img);
     %% deconvolution
     test_img = imresize(test_img, [floor(imsize_ori(1)/8)*8 floor(imsize_ori(2)/8)*8]);
    imwrite(test_img, [test_dir image_list(kk).name]);

    fprintf(fid, '%s\n', [test_dir image_list(kk).name]);
  end
  gtcc(kk) = image_info{1}.num;
end
fclose(fid);
tic;
%disp([lib caffe_path ' ' caffe_model ' deploy.prototxt estdmap estdmap.db ' num2str(nImg) ' lmdb GPU ' num2str(gpu_id)])
system([lib caffe_path ' ' caffe_model ' deploy.prototxt estdmap estdmap.db ' num2str(nImg) ' lmdb GPU ' num2str(gpu_id)]);
ttt = toc;
disp(['time = ' num2str(ttt*1000)])
system([lmdb2txt ' estdmap.db >> estdmap.txt']);
cc = dlmread('estdmap.txt');
cc = sum(cc(:,:),2);%real
ccgtcc = [cc gtcc abs(cc-gtcc)]
MAE = mean(abs(cc-gtcc))
MSE = mean((cc-gtcc).^2)^(0.5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值