步态能量图实现(二)

来源:互联网 发布:js array add 编辑:程序博客网 时间:2024/05/22 00:09

前言

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

本次改进

   本次主要有以下三个方面的改进:
   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 _DEBUGIplImage* ipl=cvLoadImage(filename);cvNamedWindow("ipl",CV_WINDOW_AUTOSIZE);cvShowImage("ipl",ipl);cvWaitKey(-1);#endifMat image=cv::imread(filename,0); //按单通道读入#ifdef _DEBUGcv::imshow("image",image);cv::waitKey(-1);#endifif(!image.data){cout<<"no image data"<<endl;system("pause");}generate->InsertImage(image);}}#ifdef _DEBUGsystem("pause");#endifdelete 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 _DEBUGcv::imshow("image",image);cv::waitKey(-1);#endifstd::vector<Contours> contours; //每个轮廓的所有角点理论上只需要contours[0]cv::findContours(image_tmp,contours,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE); //findContours只能处理8UC1和32SC1cv::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形成新的geifor(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继续运行程序也是没有问题的,图像数据是会有的。


转载请注明出处:http://blog.csdn.net/luoyun614/article/details/42602037

----------------------------------------------------------------------------------------------------------

P.S 组织了一个计算机视觉的开发者交流微信群,目标是汇集计算机视觉和图像处理的开发者分享开发经验,共同探讨技术,有兴趣入群的可以加我微信(WeChat: LaurenLuoYun),请注明“姓名-公司/学校-技术方向”,谢谢。



0 0
原创粉丝点击