2019年12月31日火曜日

[macOS] HomebrewとHomebrew経由でアプリケーションなどをインストール

HomebrewとHomebrew経由でアプリケーションをインストールした際のメモです.

Homebrewのインストール
ターミナルから以下のコマンドを実行します.
% /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Homebrew経由でアプリケーションなどのインストールを行う際には,インストール前に以下のコマンドを実行します.
アップデート(Already up-to-date. は完了を意味する応答)
% brew update
Already up-to-date.
アップグレード(特に応答はありません)
% brew upgrade
ドクター(Your system is ready to brew. は完了を意味する応答)
% brew doctor
Your system is ready to brew.

gccのインストール
以下のコマンドを実行します.
% brew install gcc

gnuplotのインストール
以下のコマンドを実行します.
% brew install gnuplot                      
gnuplotは以前のようにX11やAquaTermをオプションとしてインストールして描画させずにqtで描画する仕様となりました.

Juliaのインストール
以下のコマンドを実行します.
% brew cask install julia

Juliaを起動して,主だったパッケージをインストールしておきます.
パッケージのインストールを行う(パッケージの管理モードに入る)には,JuliaのREPLが起動して,"Julia > "と表示されている状態で"]"をタイプします.すると,プロンプトが"(vx.x) pkg> "と切り替わります(x.xはバージョンを表す数字).この状態で"add Package Name"を実行してパッケージをインストールします.
以下は,主だったパッケージをインストールした際の例です.
% Julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.3.1 (2019-12-30)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 

(v1.3) pkg> add CSV
(v1.3) pkg> add Combinatorics
(v1.3) pkg> add DataFrames
(v1.3) pkg> add Distributions

(v1.3) pkg> add IJulia

(v1.3) pkg> add JuMP
(v1.3) pkg> add Plots
(v1.3) pkg> add PyCall
(v1.3) pkg> add PyPlot
(v1.3) pkg> add RDatasets
(v1.3) pkg> add StatsBase
(v1.3) pkg> add StatsPlot
(v1.3) pkg> add SumOfSquares
(v1.3) pkg> add Statistics
(v1.3) pkg> add Gadfly
(v1.3) pkg> add LinearAlgebra

なお,各パッケージのインストールを実行した際には,インストール状況等が流れます(上記の例では省略).

インストールしたパッケージの状態を確認するには以下のコマンドを実行します.
(v1.3) pkg> status

なぜか,当初はターミナルからで起動したのですが,いつの間にか起動しなくなってしまった...といった場合には,以下のようにして.bashrcにJuliaのエイリアスを追加します(ホームディレクトリに移動して以下のコマンドを実行).
# .bashrc
% alias julia="/Applications/Julia1.3.app/Contents/Resources/julia/bin/julia"
また,Juliaでは起動しますが,juliaでは起動しません.

Jupyter Notebookのインストール
以下のコマンドを実行します.
% pip3 install jupyter
Python3は特にパスを通さなくても最初から使うことができます.

Juliaのパスを通すには以下のコマンドを実行します.
% echo "alias julia='/path/to/install/folder/bin/julia'" >> ~/.zshrc
% exec $SHELL

Jupyter NotebookにRを追加するには,Rのインタープリターを起動して,以下のコマンドを実行します.
> install.packages(c('repr', 'IRdisplay', 'evaluate', 'crayon', 'pbdZMQ', 'devtools', 'uuid', 'digest'))
このインストールでは,CRANのミラーを聞いてくるので近いところを選択します.この時は,39: Japan (Tokyo) [https] を選択しました.
続いて,以下のコマンドを実行します.
> install.packages('IRkernel')
最後に以下のコマンドを実施します.
> IRkernel::installspec()
参考:IRkernelのインストールに関する公式ページ

なお,インターネット等で調べると,2番目のコマンド実行ではなく,
> devtools::install_github('IRkernel/IRkernel')
としている例が示されている場合がありますが,GitHubからIRkernelのインストールができないというエラーが返ってきて上手くいきませんでした.

Kernel Specを確認するには以下のコマンドを実行します.
Available kernels:
  ir           /Users/hide/Library/Jupyter/kernels/ir
  julia-1.3    /Users/hide/Library/Jupyter/kernels/julia-1.3

  python3      /usr/local/share/jupyter/kernels/python3

Pythonのインストール
macOS CatalinaからはPython3がデフォルトでインストールされているので不要です.
確認のために以下のコマンドを実行してみます.
% which python3
/usr/local/bin/python3

同様に,pip3もインストールされているので確認しておきます.
% pip3 -v

Usage:   
  pip3 <command> [options]
...この後にズラズラと続きますが省略...

主だったパッケージをインストールします.
% pip3 install numpy
% pip3 install scipy
% pip3 install matplotlib
% pip3 install scikit-learn


なお,pip3経由でパッケージをインストールしたい際には,以下のコマンドを実行します(Package Nameはインストールしたいパッケージ名).

% pip3 Package Name

インストールされたパッケージを確認するには,以下のコマンドを実行します.
% pip3 list
すると,以下のようにインストールされているパッケージとそのバージョンが表示されます.
Package            Version
------------------ -------
appnope            0.1.0  
attrs              19.3.0 
backcall           0.1.0  
bleach             3.1.1  
cycler             0.10.0 
decorator          4.4.1  
defusedxml         0.6.0  
entrypoints        0.3    
importlib-metadata 1.5.0  
ipykernel          5.1.4  
ipython            7.13.0 
ipython-genutils   0.2.0  
ipywidgets         7.5.1  
jedi               0.16.0 
Jinja2             2.11.1 
joblib             0.14.1 
jsonschema         3.2.0  
jupyter            1.0.0  
jupyter-client     6.0.0  
jupyter-console    6.1.0  
jupyter-core       4.6.3  
kiwisolver         1.1.0  
MarkupSafe         1.1.1  
matplotlib         3.1.3  
mistune            0.8.4  
nbconvert          5.6.1  
nbformat           5.0.4  
notebook           6.0.3  
numpy              1.18.1 
pandas             1.0.1  
pandocfilters      1.4.2  
parso              0.6.2  
patsy              0.5.1  
pexpect            4.8.0  
pickleshare        0.7.5  
pip                20.0.2 
prometheus-client  0.7.1  
prompt-toolkit     3.0.3  
ptyprocess         0.6.0  
Pygments           2.5.2  
pyparsing          2.4.6  
pyrsistent         0.15.7 
python-dateutil    2.8.1  
pytz               2019.3 
pyzmq              19.0.0 
qtconsole          4.6.0  
scikit-learn       0.22.2 
scipy              1.4.1  
seaborn            0.10.0 
Send2Trash         1.5.0  
setuptools         42.0.2 
six                1.14.0 
statsmodels        0.11.1 
terminado          0.8.3  
testpath           0.4.4  
tornado            6.0.3  
traitlets          4.3.3  
wcwidth            0.1.8  
webencodings       0.5.1  
wheel              0.33.6 
widgetsnbextension 3.5.1  

zipp               3.0.0  

Rのインストール
ターミナルから以下のコマンドを実行して,brewsci/scienceにtapします.
% brew tap brewsci/science
続いてRをインストールします.
% brew install r

Rstanをインストールしておきます.まずはターミナルからRを起動します.
% R

続いて,以下のコマンドを実行します.
> install.packages("rstan")
インストールの途中でミラーサイトを選択することを求められます(今回は日本:39を選択).Rstanのダウンロード,インストールには多少時間がかかります.

RstanをRに読み込むには以下のコマンドを実行します.
> library(rstan)

また,以下の設定を行うことが推奨されているようです.このコマンドはコンパイルした結果を保存するためのものです.
> rstan_options(auto_write=TRUE)
こちらは,複数のコアを使用するためのものです.
> options(mc.cores=parallel::detectCores())

Ricty(フォント)のインストール
sanematのリポジトリにタップする.
% brew tap sanemat/font

ターミナルから以下のコマンドを実行するとインストールが始まります.
% brew install ricty

インストールが終了すると最後に,以下のメッセージが表示されます.
***************************************************
To install Ricty:
  $ cp -f /usr/local/opt/ricty/share/fonts/Ricty*.ttf ~/Library/Fonts/
  $ fc-cache -vf
***************************************************

上記のメッセージにある2つのコマンドを実行して,ズラズラと流れた後に,以下のように表示されれば成功です.
fc-cache: succeeded

Homebrewを使ってAppStoreで提供されているアプリケーションをインストールすることもできます.
そのためには,まずmasをインストールします.
% brew install mas
masを使ってアプリケーションをインストールする際には,以下のようにアプリケーションのID(以下の例ではxxxxxxxxx)を指定する必要があります.
% mas install xxxxxxxxx

IDはAppStoreのURLに示されています.例えばLINEであれば,AppStoreのURLは以下のようになり,URL内にid539883307と書かれているので,このid番号を指定します.

2019年12月30日月曜日

[macOS] macOS CatalinaにTeXをインストールする

macOS CatalinaにMacTeX2019をインストールした際のメモです.
詳しくは,こちらの記事を参考にして下さい.

まずは,MacTeX2019のpkgファイルをダウンロードします(この時点での最新版は,mactex-20190508.pkg).MacTeX2019はファイルサイズが4Gを超えるので,公式サイトではなく,ミラーサイトからのダウンロードが推奨されます.

ダウンロードしたpkgファイルをダブルクリックしてインストールを進めます.英文のみのドキュメント作成しかしない方はこれで終わりなのかもしれませんが,TeX Live はデフォルトだと,和文フォントとして IPAex フォントが埋め込まれる設定になっているそうです.ヒラギノフォントを TeX で使用するには,こちらからダウンロードしたパッチ(Bibunsho7-patch-1.4-20190925.dmg)を適用します.

パッチ(Bibunsho7-patch-1.4-20190925.dmg)をダブルクリックすると,Patch.appがマウントされます.出てくる雪だるま☃︎︎のアイコンをダブルクリックして実行します(警告ダイアログが表示されますが,アドミニストレーターのパスワードを入力するなどして開くとインストールが始まり,終わります.

この後に,TeXShopの日本語設定を行います.
    TeXShop > Preference...
を選んで,Sourceタブを開きます.設定画面の左下のSet Default Values(設定ファイルボタン)をクリックしてupTeX(ptex2pdf)もしくはpLaTeX(ptex2pdf)を選択します.upTeXはUnicodeを活用できて,JIS第何水準漢字などを気にしないで良いとのことです.pTeXは従来のTeXだとのことです.


また左上のDocument Font(フォント)はデフォルトでは上図のようにHelvetica - 12 になっています.等幅フォントが好みの人は変更しておくと良いです.

ここで,TeXShopを終了させて,ターミナルを起動して,以下のコマンドを実行します.
% defaults write TeXShop FixLineNumberScroll NO
% defaults write TeXShop SourceScrollElasticity NO
% defaults write TeXShop FixPreviewBlur YES

これらのコマンドの意味は,参考にさせて頂いたこちらのサイトによると,

  1.  FixLineNumberScroll NO は,10.7 Lionなどの古いOSに存在した,行番号がスクロールしないOS側のバグに対処するための対症療法を停止させる措置.最近の macOS ではこのバグが修正されており,この対症は不要で,スクロール速度が遅くなる原因となるので,これを取り除いている.
  2. SourceScrollElasticity NO は,スクロール時に上下端で大きく跳ね返るバウンスエフェクトを停止させる措置.OS X 10.10 Yosemite 以降では,バウンスが大きいので,このエフェクトを停止させている.
  3. FixPreviewBlur YES は,OS X 10.10 Yosemite 以降で,プレビューウィンドウのPDFが(一部の環境で)ぼやけて見えるのを防止する措置.
とのことです.

2019年12月29日日曜日

[macOS] Catalina へのアップデート

macOS Catalina にアップデートした際のメモです.

クリーンインストールの手順は以下の通りです.
  1. Time Machineでバックアップを取る(ことが推奨されていますが,やり忘れました...)
  2. Mojaveからのアップデートだったので,Catalinaに上書きアップグレード
  3. リカバリーモードから起動(cmd⌘ + R + 電源ボタン)
  4. 既存のデータを削除・消去
    1. ディスクユーティリティを開く
    2. Macintosh HD - Data を選択
    3. ボリュームの-ボタンをクリックし削除
    4. Macintosh HDを選択し,消去ボタンをクリック
    5. 名前は「Macintosh HD」,フォーマットは「APFS」にする
    6. 内蔵の部分にMacintosh HDのみで,使用済みの容量がほとんどないことを確認
    7. ディスクユーティリティを閉じる
  5. maOS Catalinaの再インストール
maOSのクリーンインストール後にインストールしたアプリケーションは,以下の通りです.

2019年12月28日土曜日

[macOS] HomebrewでRicky-Diminishedをインストールする.

macOSにHomebrewでフォント(Ricky-Diminished)をインストールした際のメモです.

ターミナルから以下のコマンドを順番に実行します.
% brew search Ricty

% brew tap homebrew/cask-fonts

% brew cask info font-ricty-diminished

% brew cask install font-ricty-diminished

最後のコマンドを実行した後に以下のように表示されれば成功です.
🍺  font-ricty-diminished was successfully installed!

2019年10月18日金曜日

Tello Programming 011 -Pythonで離陸と着陸を制御する-

Telloをラップトップから制御して,離陸と着陸をさせるコードのメモです.

ラップトップとTello間の情報の送受信に必要なポート情報については,Tello SDK 2.0 User Guideによると,送受信は以下のポートから行えると書いてあります.
  • ラップトップのIPアドレス:192.168.10.2(ラップトップとTelloをWifiで接続すると自動的に割り振られる)
  • ラップトップからTelloへのUDPポート:8889
  • TelloのIPアドレス:192.168.10.1
  • Telloからラップトップへの命令に対するUDPポート:8889
  • Telloからラップトップへの情報(状況)送信UDPポート:8890
  • TelloからラップトップへのビデオをストリームするUDPポート:1111
ラップトップとTelloの接続

Tello SDK 2.0 User Guide, p.2

また,Tello SDK 2.0 User GuideにはTelloの様々なコマンドが記載されていますが,今回は離陸した後に着陸するだけのプログラムなので,使用するのは,以下の二つです.

離陸後に10秒待機して着陸するコードにしてみます.

import logging
import socket
import sys
import time


logging.basicConfig(level=logging.INFO, stream=sys.stdout)
logger = logging.getLogger(__name__)

class DroneManager(object): 
    def __init__(self, host_ip='192.168.10.2', host_port=8889
                 drone_ip='192.168.10.1', drone_port=8889):
        self.host_ip = host_ip
        self.host_port = host_port
        self.drone_ip = drone_ip
        self.drone_port = drone_port
        self.drone_address = (drone_ip, drone_port)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.bind((self.host_ip, self.host_port))
        self.socket.sendto(b'command', self.drone_address)
        self.socket.sendto(b'streamon', self.drone_address)
    
    def __dell__(self):
        self.stop()
    
    def stop(self):
        self.socket.close()
    
    def send_command(self, command):
        logger.info({'action': 'send_command', 'command': command})
        self.socket.sendto(command.encode('utf-8'), self.drone_address)
    
    def takeoff(self):
        self.send_command('takeoff')
    
    def land(self):
        self.send_command('land')

if __name__ == '__main__'
    drone_manager = DroneManager()
    drone_manager.takeoff()

    time.sleep(10)


    drone_manager.land()

実行に当たっては,ラップトップとTelloをWifi接続します.

そして,ターミナルから以下のように(この例では上記のコードに drone-manager.pyという名前をつけています)実行するだけです.
$ python3 drone_manager.py

実行した際に,ターミナルでは以下のように命令の送信をしている(プログラムは動いている)にも関わらず,Telloが反応しないというトラブルが生じました....
$ python3 drone_manager.py
INFO:__main__:{'action': 'send_command', 'command': 'takeoff'}
INFO:__main__:{'action': 'send_command', 'command': 'land'}

IPアドレスの割り振りの問題かと思って,Telloとラップトップを接続した状態でのラップトップに割り振られているIPアドレスをSystem Preference(システム環境設定)から調べてみると以下のように,192.168.10.2 が割り振られています.

その後,Telloのバッテリーがなくなるまで試行錯誤を繰り返したのですが,状況は変わらず,別のバッテリーに差し替えて試してみたところ,無事にTelloは離陸してホバリングした後に着陸しました.



結果としては離着陸に成功したのですが,何故,最初の時点で反応しなかったのかは,謎のままです.

2019年10月17日木曜日

[OpenCV] 動画の顔認識

OpenCVのライブラリを使用して,動画での顔認識を行ってみた際のメモです.なお,Python3とOpenCVがインストールされている前提です(Python3のインストールはこちら,OpenCVのインストールはこちら).

コードは以下のようになります.

import cv2 as cv

cap = cv.VideoCapture(0)

face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv.CascadeClassifier('haarcascade_eye.xml')

while True:
    ret, frame = cap.read()
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5) # default setting
    print(len(faces))
    
    for (x, y, w, h) in faces:
        cv.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
        eye_gray = gray[y:y+h, x:x+w]
        eye_color = frame[y:y+h, x:x+w]
        eyes = eye_cascade.detectMultiScale(eye_gray)
        for (ex, ey, ew, eh) in eyes:
            cv.rectangle(eye_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)

    cv.imshow('frame', frame)
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

cv.destroyAllWindows()

以下は,コードの解説です.
1行目
import cv2 as cv
OpenCVのパッケージを読み込む.

3行目
変数 cap にカメラの画像を読み込むように設定する.0 はラップトップに付属のカメラを使用する場合.上手く認識できない場合は,0を1, 2などと変えてみると上手く行く場合が多い.


2019年10月15日火曜日

[OpenCV] 静止画の顔認識 Object Detection (objdetect module) Cascade Classifier

前回投稿したPython3 + OpenCVによる顔認識では,Cascade Classifier を使用しています.
以下は,OpenCVのページに示されている説明に関してのメモです(ほぼ,直訳).

Goal 目標
In this tutorial,

  • We will learn how the Haar cascade object detection works.
  • We will see the basics of face detection and eye detection using the Haar Feature-based Cascade Classifiers.
  • We will use the cv::CascadeClassifier class to detect objects in a video stream. Particularly, we will use the functions:
  • cv::CascadeClassifier::load to load a .xml classifier file. It can be either a Haar or a LBP classifer
  • cv::CascadeClassifier::detectMultiScale to perform the detection.

このチュートリアルでは

  • Haar cascade 検出の仕組みを学習します.
  • Haar Feature-based Cascade 検出器を使用した顔検出と目の検出の基本について説明します.
  • cv::CascadeClassifierクラスを使用して、ビデオストリーム内のオブジェクトを検出します.特に,次の関数を使用します.
  • cv::CascadeClassifier::load 分類器ファイルを読み込む(HaarまたはLBP分類器のいずれか).
  • cv::CascadeClassifier::detectMultiScale 検出を実行する.


Theory 理論
Object Detection using Haar feature-based cascade classifiers is an effective object detection method proposed by Paul Viola and Michael Jones in their paper, "Rapid Object Detection using a Boosted Cascade of Simple Features" in 2001. It is a machine learning based approach where a cascade function is trained from a lot of positive and negative images. It is then used to detect objects in other images.
Haarの特徴に基づくカスケード分類器を使用したオブジェクト検出は,2001年にPaul ViolaとMichael Jonesの論文「単純な特徴のブーストカスケードを使用した迅速なオブジェクト検出」で提案された効果的なオブジェクト検出方法です.カスケード機能は,多くのポジティブ(正解)またはネガティブ(不正解)画像によってトレーニングされた機械学習です.その後,他の画像内のオブジェクトを検出するために使用されます.

Here we will work with face detection. Initially, the algorithm needs a lot of positive images (images of faces) and negative images (images without faces) to train the classifier. Then we need to extract features from it. For this, Haar features shown in the below image are used. They are just like our convolutional kernel. Each feature is a single value obtained by subtracting sum of pixels under the white rectangle from sum of pixels under the black rectangle.
ここでは,顔検出を行います.最初に,アルゴリズムは分類器を訓練するために多くのポジティブ(正解)画像(顔の画像)とネガティブ(不正解)画像(顔のない画像)を必要とします.次に,そこから(顔の)特徴を抽出する必要があります.このために,下図に示されているHaar機能を使用します.それらは畳み込みカーネルのようなものです.各特徴は,黒い長方形の下のピクセルの合計から白い長方形の下のピクセルの合計を引いて得られる一つの値となります.
image 画像

Now, all possible sizes and locations of each kernel are used to calculate lots of features. (Just imagine how much computation it needs? Even a 24x24 window results over 160000 features). For each feature calculation, we need to find the sum of the pixels under white and black rectangles. To solve this, they introduced the integral image. However large your image, it reduces the calculations for a given pixel to an operation involving just four pixels. Nice, isn't it? It makes things super-fast.
ここで,各カーネルのすべての可能なサイズと場所が多くの特徴を計算するために使用されます(必要な計算量を想像すると,24x24のウィンドウで160000以上の特徴が得られる).特徴の計算ごとに,白と黒の長方形の下にあるピクセルの合計を見つける必要があります.これを解決するために,彼ら(論文の著者達)は積分画像を導入しました.画像がどれほど大きくても,指定されたピクセルの計算は,4つのピクセルのみを含む演算に削減されます.素晴らしいでしょう.それによって超高速になります.

But among all these features we calculated, most of them are irrelevant. For example, consider the image below. The top row shows two good features. The first feature selected seems to focus on the property that the region of the eyes is often darker than the region of the nose and cheeks. The second feature selected relies on the property that the eyes are darker than the bridge of the nose. But the same windows applied to cheeks or any other place is irrelevant. So how do we select the best features out of 160000+ features? It is achieved by Adaboost.
しかし,計算した,全てのこれらの特徴のほとんどは(目とは)無関係です.たとえば,下の画像について考えてください.一番上の行は、2つのわかりやすい特徴を示しています.最初の特徴は,目の領域が鼻と頬よりも暗い色であるという特性にフォーカスしています.二番目の特徴は,しかし,目が鼻梁よりも暗い色である特徴です.しかし,ウィンドウが頬やその他の場所に適用される同じウィンドウは無関係です.それでは,160000以上の特徴の中から最適な特徴を選択するにはどうすればよいでしょうか? それは,Adaboostによって達成されます.
image 画像

For this, we apply each and every feature on all the training images. For each feature, it finds the best threshold which will classify the faces to positive and negative. Obviously, there will be errors or misclassifications. We select the features with minimum error rate, which means they are the features that most accurately classify the face and non-face images. (The process is not as simple as this. Each image is given an equal weight in the beginning. After each classification, weights of misclassified images are increased. Then the same process is done. New error rates are calculated. Also new weights. The process is continued until the required accuracy or error rate is achieved or the required number of features are found).
これによって,すべての特徴を,すべてのトレーニング画像に適用します.各々の特徴に対して,顔を正しいものを間違っているものに分類する,最適なしきい値を見つけますが,明らかに,エラーや誤分類が生じます.なので,エラー率が最小の特徴,すなわち顔と顔以外の画像を最も正確に分類する特徴を選択します(プロセスはこれほど単純ではありません.各々の画像には,最初に等しい重みが与えられます.各分類の後に,誤分類された画像の重みが増加します.その後,同じプロセスが実行されます.その後,新しいエラー率が計算されて,必要な精度またはエラー率が達成されるか,必要な機能の数が見つかるまでプロセスが実行されます).

The final classifier is a weighted sum of these weak classifiers. It is called weak because it alone can't classify the image, but together with others forms a strong classifier. The paper says even 200 features provide detection with 95% accuracy. Their final setup had around 6000 features. (Imagine a reduction from 160000+ features to 6000 features. That is a big gain).
最終的な分類器は,これらの弱い分類器の重みの和になります.それらは,単独では画像を分類できないために,弱いと呼ばれますが,他のものと一緒になって強力な分類器を形成します.この論文では,200の特徴ですら,95%の精度で検出できると述べています.最終的にセットアップされたものには約6000の特徴がありました (160000以上の特徴から6000の特徴への削減は,大きなメリットです).

So now you take an image. Take each 24x24 window. Apply 6000 features to it. Check if it is face or not. Wow.. Isn't it a little inefficient and time consuming? Yes, it is. The authors have a good solution for that.
撮影した画像に対して, 24 x 24の各ウィンドウを取得します.これに, 6000の特徴を適用して,顔かどうかを判断します.この方法は,非効率的で時間がかかると思いませんか?その通りです.著者はこの良い解決策を持っています.

In an image, most of the image is non-face region. So it is a better idea to have a simple method to check if a window is not a face region. If it is not, discard it in a single shot, and don't process it again. Instead, focus on regions where there can be a face. This way, we spend more time checking possible face regions.
画像では,画像のほとんどは顔以外の領域になるので,ウィンドウが顔領域でないかどうかを確認する簡単な方法を用意することをお勧めします.そうでない場合は,1回のショットで破棄し,再度処理はせずに,顔が存在する可能性のある領域にフォーカスします.このようにして,顔の可能性の高い領域を確認することに時間を費やします.

For this they introduced the concept of Cascade of Classifiers. Instead of applying all 6000 features on a window, the features are grouped into different stages of classifiers and applied one-by-one. (Normally the first few stages will contain very many fewer features). If a window fails the first stage, discard it. We don't consider the remaining features on it. If it passes, apply the second stage of features and continue the process. The window which passes all stages is a face region. How is that plan!
このように,彼ら(著者)は分類器のカスケードの概念を導入しました.ウィンドウに6000個のすべての(顔の)特徴判定機能を適用する代わりに,特徴は分類器のさまざまな段階にグループ化されて,1つずつ適用されます(通常,最初の数段階には非常に少ない機能が含まれます).ウィンドウが最初の段階で誤りである(顔ではない)と判断した場合には,そのウィンドウを破棄して,残りの特徴については考慮しません.正しい(顔である)と判断した場合は,次の特徴を判断するステージを適用して,プロセスを続行します.すべてのステージを通過する(顔だと判断される)ウィンドウは,顔の領域となります.この計画はどうでしょう!

The authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25 and 50 features in the first five stages. (The two features in the above image are actually obtained as the best two features from Adaboost). According to the authors, on average 10 features out of 6000+ are evaluated per sub-window.
著者の検出器には、最初の5つの段階で1、10、25、25、および50の機能を備えた38の段階で6000以上の機能がありました(上の画像の2つの特徴は,Adaboostから最高の2つの特徴として実際に取得されています).著者によるとサブウィンドウごとに,平均して6000以上の10個の機能で評価されます.

So this is a simple intuitive explanation of how Viola-Jones face detection works. Read the paper for more details or check out the references in the Additional Resources section.
これは,Viola-Jonesの顔検出をどのように機能するかについての簡単かつ直感的な説明です.詳細については論文を読むか「その他のリソース」セクションを参照して確認してください.

Haar-cascade Detection in OpenCV 
OpenCV provides a training method (see Cascade Classifier Training) or pretrained models, that can be read using the cv::CascadeClassifier::loadmethod. The pretrained models are located in the data folder in the OpenCV installation or can be found here.
The following code example will use pretrained Haar cascade models to detect faces and eyes in an image. First, a cv::CascadeClassifier is created and the necessary XML file is loaded using the cv::CascadeClassifier::load method. Afterwards, the detection is done using the cv::CascadeClassifier::detectMultiScale method, which returns boundary rectangles for the detected faces or eyes.
This tutorial code's is shown lines below. You can also download it from here

objectDetection.cpp
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>

using namespace std;
using namespace cv;

/** Function Headers */
void detectAndDisplay( Mat frame );

/** Global variables */
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;

/** @function main */
int main( int argc, const char** argv )
{
    CommandLineParser parser(argc, argv,
                             "{help h||}"
                             "{face_cascade|data/haarcascades/haarcascade_frontalface_alt.xml|Path to face cascade.}"
                             "{eyes_cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|Path to eyes cascade.}"
                             "{camera|0|Camera device number.}");

    parser.about( "\nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face + eyes) in a video stream.\n"
                  "You can use Haar or LBP features.\n\n" );
    parser.printMessage();

    String face_cascade_name = samples::findFile( parser.get<String>("face_cascade") );
    String eyes_cascade_name = samples::findFile( parser.get<String>("eyes_cascade") );

    //-- 1. Load the cascades
    if( !face_cascade.load( face_cascade_name ) )
    {
        cout << "--(!)Error loading face cascade\n";
        return -1;
    };
    if( !eyes_cascade.load( eyes_cascade_name ) )
    {
        cout << "--(!)Error loading eyes cascade\n";
        return -1;
    };

    int camera_device = parser.get<int>("camera");
    VideoCapture capture;
    //-- 2. Read the video stream
    capture.open( camera_device );
    if ( ! capture.isOpened() )
    {
        cout << "--(!)Error opening video capture\n";
        return -1;
    }

    Mat frame;
    while ( capture.read(frame) )
    {
        if( frame.empty() )
        {
            cout << "--(!) No captured frame -- Break!\n";
            break;
        }

        //-- 3. Apply the classifier to the frame
        detectAndDisplay( frame );

        if( waitKey(10) == 27 )
        {
            break; // escape
        }
    }
    return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay( Mat frame )
{
    Mat frame_gray;
    cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    //-- Detect faces
    std::vector<Rect> faces;
    face_cascade.detectMultiScale( frame_gray, faces );

    for ( size_t i = 0; i < faces.size(); i++ )
    {
        Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
        ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );

        Mat faceROI = frame_gray( faces[i] );

        //-- In each face, detect eyes
        std::vector<Rect> eyes;
        eyes_cascade.detectMultiScale( faceROI, eyes );

        for ( size_t j = 0; j < eyes.size(); j++ )
        {
            Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
            int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
            circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
        }
    }

    //-- Show what you got
    imshow( "Capture - Face detection", frame );

}

Result
1. Here is the result of running the code above and using as input the video stream of a built-in webcam:
1. 以下は,上記のコードを実行して,入力として組み込みWebカメラのビデオストリームを使用した結果です.

Be sure the program will find the path of files haarcascade_frontalface_alt.xml and haarcascade_eye_tree_eyeglasses.xml. They are located in opencv/data/haarcascades
プログラムがhaarcascade_frontalface_alt.xmlファイルとhaarcascade_eye_tree_eyeglasses.xmlファイルのパスを見つけられるようにしてください.それらはopencv / data / haarcascadesに置いてあります.

2. This is the result of using the file lbpcascade_frontalface.xml (LBP trained) for the face detection. For the eyes we keep using the file used in the tutorial.
2. これは,顔検出にファイルlbpcascade_frontalface.xml(LBPトレーニング済み)を使用した結果です.目のために,チュートリアルで使用したファイルを使用し続けています.

Additional Resources

  1. Paul Viola and Michael J. Jones. Robust real-time face detection. International Journal of Computer Vision, 57(2):137–154, 2004. [239]
  2. Rainer Lienhart and Jochen Maydt. An extended set of haar-like features for rapid object detection. In Image Processing. 2002. Proceedings. 2002 International Conference on, volume 1, pages I–900. IEEE, 2002. [136]
  3. Video Lecture on Face Detection and Tracking
  4. An interesting interview regarding Face Detection by Adam Harvey
  5. OpenCV Face Detection: Visualized on Vimeo by Adam Harvey