天天看点

步态能量图实现(二)前言本次改进具体实现结果

前言

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

本次改进

   本次主要有以下三个方面的改进:    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继续运行程序也是没有问题的,图像数据是会有的。

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

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

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