人脸检测中,如何构建输入图像金字塔
目录
- 写在前面
- 人脸检测中的图像金字塔
- 代码实现
- MTCNN
- Seetaface
- 总结
- 参考
博客:blog.shinelee.me | 博客园 | CSDN
写在前面
在文章《特征,特征不变性,尺度空间与图像金字塔》中我们初步谈到了图像金字塔,在这篇文章中将介绍如何在人脸检测任务中构建输入图像金子塔。
人脸检测中的图像金字塔
人脸检测任务,输入是一张图像,输出图像中人脸所在位置的Bounding Box。因为卷积神经网络强大的特征表达能力,现在的人脸检测方法通常都基于卷积神经网络,如MTCNN等。网络确定后,通常只适用于检测一定尺寸范围内的人脸,比如MTCNN中的P-Net,用于判断12 × 12大小范围内是否含有人脸,但是输入图像中人脸的尺寸是未知的,因此需要构建图像金字塔,以获得不同尺寸的图像,只要某个人脸被放缩到12×12左右,就可以被检测出来。下图为MTCNN 的Pipeline,来自链接。
构建金字塔需要解决几个问题:
- 金字塔要建多少层,即一共要生成多少张图像
- 每张图像的尺寸如何确定
下面直接从代码层面看是如何实现的,也可以直接跳到总结查看结论。
代码实现
MTCNN
以下为MTCNN 人脸检测 matlab代码
现在就可以回答上面的两个问题了:
- 给定输入图像,根据设置的最小人脸尺寸以及网络能检测的人脸尺寸,确定图像金子塔中最大图像和最小图像
- 根据设置的金字塔层间缩放比率,确定每层图像的尺寸
Seetaface
可以再看一下Seetaface中是如何构建图像金字塔的,Seetaface人脸检测使用的是非深度学习的方法,检测窗口大小impl_->kWndSize = 40
,其对应MTCNN中网络适宜检测的人脸大小。
// 设置最大人脸,计算最大
void FaceDetection::SetMinFaceSize(int32_t size) {
if (size >= 20) {
impl_->min_face_size_ = size;
impl_->img_pyramid_.SetMaxScale(impl_->kWndSize / static_cast<float>(size));
}
}
// 设置最大尺度
inline void SetMaxScale(float max_scale) {
max_scale_ = max_scale;
scale_factor_ = max_scale;
UpdateBufScaled();
}
// 设置最小人脸
void FaceDetection::SetMaxFaceSize(int32_t size) {
if (size >= 0)
impl_->max_face_size_ = size;
}
// 设置相邻层放缩比率
void FaceDetection::SetImagePyramidScaleFactor(float factor) {
if (factor >= 0.01f && factor <= 0.99f)
impl_->img_pyramid_.SetScaleStep(static_cast<float>(factor));
}
// 在金字塔中检测人脸
std::vector<seeta::FaceInfo> FaceDetection::Detect(
const seeta::ImageData & img) {
int32_t min_img_size = img.height <= img.width ? img.height : img.width;
min_img_size = (impl_->max_face_size_ > 0 ? (min_img_size >= impl_->max_face_size_ ?
impl_->max_face_size_ : min_img_size) : min_img_size);
// ...
// 最小尺度为 impl_->kWndSize / min_img_size,在Seetaface中impl_->kWndSize=40
impl_->img_pyramid_.SetMinScale(static_cast<float>(impl_->kWndSize) / min_img_size);
// ...
impl_->pos_wnds_ = impl_->detector_->Detect(&(impl_->img_pyramid_));
// ...
}
// 金子塔中对应尺度的图像
const seeta::ImageData* ImagePyramid::GetNextScaleImage(float* scale_factor) {
// initial scale_factor_ = max_scale = impl_->kWndSize / min_face_size
if (scale_factor_ >= min_scale_) { // min_scale_ = impl_->kWndSize / min_img_size
if (scale_factor != nullptr)
*scale_factor = scale_factor_;
width_scaled_ = static_cast<int32_t>(width1x_ * scale_factor_);
height_scaled_ = static_cast<int32_t>(height1x_ * scale_factor_);
seeta::ImageData src_img(width1x_, height1x_);
seeta::ImageData dest_img(width_scaled_, height_scaled_);
src_img.data = buf_img_;
dest_img.data = buf_img_scaled_;
seeta::fd::ResizeImage(src_img, &dest_img);
scale_factor_ *= scale_step_;
img_scaled_.data = buf_img_scaled_;
img_scaled_.width = width_scaled_;
img_scaled_.height = height_scaled_;
return &img_scaled_;
} else {
return nullptr;
}
}
看代码就很清晰了,与MTCNN是相通的。
总结
人脸检测中的图像金字塔构建,涉及如下数据:
-
输入图像尺寸,定义为
(h, w)
-
最小人脸尺寸,定义为
min_face_size
-
最大人脸尺寸,如果不设置,为图像高宽中较短的那个,定义为
max_face_size
-
网络/方法能检测的人脸尺寸,定义为
net_face_size
-
金字塔层间缩放比率,定义为
factor
缩放图像是为了将图像中的人脸缩放到网络能检测的适宜尺寸,图像金字塔中
最大尺度max_scale = net_face_size / min_face_size
,
最小尺度min_scale = net_face_size / max_face_size
,
中间的尺度scale_n = max_scale * (factor ^ n)
,
对应的图像尺寸为(h_n, w_n) = (h * scale_n, w_n * scale_n)
。
以上。
参考
- C#检测SqlServer中某张表是否存在
- Cobbler自动化批量安装linux服务器的操作记录
- Twemproxy——针对MemCached与Redis的代理
- 谁适合学Python?学了Python可以做什么工作?
- webservice今日遇到的二个问题:DataTable + Namespace
- php安全配置记录和常见错误梳理
- Flex:地图缩放平移效果(简易版)
- Mongodb副本集+分片集群环境部署记录
- 线上mongodb 数据库用户到期时间修改的操作记录
- 微信小程序“授权失败”场景的处理
- 动软.net代码生成器 win2008 r2下无法连接oracle,以及vs2008模板丢失的解决
- ASP.NET Web API 支持 CORS
- oracle odp.net 32位/64位版本的问题
- Redis+TwemProxy(nutcracker)集群方案部署记录
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python之Bilibili自动更新邮件提醒并任务栏图标「完整代码」
- STC15频率产生器(粗调+微调+数码管显示)完整代码
- PID算法原理、调整规律及代码
- GIT——分布式版本控制系统
- 如何在 PHP 中使用和管理 Cookie
- 玩转 PhpStorm 系列(九):代码调试篇(上)
- 在 PHP 中使用和管理 Session
- STC51单片机中断与定时器配置参考
- 玩转 PhpStorm 系列(十):代码调试篇(下)
- STM32字符串转整数
- Java常用设计模式--代理模式(Proxy Pattern)
- 详解爬取搜狐号自媒体的所有文章
- 笑了,面试官问我知不知道异步编程的Future。
- ES6之let和const命令
- [Python] 豆瓣自动回帖、顶帖源码