人臉檢測中,如何構建輸入圖像金字塔


博客:blog.shinelee.me | 博客園 | CSDN

寫在前面

在文章《特征,特征不變性,尺度空間與圖像金字塔》中我們初步談到了圖像金字塔,在這篇文章中將介紹如何在人臉檢測任務中構建輸入圖像金子塔。

人臉檢測中的圖像金字塔

人臉檢測任務,輸入是一張圖像,輸出圖像中人臉所在位置的Bounding Box。因為卷積神經網絡強大的特征表達能力,現在的人臉檢測方法通常都基於卷積神經網絡,如MTCNN等。網絡確定后,通常只適用於檢測一定尺寸范圍內的人臉,比如MTCNN中的P-Net,用於判斷\(12 \times 12\)大小范圍內是否含有人臉,但是輸入圖像中人臉的尺寸是未知的,因此需要構建圖像金字塔,以獲得不同尺寸的圖像,只要某個人臉被放縮到\(12\times12\)左右,就可以被檢測出來。下圖為MTCNN 的Pipeline,來自鏈接

MTCNN Pipeline

構建金字塔需要解決幾個問題:

  1. 金字塔要建多少層,即一共要生成多少張圖像
  2. 每張圖像的尺寸如何確定

下面直接從代碼層面看是如何實現的,也可以直接跳到總結查看結論。

代碼實現

MTCNN

以下為MTCNN 人臉檢測 matlab代碼
MTCNN detect face code

在人臉檢測,通常要設置要原圖中要檢測的最小人臉尺寸,原圖中小於這個尺寸的人臉不必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\)(在保證縮放比率一致的情況下近似)。

現在就可以回答上面的兩個問題了:

  1. 給定輸入圖像,根據設置的最小人臉尺寸以及網絡能檢測的人臉尺寸,確定圖像金子塔中最大圖像和最小圖像
  2. 根據設置的金字塔層間縮放比率,確定每層圖像的尺寸

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是相通的。

總結

人臉檢測中的圖像金字塔構建,涉及如下數據:

  1. 輸入圖像尺寸,定義為(h, w)
  2. 最小人臉尺寸,定義為 min_face_size
  3. 最大人臉尺寸,如果不設置,為圖像高寬中較短的那個,定義為max_face_size
  4. 網絡/方法能檢測的人臉尺寸,定義為net_face_size
  5. 金字塔層間縮放比率,定義為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)

以上。

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM