分享

步态能量图实现(二)

 木俊 2018-05-11

转载自:https://blog.csdn.net/luoyun614/article/details/42602037

前言

   时隔半年,才写这个步态能量图(二),一方面是这次的实现使用了不同的数据库,另一方面,则是有了编码和思路上的改进。

本次改进

   本次主要有以下三个方面的改进:
   1. 实现的数据库是自动化所是的CASIA datasetB,之前实现的是USF的数据库,前者的数据量要比后者大得多。而且可以涉及到不同的角度,不同的行为(大衣、背包和正常)。
   2. 编码上全部自动化提取文件夹信息,后续应对其他数据库也可以修改该方法去自动读取信息。
   3. 其实这个步态能量图的实现只是铺垫,后续更重要的是分析,看过我前面的文章的都知道我是做视频处理分析的,在实际情况中,人物的轮廓往往不是时时刻刻都是完整的,所以,为了使得训练的数据尽量接近真实的情况,我做了大胆的处理,就是不在检测周期,就是说不再除以周期,而是直接除以总的步态数,因为在实际场景中,当步态数量足够大的时候,可以等同于单个正常的步态能量图,从而减少因为遮挡、缺失等问题导致的图像偏差。

具体实现

1. 实现自动文件提取,主要是在main函数中处理。
// Create_GEI.cpp : 定义控制台应用程序的入口点。
//
//用于自动生成CASIA DatasetB的GEI的图
//作者:罗韵
//时间:2015.01.08

#include "stdafx.h"

#include "string.h"
#include <io.h>
#include <stdio.h>
#include <iostream>

#include <opencv2\opencv.hpp>
#include <cv.h>

#include "GenerateGEI.h"

using namespace std;
using namespace cv;


//@argv[1]:文件夹列表地址
int _tmain(int argc, char* argv[])
{
char* rootpath=new char[100];
rootpath="G:\\CASIAdatasetB\\silhouettes\\"; //G:\\CASIA_datasetB\\silhouettes\\   或者argv[1]输入也可以
cout<<rootpath<<endl;
char* folder=new char[100]; //二级文件夹
char* filepath=new char[100]; //图片文件路径
char* folderpath=new char[100]; //图片所在文件夹路径
char* filename=new char[100]; //图片名称
for(int i=1;i<=124;i++) //以及目录有124个文件夹
{
sprintf(folder,"%s\%03d",rootpath,i);
cout<<folder<<endl;
for(int j=1;j<=6;j++)
{
for(int k=0;k<=180;k+=18)
{
const char* p="*.*";
sprintf(filepath,"%s\\nm-%02d\\%03d\\%s",folder,j,k,p);
cout<<filepath<<endl;
long lf;
_finddata_t file;
//遍历该文件夹内所有文件
if((lf = _findfirst(filepath, &file))==-1l) //_findfirst返回的是long型; long __cdecl _findfirst(const char *, struct _finddata_t *)
{
cout<<"文件没有找到!\n";
system("pause");
}
else
{
sprintf(folderpath,"%s\\nm-%02d\\%03d\\",folder,j,k);
GenerateGEI* generate=new GenerateGEI(folderpath); //传入当前文件夹路径,方便作为生成的GEI文件名
cout<<"\n文件列表:\n";
while( _findnext( lf, &file ) == 0 )//int __cdecl _findnext(long, struct _finddata_t *);如果找到下个文件的名字成功的话就返回0,否则返回-1 
{
cout<<file.name<<endl;
string str(file.name);
int te = str.find(".png"); //指定文件类型
if(te != -1){
sprintf(filename,"%s\%s",folderpath,file.name); //图片
cout<<filename<<endl;
//读入并处理图片
#ifdef _DEBUG
IplImage* ipl=cvLoadImage(filename);
cvNamedWindow("ipl",CV_WINDOW_AUTOSIZE);
cvShowImage("ipl",ipl);
cvWaitKey(-1);
#endif
Mat image=cv::imread(filename,0); //按单通道读入
#ifdef _DEBUG
cv::imshow("image",image);
cv::waitKey(-1);
#endif
if(!image.data)
{
cout<<"no image data"<<endl;
system("pause");
}
generate->InsertImage(image);
}
}
#ifdef _DEBUG
system("pause");
#endif
delete generate;
}
}

}
}
return 0;


}
2. 处理生成步态能量图的类
头文件:
#pragma once

#include <iostream>

#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui.hpp>

#include <vector>

using namespace cv;
using namespace std;

typedef std::vector<Point> Contours;

class GenerateGEI
{
public:
int num; //当前计数
explicit GenerateGEI(const char* folderpath);
~GenerateGEI(void);
int InsertImage(Mat image);
int Process(Mat image);
Mat FindContours(Mat image);
Mat Resize(Mat image);
Mat CalGei(Mat image);
private:
char* gei_name;
Mat gei; //当前gei图

};
源文件:
#include "StdAfx.h"
#include "GenerateGEI.h"

#define H 500
#define W 400
#define BASE_RATIO 1.25 


GenerateGEI::GenerateGEI(const char* folderpath)
{
gei_name=new char[100];
sprintf(gei_name,"%s\gei_.jpg",folderpath); //产生的GEI储存位置
num=0;
}


GenerateGEI::~GenerateGEI(void)
{
delete gei_name;
}

int GenerateGEI::InsertImage(Mat image)
{
num++;
Process(image);
return 1;
}

int GenerateGEI::Process(Mat image)
{
Mat origin=FindContours(image);
Mat normal=Resize(origin);
Mat show_gei=CalGei(normal);
imwrite(gei_name,show_gei);
return 1;
}

Mat GenerateGEI::FindContours(Mat image)
{
Mat image_tmp=image.clone(); //用于findContours,因为该函数使用后会导致原图改变,所以要复制一个用于该函数
#ifdef _DEBUG
cv::imshow("image",image);
cv::waitKey(-1);
#endif
std::vector<Contours> contours; //每个轮廓的所有角点理论上只需要contours[0]
cv::findContours(image_tmp,contours,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE); //findContours只能处理8UC1和32SC1
cv::Rect r0 = cv::boundingRect(cv::Mat(contours[0]));
cv::Mat gait_img_roi = image(r0);
return gait_img_roi;
}

Mat GenerateGEI::Resize(Mat image)
{
float ra = image.rows/image.cols;
cv::Mat gait_roi_tmp;
Mat gait_img2 = Mat::zeros(H,W,CV_8UC1);
//if(ra>=base_ratio)
{
double resize_scale = (double)H/image.rows;
cv::resize(image,gait_roi_tmp,cv::Size(),resize_scale,resize_scale); //按比例缩放
for(int i =0;i<gait_roi_tmp.rows;i++)
{
uchar* p_tmp = gait_roi_tmp.ptr<uchar>(i);
uchar* p = gait_img2.ptr<uchar>(i);
for(int j=(W-gait_roi_tmp.cols)/2,k=0;k<gait_roi_tmp.cols;k++,j++)
{
p[j] = p_tmp[k];
}
}
}
//else
//{
// double resize_scale = (double)W/image.cols;
// cv::resize(image,gait_roi_tmp,cv::Size(),resize_scale,resize_scale); //按比例缩放
// int i =(H-gait_roi_tmp.rows)/2;
// for(int k = 0;k<gait_roi_tmp.rows;k++,i++)
// {
// uchar* p_tmp = gait_roi_tmp.ptr<uchar>(k);
// uchar* p = gait_img2.ptr<uchar>(i);
// for(int j=0;j<gait_roi_tmp.cols;j++)
// {
// p[j]=p_tmp[j];
// }
// }
//}
return gait_img2;
}

Mat GenerateGEI::CalGei(Mat image)
{
if(num==1)
{
gei=image.clone();
}
else
{
//新的图像与原来的gei形成新的gei
for(int i=0;i<image.rows;i++)
{
uchar* p_old_gei=gei.ptr<uchar>(i);
uchar* p=image.ptr<uchar>(i);
for(int j=0;j<image.cols;j++)
{
p_old_gei[j]=(p_old_gei[j]*(num-1)+p[j])/num;
}
}
}
return gei;
}

结果

    结果是怎么样的图估计大家都知道,就不在这里啰嗦了,如果你不知道,那估计这篇文章对你也没什么用。

    最费劲的是,足足跑了好几个小时,中途要注意findContours这个函数只能结构单通道的输入,要想直接获得单通道的图形矩阵,Mat(src,0)中的第二个参数就是控制图形矩阵通道数目的。

    最后还有个很误导人的发现,就是使用imread函数时,然后想用imshow看是否读取成功,一旦设置了断点在imshow后面,那一般情况是看不到图像的,重点是src.data也是显示为0,这时候,不要以为你没有读取成功,我就是以为没有读取成功,然后还以为配置有问题(但我用了OpenCV都一段时间了,虽然平时大多使用视频直接获得图像,但也不至于配置有问题吧~),最后只要在imshow后面设置一个waitkey(0),就可以看到图像了,即使不用waitkey继续运行程序也是没有问题的,图像数据是会有的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多