Monday, January 1, 2018

Pythonではじめる機械学習を読んで その1

最近、AIという言葉をどこでも耳にします。
私は、ここでいうAIは機械学習のことだと認識しています。
以前にも機械学習は勉強したことがあるのですが、すっかり忘れてしまったので再度学習してみようと思い立ちました。

色々情報を集めていると以下の本がなかなかよさそうです。
今は機械学習といえばPythonが流行りのようです。

Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

私が購入したのは2017年11月6日発行の初版第3刷のモノです。
本通りにやって詰まった部分がちょこちょこありましたので、メモ代わりにブログに残しておきます。
同じように悩める方がスムーズに学習できることを期待しております。


それでは今回は1章 はじめについてです。
以下の章番号はPythonではじめる機械学習に準じています。
なお、私の環境はWindows10 Pro 64bitです。

1章 はじめに

1.3.1 scikit-learnのインストール

3つのやり方が示されていましたが、私は一番無難そうだったAnacondaでインストールしていました。
下記サイトにアクセスして各プラットフォームにあったインストーラをダウンロードしてください。
私が入手したのはAnaconda 5.0.1 For Windows InstallerのPython 3.6 version 64bitです。
https://www.anaconda.com/download/

後述しますが、書籍では別途mglearnを入手するよう指示しています。


1.4.1 Jupyter Notebook

Jupyter NotebookはWindowsのスタートメニューから起動します。
起動するとブラウザ上に下記のような画面が表示されます。
①のNewをクリックしてPython3を選択します。
下記の画面が表示されます。
②のセル内にコードを入力します。
 Ctrl+Enterを押すと選択したセル内のコードが実行され、その結果が表示されます。
Shift+Enterで新しいセルを追加できます。
③のテクストボックスに名前を入力し、④のボタンで保存できます。
保存すればまたいつでも途中から作業を続けることができます。

1.4.5 pandas

IPythonでDataFrameを表示しますが、display()を読んだところでエラーとなりました。
以下のようにimportするとうまくいきます。
from IPython.core.display import display

1.4.6 mglearn

Anacondaにはmglearnは含まれていないので別途インストールする必要があります。
(ちゃんと書籍には記してありましたがうっかり見落としていました。)
Anacondaのcoda installコマンドではインストールできないのでpipを使います。
pip install mglearn
特にパスを通すなど必要なくjupyter noteで動きました。


私がつまづいたところは以上です。





Python版OpenCVで平滑化を行う

今回は,Python版のOpenCVを使って取得した画像の平滑化を行う方法をメモしておきます.

環境は以下のとおりです.
Python 2.6
OpenCV 2.4.6


それでは早速スクリプトを見ていきます.

import cv2

if __name__=="__main__":

    capture = cv2.VideoCapture(0)
    
    if capture.isOpened() is False:

        raise("IO Error")

    cv2.namedWindow("Capture", cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow("Red", cv2.WINDOW_AUTOSIZE)

    while True:

        ret, image = capture.read()
        if ret == False:
            continue

        gaussian_image = cv2.GaussianBlur(image, (5, 5),  0)
        
        red_image = []
        red_image.append(extract_color(image, 170, 5, 50, 200))
        red_image.append(extract_color(gaussian_image, 170, 5,  50, 200))
        
        gaussian_result = cv2.hconcat([image, gaussian_image])
        red_result = cv2.hconcat(red_image)
        
        cv2.imshow("Capture", gaussian_result)
        cv2.imshow("Red", red_result)
       
        if cv2.waitKey(33) >= 0:
            cv2.imwrite("capture.png", gaussian_result)
            cv2.imwrite("red_image.png", red_result)
            break

    cv2.destroyAllWindows()

Webカメラからの画像の取得と色抽出については,記事の終わりにあるリンクからそれぞれの説明をご覧ください.
なお,色抽出には以前に作成した以下のようなextract_color関数を使います.

出力画像 extract_color( 入力画像, 色相のしきい値(下), 色相のしきい値(上), 彩度のしきい値, 明度のしきい値 )



cv2.THRESH_BINARY: しきい値より大きい値は最大値,それ以外は0
cv2.THRESH_BINARY_INV: しきい値より大きい値は0,それ以外は最大値

その後,各画像のORを取ることで,2枚の画像を合わせます.
    if h_th_low > h_th_up:
        ret, h_dst_1 = cv2.threshold(h, h_th_low, 255, cv2.THRESH_BINARY) 
        ret, h_dst_2 = cv2.threshold(h, h_th_up,  255, cv2.THRESH_BINARY_INV)
        
        dst = cv2.bitwise_or(h_dst_1, h_dst_2)
次に,360°をまたがない場合を考えます.
ここでは,しきい値処理に以下のものを使用します.

cv2.THRESH_TOZERO: しきい値よりより大きい値はそのまま,それ以外は0
cv2.THRESH_TOZERO_INV: しきい値よりより大きい値は0,それ以外はそのまま

まず,しきい値(下)の値を0にし,その後,しきい値(上)より大きい値を0にすることで特定の範囲の値を抽出できます.
    else:
        ret, dst = cv2.threshold(h,   h_th_low, 255, cv2.THRESH_TOZERO) 
        ret, dst = cv2.threshold(dst, h_th_up,  255, cv2.THRESH_TOZERO_INV)

        ret, dst = cv2.threshold(dst, 0, 255, cv2.THRESH_BINARY)
色相については,ここまでで処理できたので,残りの明度と彩度についても処理を行います.
ここでは,黒に近い色を排除するだけでよいので,下限値のみのしきい値処理を行います.
    ret, s_dst = cv2.threshold(s, s_th, 255, cv2.THRESH_BINARY)
    ret, v_dst = cv2.threshold(v, v_th, 255, cv2.THRESH_BINARY)
そして最後に,各画像のANDをとり,各しきい値を満たす画素を抽出します.
    dst = cv2.bitwise_and(dst, s_dst)
    dst = cv2.bitwise_and(dst, v_dst)
これで,任意の色を抽出するextract_color関数が完成しました.

それでは,この関数を使って色抽出を行ってみます.
基本的なWebカメラの扱い使い方は,ここを見てください.
if __name__=="__main__":

    capture = cv2.VideoCapture(0)
    
    if capture.isOpened() is False:

        raise("IO Error")

    cv2.namedWindow("Capture", cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow("Red",     cv2.WINDOW_AUTOSIZE)
    cv2.namedWindow("Yellow",  cv2.WINDOW_AUTOSIZE)

    while True:

        ret, image = capture.read()
        if ret == False:
            continue

        red_image    = extract_color(image, 170, 5,  190, 200)
        yellow_image = extract_color(image, 10,  25, 50,  50)

        cv2.imshow("Capture", image)
        cv2.imshow("Red",     red_image)
        cv2.imshow("Yellow",  yellow_image)
       
        if cv2.waitKey(33) >= 0:
            cv2.imwrite("image.png", image)
            cv2.imwrite("red_image.png", red_image)
            cv2.imwrite("yellow_image.png", yellow_image)
            break

    cv2.destroyAllWindows()
このスクリプトの実行結果は以下のようになります.
まずは,入力画像です.
image
次に,赤色の抽出結果です.
red_image
最後に,黄色の抽出結果です.
yellow_image

この例では,赤色と黄色をそれぞれ抽出して画像を表示しています.
各画像を見ると,それぞれの色で抽出出来ていることがわかります.
基本的な処理は既に説明していますが,OpenCVではHSVの各チャンネルは以下のような値域となっていることに注意してください.

H(色相):0~180
S(彩度):0~255
V(明度):0~255

以上でHSV色空間で色抽出をする方法の説明を終わります.  

Python版OpenCV関連の記事:
参考文献:
「Miscellaneous Image Transformations」『OpenCV 2.4.9.0 documentation』<http://docs.opencv.org/modules/imgproc/doc /miscellaneous_transformations.html> (2015/02/20アクセス)
「Basic Operations on Images」『OpenCV 3.0.0-dev documentation』<http://docs.opencv.org/trunk/doc/py_tutorials/py_core /py_basic_ops/py_basic_ops.html> (2015/02/20アクセス)