(转载请注明出处)
使用SDK: Kinect for Windows SDK v2.0 public preview1409
同前面,因为SDK未完成,不附上函数/方法/接口的超链接。
这次让我们让面部捕捉更加稳定/精确吧!
自从一直8月有了高清面部帧的例子后,觉得IFaceModel::GetFaceShapeDeformations它不干正事,一直返回0.0f的数据。
与其他开发者简单交流后,发现了问题的根本所在,需要面部模型构建器(IFaceModelBuilder)。
好了,那么这是开始。还记得上节的CreateFaceModel函数没有?这个函数需要传递一个数组,称为
FaceShapeDeformations数组,在这里简单翻译为面形吧。这个储存了面部的特征点的模拟数据,可能的数据
比如说鼻子的高度模拟值,详细的还需官方SDK更新,现在啥也没有。
那么,如果已经储存了面形信息,CreateFaceModel时直接导入即可。没有就需要捕捉并构建了。
于是使用IFaceModelBuilder吧!
IHighDefinitionFaceFrameSource::OpenModelBuilder打开面部模型构建器
参数1: 构建属性:
enum _FaceModelBuilderAttributes
{
FaceModelBuilderAttributes_None = 0,
FaceModelBuilderAttributes_SkinColor = 0x1,
FaceModelBuilderAttributes_HairColor = 0x2
} ;
比较简单,需要肤色那就0x1,需要发色就0x2,都需要就做按位或运算。我们这里仅需面形数据信息,就
FaceModelBuilderAttributes_None即可.
对了,我们这次需要支持简单的数据导入,所以可能会这样:
<span style="font-size:14px;"> // 创建高清面部帧源
if (SUCCEEDED(hr)){
hr = CreateHighDefinitionFaceFrameSource(m_pKinect, &m_pHDFaceFrameSource);
}
// 创建面部模型构建器 之前常试从文件中读取数据
if (SUCCEEDED(hr) && !read_fsdfile_data()){
hr = m_pHDFaceFrameSource->OpenModelBuilder(FaceModelBuilderAttributes_None, &m_pFaceModelBuilder);
}
// 开始数据收集
if (SUCCEEDED(hr) && m_pFaceModelBuilder){
hr = m_pFaceModelBuilder->BeginFaceDataCollection();
}</span>
IFaceModelBuilder::BeginFaceDataCollection
开始数据搜集
也是简单易懂, read_fsdfile_data()方法常试读取数据。
我是这样实现的,果然IO还是纯C好点
<span style="font-size:14px;">// 常试FSD读取文件
bool ThisApp::read_fsdfile_data(){
FILE* file = nullptr;;
size_t ok = reinterpret_cast<size_t>(m_pFSDFileName);
// 打开文件
if (ok){
file = _wfopen(m_pFSDFileName, L"rb");
size_t ok = reinterpret_cast<size_t>(file);
}
// 读取信息
if (ok){
auto length = fread(m_ImagaRenderer.data.sd, 1, lengthof(m_ImagaRenderer.data.sd), file);
ok = length == lengthof(m_ImagaRenderer.data.sd);
}
// 设置已获取
if (ok){
m_bProduced = TRUE;
m_ImagaRenderer.data.co_status = FaceModelBuilderCollectionStatus_Complete;
}
// 关闭文件
if (file){
fclose(file);
#ifdef _DEBUG
file = nullptr;
#endif
}
return ok != 0;
}</span>
IFaceModelBuilder::get_CollectionStatus
获取搜集状态,搜集状态有
<span style="font-size:14px;">enum _FaceModelBuilderCollectionStatus
{
FaceModelBuilderCollectionStatus_Complete = 0,
FaceModelBuilderCollectionStatus_MoreFramesNeeded = 0x1,
FaceModelBuilderCollectionStatus_FrontViewFramesNeeded = 0x2,
FaceModelBuilderCollectionStatus_LeftViewsNeeded = 0x4,
FaceModelBuilderCollectionStatus_RightViewsNeeded = 0x8,
FaceModelBuilderCollectionStatus_TiltedUpViewsNeeded = 0x10
} ;</span>
FaceModelBuilderCollectionStatus_Complete
面部信息搜集完毕,状态就是这个
FaceModelBuilderCollectionStatus_MoreFramesNeeded
还需要其他位置信息,接下来4个状态存在任意一个状态,该状态置为1
FaceModelBuilderCollectionStatus_FrontViewFramesNeeded
需要正面帧数据,面部朝着Kinect即可
FaceModelBuilderCollectionStatus_LeftViewsNeeded
需要面向左边(几乎90度)
FaceModelBuilderCollectionStatus_RightViewsNeeded
需要面形右边(几乎90度)
FaceModelBuilderCollectionStatus_TiltedUpViewsNeeded
需要斜向上(目测需要45度),但是笔者的Kinect置于高处,这个需要90度抬头,简直
还需要值得提到的是,有耳机最好摘掉,会提高收集成功的概率
错别字就不要在意了,代码已经上传了,改也没有意义了.
IFaceModelBuilder::get_CaptureStatus
获取采集状态,就是提示用户的姿势是怎样不对的,基本不动就没事
enum _FaceModelBuilderCaptureStatus
{
FaceModelBuilderCaptureStatus_GoodFrameCapture = 0,
FaceModelBuilderCaptureStatus_OtherViewsNeeded = 1,
FaceModelBuilderCaptureStatus_LostFaceTrack = 2,
FaceModelBuilderCaptureStatus_FaceTooFar = 3,
FaceModelBuilderCaptureStatus_FaceTooNear = 4,
FaceModelBuilderCaptureStatus_MovingTooFast = 5,
FaceModelBuilderCaptureStatus_SystemError = 6
} ;
这个不多说
采集成功后,使用IFaceModelBuilder::GetFaceData可以获取IFaceModelData,
居然不是小写的,微软在想什么╮( ̄▽ ̄)╭
获取之后IFaceModelData::ProduceFaceModel来生成面部模型,记得释放之前的模型哟
代码差不多就是这样,请注意,我试验后发现构建IFaceModelData::ProduceFaceModel模型需要几秒钟,
简直影响用户体验,所以建议保留数据,下次
// 检查面部模型构建器
if (SUCCEEDED(hr) && !m_bProduced){
IFaceModelData* pFaceModelData = nullptr;
// 检查收集状态
hr = m_pFaceModelBuilder->get_CollectionStatus(&m_ImagaRenderer.data.co_status);
// 检查采集状态
if (SUCCEEDED(hr)){
hr = m_pFaceModelBuilder->get_CaptureStatus(&m_ImagaRenderer.data.ca_status);
}
// 采集成功 获取数据
if (SUCCEEDED(hr) && m_ImagaRenderer.data.co_status == FaceModelBuilderCollectionStatus_Complete){
hr = m_pFaceModelBuilder->GetFaceData(&pFaceModelData);
}
// 生成面部模型
if (SUCCEEDED(hr) && pFaceModelData){
SafeRelease(m_pFaceModel);
hr = pFaceModelData->ProduceFaceModel(&m_pFaceModel);
}
// 检查结果
if (SUCCEEDED(hr) && pFaceModelData){
m_bProduced = TRUE;
// 顺便输出数据
m_pFaceModel->GetFaceShapeDeformations(lengthof(m_ImagaRenderer.data.sd), m_ImagaRenderer.data.sd);
}
// 释放掉
SafeRelease(pFaceModelData);
}
差不多就这样:
下面再说说采集的信息:
笔者的方法自然简单:
case WM_KEYDOWN:
if (wParam == 'S'){
FILE* file = nullptr;
BYTE buffer[FaceShapeDeformations_Count * 64];
size_t now_length = 0;
if (!_wfopen_s(&file, L"FaceShapeDeformations.txt", L"wb")){
memcpy(buffer, pOurApp->m_ImagaRenderer.data.sd, sizeof(pOurApp->m_ImagaRenderer.data.sd));
char* index = reinterpret_cast<char*>(buffer+sizeof(pOurApp->m_ImagaRenderer.data.sd));
*index = '\r'; ++index; *index = '\n'; ++index;
float* data_index = pOurApp->m_ImagaRenderer.data.sd;
for (int i = 0; i < FaceShapeDeformations_Count; ++i){
now_length = sprintf(index, "%f\r\n", *data_index);
index += now_length;
++data_index;
}
fwrite(buffer, 1, reinterpret_cast<BYTE*>(index)-buffer, file);
}
if (file){
fclose(file);
file = nullptr;
::SendMessageW(hwnd, WM_CLOSE, 0, 0);
}
else{
::MessageBoxW(hwnd, L"储存失败", L"Error", MB_ICONERROR);
}
}
break;但是简单两次采样的数据大致如下:
可以看出数据波动较大,解决办法只有多次采样抵消了。算法不少,最简单的平均法。
也可以假定服从N(μ, σ^2)的正态分布,利用《概概率论与数理统计》中的方法计算,不多说了(其实是不会)。
调试可以传递一个参数,表示文件的路径:
正式使用更简单了,直接把输出文件拖到exe文件上即可。
范例下载地址:点击这里
这次我学精了,提前上传,不过错别字
Kinect for Windows SDK v2.0 开发笔记 (十三) 高清面部帧(4) 面部模型构建器
原文:http://blog.csdn.net/dustpg/article/details/39580837