画像に対して顔検出を行いマスクする(opencv/opencv4nodejs/Node.js)
動機
インカメラで人物や顔写真入り証明書を撮影したエビデンス画像に対して、顔部分のマスクを行うツールを作成したかった。
言語選定
画像処理ライブラリ opencv の対応言語は C/C++
Java
Python
です。
今回の動機であるツール的に用いるならば、Pythonが適していると思います。サンプルコードもたくさんあります。しかし、自分がPythonに対する知識が少なく、時間がかかりそうで逡巡していました。
しかし、opencv を Node.js 環境から使えるライブラリopencv4nodejsを見つけたので、試してみることにしました。
落とし穴
opencv4nodejsはopencvの型やメソッドと全く同じ名称ではなく、JavaScriptの言語仕様に合わせて引数なども異なります。→ Contribution Guide
従って、Pythonのコードをそのまま置き換えればOK!といった形では実装できません。
自分はここを安易に考えていて若干ハマりました…
環境構築
Windows10(64bit)
Nodist(0.9.1) Node.js 11.13.0 上に
opencv4nodejs(5.5.0)をインストール
公式の手順はこちら
事前注意
- スペースを含むパスにインストールしない → node-gyp でパスが読めない
- 日本語を含むパスにインストールしない → opencvでパスが読めない
cmakeインストール
opencv4nodejs のインストール時に要求され、これが無いとエラーで進みません。
- cmake をインストールする
- 実行ファイルがあるフォルダにPATHを通す 例:
G:\Program Files\CMake\bin
git
git ロングファイルネーム許可の設定(opencv4nodejs 内でのC++コンパイル用)
git config --system core.longpaths true
npm
node-gypのインストール
npm install --global node-gyp
windows-build-tools インストール
npm install --global windows-build-tools
※時間かかりますopencv4nodejs のインストール
npm install opencv4nodejs
※とても時間かかります
実装
TypeScriptで書いてます
顔検出
サンプルソースをそのまま使いました。opencv4nodejsではサンプルソースが充実していてます。
import * as cv from 'opencv4nodejs';
export const feceMaskBlur = (imagePath:string) => {
// 対象画像読込
const image = cv.imread(imagePath);
if (!image) {
throw new Error(`No file ${imagePath}`);
}
const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);
// detect faces
const { objects, numDetections } = classifier.detectMultiScale(image.bgrToGray());
if (!objects.length) {
throw new Error(`No faces detected! ${imagePath}`);
}
console.log('顔検出した領域:', objects);
console.log('確度:', numDetections);
// draw detection
let blurImage:cv.Mat;
blurImage = image.copy();
objects.forEach((rect, i) => {
// 顔検出した部分に対してマスクを実施
blurImage = drawBlurRect(blurImage, rect, numDetections[i]);
});
// file 保存
cv.imwrite(imagePath, blurImage);
}
検出した領域は、以下のような座標と大きさで取得できます
顔検出した領域: [ Rect { height: 525, width: 525, y: 1188, x: 1923 },
Rect { height: 262, width: 262, y: 3214, x: 2298 },
Rect { height: 584, width: 584, y: 878, x: 2714 } ]
確度: [ 8, 4, 11 ]
画像の一部上書き
上記で取得した領域に対して、マスクをかけます。
python だと、画像のデータは二次元配列として読み込まれるため、座標位置を指定して代入する形で記述できるようなのですが、opencv4nodejsだと形式が異なったため、ちょっと悩みました。
def mosaic_area(src, x, y, width, height, ratio=0.1):
dst = src.copy()
dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width], ratio)
return dst
dst_area = mosaic_area(src, 100, 50, 100, 150)
cv2.imwrite('data/dst/opencv_mosaic_area.jpg', dst_area)
Python, OpenCVで画像にモザイク処理(全面、一部、顔など)より引用
issueを検索して見つけました。
// 対象のRectを塗りつぶし
const drawBlurRect = (image: cv.Mat, rect: cv.Rect, numDetection: number):cv.Mat => {
// 領域の切り出し
const srcRoi:cv.Mat = image.getRegion(rect);
// 切り出した部分にマスクをかける
const masked = cv.blur(srcRoi, new cv.Size(rect.width,rect.height));
// 切り出した部分を元画像に合成
masked.copyTo(image.getRegion(rect));
return image;
}
実行
こうなります
画像取得元
まとめと気づき
画像から何かを識別する場合には識別器を用い、OpenCVにはこの識別に使う学習済みファイルが準備されています。
今回は、Haar Cascade識別器(分類器)のhaarcascade_frontalface_alt2.xml → コード中では cv.HAAR_FRONTALFACE_ALT2
を使いました(サンプルそのまま)。
今回はインカメラを使った正面を向いた写真が基本なので顔検出がマッチしたのですが、横向きの顔は検出されにくい点については把握しておいた方がよさそうです。
参考
Author And Source
この問題について(画像に対して顔検出を行いマスクする(opencv/opencv4nodejs/Node.js)), 我々は、より多くの情報をここで見つけました https://qiita.com/endk/items/820db1ddd43c3433cef9著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .