LoginSignup
4
4

More than 3 years have passed since last update.

アンジェの画像を集めて顔検出する。

Last updated at Posted at 2020-02-15

Vtuberも、にじさんじも知らないという人はココにたどり着かないと思いますが、
「さんばか」を識別できるような機械学習をしてみたく、まずはアンジェの画像ダウンロード、顔検出してみました。いろいろ参考サイトはあるんですが、以下のサイトをベースにしています。

プログラム:pytyon3.7
環境:ubuntu18.04
使用ライブラリ:BeautifulSoup(スクレイピング)、opencv(顔検出)、urllib(画像ダウンロード)

コードのメイン処理は以下。

if __name__ == '__main__':

    downloads = ImageDownloader('アンジェ・カトリーナ').go()
    for i, d in enumerate(downloads):
        FaceDetector(d).cutout_faces('image/faces/faces_{}.jpg'.format(i + 1))

ダウンローダでDLして、そのリストを顔検出する、これだけです。

ダウンローダは以下。

class ImageDownloader(object):
    def __init__(self, keyword):
        session = requests.session()
        session.headers.update(
            {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) \
             Gecko/20100101 Firefox/10.0'})
        params = urllib.parse.urlencode(
            {'q': keyword, 'tbm': 'isch', 'ijn': '1'})
        query = "https://www.google.co.jp/search" + '?' + params
        self._bs = BeautifulSoup(session.get(query).text, 'html.parser')

    def go(self):
        downloads = []
        for img in self._bs.find_all('img'):
            try:
                url = img['data-iurl']
                downloads.append('image/image_{}.jpg'.format(len(downloads) + 1))
                urllib.request.urlretrieve(url, downloads[-1])
            except KeyError:
                print('failed to get url : {}'.format(img))
        return downloads

■コンストラクタ
 Googleさんにクエリーを発行して(キーワード:アンジェ)、検索結果ページ(今回は1ページ目のみ)をスクレイピングライブラリ(BeautifulSoup)にかけています。

■goメソッド
 imgタグを全検索し、その属性['data-iurl']にリンクが格納されてるので、urllibモジュールでダウンロードします。中には['data-iurl']属性を持たない、おそらく検索画像以外のタグが見つかるので、それはKeyError例外を捕らえてスルーしてます。

顔切り出し器は以下。

class FaceDetector(object):

    # 学習済モデル
    FACE_CASCADE = '/home/websoler/anaconda3/lib/python3.7/site-packages/cv2/data/lbpcascade_animeface.xml'

    def __init__(self, fname):
        self._img = cv2.imread(fname)

    def cutout_faces(self, fname):
        gray = cv2.cvtColor(self._img, cv2.COLOR_BGR2GRAY)
        classifier = cv2.CascadeClassifier(FaceDetector.FACE_CASCADE)
        faces = classifier.detectMultiScale(gray, scaleFactor=1.2, minSize=(30, 30))
        if len(faces):
            for (x, y, w, h) in faces:
                region = self._img[y:y + h, x:x + w]
                region_resized = cv2.resize(region, (128, 128))
                cv2.imwrite(fname, region_resized)
                break  #TODO とりあえず最初の一件だけとする。

■コンストラクタ
 渡されたファイルをopencvに読み込ませてます。

■cut_facesメソッド
 顔検出したら、それを切り取り、128 x 128にリサイズしてファイル保存してます。

学習モデルはOpenCVが提供している標準モデルでなく、アニメ顔に特化したlbpcascade_animeface.xmlを使ってます。ローカルに置くとうまく動かなかったので、pythonライブラリパスに直接置いてます。うちの環境だといつのまにかanaconda入ってたのでその下に。

アニメモデルは以下からDLしました。
https://github.com/nagadomi/lbpcascade_animeface

minSizeを指定したのは、小さい領域ほど誤検出率が増加しそうだったので。
なんかアンジェの袖と指を「顔」とか言ってくるので。

次回は機械学習、TensorFlowにかけるために、TFRecords形式を用意してみようと思います。

コード全体は以下。


from bs4 import BeautifulSoup
import cv2
import os
import requests
import shutil
import urllib


# 環境整備
shutil.rmtree('image')
os.mkdir('image')
os.mkdir('image/faces')


class ImageDownloader(object):
    def __init__(self, keyword):
        session = requests.session()
        session.headers.update(
            {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) \
             Gecko/20100101 Firefox/10.0'})
        params = urllib.parse.urlencode(
            {'q': keyword, 'tbm': 'isch', 'ijn': '1'})
        query = "https://www.google.co.jp/search" + '?' + params
        self._bs = BeautifulSoup(session.get(query).text, 'html.parser')

    def go(self):
        downloads = []
        for img in self._bs.find_all('img'):
            try:
                url = img['data-iurl']
                downloads.append('image/image_{}.jpg'.format(len(downloads) + 1))
                urllib.request.urlretrieve(url, downloads[-1])
            except KeyError:
                print('failed to get url : {}'.format(img))
        return downloads


class FaceDetector(object):

    # 学習済モデル
    FACE_CASCADE = '/home/websoler/anaconda3/lib/python3.7/site-packages/cv2/data/lbpcascade_animeface.xml'

    def __init__(self, fname):
        self._img = cv2.imread(fname)

    def cutout_faces(self, fname):
        gray = cv2.cvtColor(self._img, cv2.COLOR_BGR2GRAY)
        classifier = cv2.CascadeClassifier(FaceDetector.FACE_CASCADE)
        faces = classifier.detectMultiScale(gray, scaleFactor=1.2, minSize=(30, 30))
        if len(faces):
            for (x, y, w, h) in faces:
                region = self._img[y:y + h, x:x + w]
                region_resized = cv2.resize(region, (128, 128))
                cv2.imwrite(fname, region_resized)
                break  #TODO とりあえず最初の一件だけとする。

if __name__ == '__main__':

    downloads = ImageDownloader('アンジェ・カトリーナ').go()
    for i, d in enumerate(downloads):
        FaceDetector(d).cutout_faces('image/faces/faces_{}.jpg'.format(i + 1))
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4