Python AIプログラミング　その1　環境構築、文字認識

# 1. はじめに
最近家でプログラミングあまりやっていないなと思い、以前やろうとしたWebサービス作りも滞ってしまっていたのでAIプログラミングを少し勉強してみようと思い、[こちら](https://www.amazon.co.jp/%E3%81%99%E3%81%90%E3%81%AB%E4%BD%BF%E3%81%88%E3%82%8B-%E6%A5%AD%E5%8B%99%E3%81%A7%E5%AE%9F%E8%B7%B5%E3%81%A7%E3%81%8D%E3%82%8B-Python%E3%81%AB%E3%82%88%E3%82%8BAI%E3%83%BB%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%BB%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%82%8A%E6%96%B9-TensorFlow2%E5%AF%BE%E5%BF%9C-%E3%82%AF%E3%82%B8%E3%83%A9%E9%A3%9B%E8%A1%8C%E6%9C%BA/dp/4802612796/ref=pd_lpo_sccl_1/356-0633220-3417753?pd_rd_w=2F50v&content-id=amzn1.sym.855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_p=855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_r=E5V636NA51MB3SM43XGC&pd_rd_wg=zig6s&pd_rd_r=8b617f0d-6aa1-4577-9c65-465dacfee41b&pd_rd_i=4802612796&psc=1)の本を使って学習を始めてみた。

今回はその本の3.3 「文字認識・手書き数字を判定しよう」をやってみた。

# 2. 環境構築
今回はWindowsでの環境構築だが、今はMicrosoft Storeでインストールできるので**めっちゃ簡単！**
ついでに必要なライブラリとかもコマンドプロンプトまたはPowershellからpipでインストールできるので、**めっちゃ簡単！**
3.3章で使うライブラリはmatplotlib（グラフ描画ライブラリ）とscikit-learn（機械学習ライブラリ）、OpenCV（画像処理ライブラリ）なので、以下のコマンドを打てば終わり。
```
pip install -U pip
pip install -U matplotlib
pip install -U scikit-learn
pip install -U opencv-python
```
ちなみに、pip自身も必要に応じてアップグレードする必要があるので、最初にpipのアップグレード（"-Uオプション"）を入れてます。
![MSstore1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/862bb72b-3109-8cdd-2cde-15694763c2e8.png)

# 3. 手書き数字判定
本ではscikit-learnが持っているテストデータを学習するml_digist.pyと作った画像を判定するpredict-muimage.pyに分かれていたが、１回で実行できるよう下記のようにまとめてみた。
```Python
import cv2
import pickle
from sklearn.model_selection import train_test_split
from sklearn import datasets, svm, metrics
from sklearn.metrics import accuracy_score

def learn():
    # データを読み込む --- (*1)
    digits = datasets.load_digits()
    x = digits.images
    y = digits.target
    x = x.reshape((-1, 64)) # 二次元配列を一次元配列に変換 --- (*2)

    # データを学習用とテスト用に分割する --- (*3)
    x_train, x_test, y_train, y_test = \
        train_test_split(x, y, test_size=0.2)

    # データを学習 --- (*4)
    clf = svm.SVC()
    clf.fit(x_train, y_train)

    # 予測して精度を確認する --- (*5)
    y_pred = clf.predict(x_test)
    print(accuracy_score(y_test, y_pred))

    return clf

def predict_digit(filename, clf):
    with open("digits.pkl", "wb") as fp:
        pickle.dump(clf, fp)
    
    # 学習済みデータを読み込む
    with open("digits.pkl", "rb") as fp:
        clf = pickle.load(fp)
    # 自分で用意した手書きの画像ファイルを読み込む
    my_img = cv2.imread(filename)
    # 画像データを学習済みデータに合わせる
    my_img = cv2.cvtColor(my_img, cv2.COLOR_BGR2GRAY)
    my_img = cv2.resize(my_img, (8, 8))
    my_img = 15 - my_img // 16 # 白黒反転する
    # 二次元を一次元に変換
    my_img = my_img.reshape((-1, 64))
    # データ予測する
    res = clf.predict(my_img)
    return res[0]

clf = learn()

# 画像ファイルを指定して実行
n = predict_digit("zero.png", clf)
print("zero.png = " + str(n))
n = predict_digit("one.png", clf)
print("one.png = " + str(n))
n = predict_digit("two.png", clf)
print("two.png = " + str(n))
n = predict_digit("three.png", clf)
print("three.png = " + str(n))
n = predict_digit("four.png", clf)
print("four.png = " + str(n))
n = predict_digit("five.png", clf)
print("five.png = " + str(n))
n = predict_digit("six.png", clf)
print("six.png = " + str(n))
n = predict_digit("seven.png", clf)
print("seven.png = " + str(n))
n = predict_digit("eight.png", clf)
print("eight.png = " + str(n))
n = predict_digit("nine.png", clf)
print("nine.png = " + str(n))
```

で、読み込み対象の文字はこんな感じ。
![digits.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/833713d1-76e7-784c-6468-1673e846fd18.png)

結果は、こんな感じ。
![results.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/f4dbb20a-5436-ae10-ee2c-88a0f99a1a17.png)

うーん微妙。
原因としては、俺の字が汚いのもあるだろうけど、本にも3.3の最後の「改良のヒント」で今回のテストデータではそれほど正確な結果が出ないと書いてあるので、次はMNISTというデータセットを使うやり方で改良できるか見てみるか。

# 4. まとめと今後の展望
今回は久々のAIプログラミングということで試運転だったけど、環境構築は思ったより簡単だったのに驚いた。
次は数字認識の改良と、数字以外の文字の認識にチャレンジしてみるか。
その次は顔認識や動画解析、ニュース記事の分類などもやってみて、ある程度のところまで来たらFlaskかDjangoで機械学習のAPIサービスみたいなのを作ってみたい。
行く行くはそのAPIサービスを使ったWebサービスを作るところまで行けたらいいな。