Help us understand the problem. What is going on with this article?

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

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

https://qiita.com/Tatsuro64/items/95b0ce48b6bb155bfe29

プログラム: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))
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした