人臉檢測中,如何構建輸入影象金字塔
目錄
部落格: ofollow,noindex" target="_blank">blog.shinelee.me |部落格園 | CSDN
寫在前面
在文章《特徵,特徵不變性,尺度空間與影象金字塔》中我們初步談到了影象金字塔,在這篇文章中將介紹如何在人臉檢測任務中構建輸入影象金子塔。
人臉檢測中的影象金字塔
人臉檢測任務,輸入是一張影象,輸出影象中人臉所在位置的Bounding Box。因為卷積神經網路強大的特徵表達能力,現在的人臉檢測方法通常都基於卷積神經網路,如 MTCNN 等。網路確定後,通常只適用於檢測一定尺寸範圍內的人臉,比如MTCNN中的P-Net,用於判斷 \(12 \times 12\) 大小範圍內是否含有人臉,但是輸入影象中人臉的尺寸是未知的,因此需要構建影象金字塔,以獲得不同尺寸的影象,只要某個人臉被放縮到 \(12\times12\) 左右,就可以被檢測出來。下圖為MTCNN 的Pipeline,來自 連結 。
構建金字塔需要解決幾個問題:
- 金字塔要建多少層,即一共要生成多少張影象
- 每張影象的尺寸如何確定
下面直接從程式碼層面看是如何實現的,也可以直接跳到總結檢視結論。
程式碼實現
MTCNN
以下為MTCNN 人臉檢測 matlab程式碼

在人臉檢測,通常要設定要原圖中要檢測的 最小人臉尺寸 ,原圖中小於這個尺寸的人臉不必care,MTCNN程式碼中為 minsize=20
,MTCNN P-Net用於檢測 \(12\times12\) 大小的人臉。如果輸入影象為 \(100 \times 120\) ,其中人臉最小為 \(20 \times 20\) ,最大為 \(100 \times 100\) ——對應影象較短邊長,為了將人臉放縮到 \(12 \times 12\) ,同時保證相鄰層間縮放比率 factor=0.709
,則金子塔中影象尺寸依次為 \(60 \times 72\) 、 \(52 \times 61\) 、 \(36 \times 43\) 、 \(26 \times 31\) 、 \(18 \times 22\) 、 \(13 \times 16\) ,其中 \(60 \times 72\) 對應把 \(20\times 20\) 的人臉縮放到 \(12 \times 12\) , \(13 \times 16\) 對應把 \(100 \times 100\) 的人臉縮放到 \(12 \times 12\) (在保證縮放比率一致的情況下近似)。
現在就可以回答上面的兩個問題了:
- 給定輸入影象,根據設定的最小人臉尺寸以及網路能檢測的人臉尺寸,確定影象金子塔中最大影象和最小影象
- 根據設定的金字塔層間縮放比率,確定每層影象的尺寸
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)
。
以上。