# 【サンプルコード付き】画像認識をPython×機械学習で実装していこう！

> 本記事では、画像認識についてPythonでプログラムを実装しながら簡単に解説していきます。画像認識の領域はディープラーニングの発展とともに盛り上がり、今でも様々な研究が盛んです。そんな画像認識の領域についてサンプルコードを参考にしながらPythonで実装していきましょう！

- URL: https://toukei-lab.com/python-image
- 公開: 2022.11.29 / 更新: 2024.01.29
- サイト: スタビジ（https://toukei-lab.com）

:::talk{who="umatan"}
本記事では、画像認識についてPythonでプログラムを実装しながら簡単に解説していきます。画像認識の領域はディープラーニングの発展とともに盛り上がり、今でも様々な研究が盛んです。そんな画像認識の領域についてサンプルコードを参考にしながらPythonで実装していきましょう！
:::

こんにちは！

消費財メーカーでデータ分析＆デジタルマーケのお仕事をしているウマたん（[@statistics1012](https://twitter.com/statistics1012?lang=ja)）です。

[ディープラーニング](/deep-learning)の登場で画像認識の世界には大きなブレイクスルーがおきました。

:::talk{who="robotan"}
画像認識の世界が盛り上がっているのは知っているんだけど、いまいち具体的なことは分からないんだよなー！
:::

:::talk{who="umatan"}
そうだよねー！画像認識の世界を簡単に理解していこう！
:::

この記事では画像認識について、Pythonでの実装をおこないつつ簡単に解説していきます！

:::talk{who="umatan"}
画像認識やディープラーニングについては当メディアが運営する「[スタアカ](https://toukei-lab.com/achademy/)」というサービスの「**[ディープラーニングコース](https://toukei-lab.com/achademy/?sfwd-courses=deep-learning)**」でも詳しく解説しているので是非参考にしてみてね
:::

:::box
**[業界最安級AIデータサイエンス特化スクール：スタアカ（スタビジアカデミー）](https://toukei-lab.com/achademy/)**
:::

## 画像認識の基礎をPython×OpenCVで理解

![stories data](/wp-content/uploads/2021/01/Data-points-rafiki-e1612221774326-1024x765.png)

まずは、画像認識の領域の基礎知識について見ていきましょう！

画像認識の領域で非常によく使われるライブラリに[OpenCV](/python_opencv)というものがあります。

正式名称は「Open Source Computer Vision Library」と言い、コンピュータービジョン・画像認識の領域でよく使われるライブラリです。

Pythonで利用されることが多いですが、Python以外のプログラミング言語でも利用することが可能です。

### OpenCVを使って画像を読み取ろう！

まずは、この[OpenCV](/python_opencv)を使って簡単に画像を表示させたり加工したりしていきましょう！

今回題材として使うデータは[Nishika](https://competition.nishika.com/competitions/kaokore_pra/summary)というデータ分析コンペの絵画データです。

[Nishika](https://competition.nishika.com/competitions/kaokore_pra/summary)のトレーニングコンペ「日本絵画に描かれた人物の顔分類に機械学習で挑戦！」のデータをダウンロードしてください！（※会員登録しないとデータをダウンロードできないので注意してください）

![Nishika-image](/wp-content/uploads/2021/04/Nishika_image-min-1024x548.jpg)

教師データには4238枚の様々な日本絵画の人物が描かれた画像データが入っています。

性別と身分によって8種類のラベルが振られていて、画像からその人物がどのラベルに該当するかを当てるという面白いデータコンペです。

[Google colaboratory](/google-colaboratory)を前提に実装していきますが、ローカルの[Jupyter環境](/python-how)でも問題ないです。

GPUが無料で使えるのでディープラーニングなどを利用する際はGoogle colaboratoryを使うことが多いです。

まずは、必要なライブラリをインポートしておきます。

```python
import matplotlib.pyplot as plt
import glob
import cv2
```

globは特定のファイルパスを抽出してくるのによく使います。

この場合は、4238枚の画像パスを抽出するのに使います。

```python
files = glob.glob("ご自身のパス/*.jpg")
```

このようにglobを使ってあげることで特定のディレクトリ配下にあるjpgファイルのパスを全て抽出してくることができます。

<https://toukei-lab.com/glob>

```python
files = sorted(files)
print(files)
```

抽出したファイルパスを表示してみると、ちゃんとパスがリスト形式で格納されていることが分かります。

さて続いてはファイルのパスから画像を読み込む作業！

ここでOpenCVの出番です。

```python
image = cv2.imread(files[0])
```

ファイルパスの中で最初のパスの画像情報をOpenCVを使って抽出してあげます。

そうすると以下のように配列形式で画像の情報が得られます。

:::box
array(\[\[\[ 83, 109, 109], \[ 82, 108, 108], \[ 85, 109, 107], …, \[100, 141, 104], \[100, 143, 106], \[100, 144, 105]],・・・
:::

この画像を表示させてみましょう！

```python
plt.imshow(image)
```

以下のように表示されたと思います。

![image_nishika](/wp-content/uploads/2021/04/image_nishika-min.jpg)

さて改めて先程の画像情報がどんな形になっているか見てみましょう！

```python
image.shape
```

:::box
(256, 256, 3)
:::

これは256×256のピクセルの面がRGB（赤緑青）の3次元で重なっていることを表します。

通常、どんな画像もこのようにRGBの3次元で色を重ねて様々なカラーを表現しているのです。

そしてそれぞれのRGBの画素値が0\~255で表現されます。

それが先程の配列で表示された各要素になります。

:::box
array(\[\[\[ 83, 109, 109], \[ 82, 108, 108], \[ 85, 109, 107], …, \[100, 141, 104], \[100, 143, 106], \[100, 144, 105]],・・・
:::

この時、\[R255, G0, B0]であれば完全な赤になります。

それぞれRGBの3次元が重なったピクセルの集合体が画像となるのです。

:::talk{who="robotan"}
画像も数値データとして扱うことができるってことか！
:::

### OpenCVで画像を加工してみよう！

それでは先程表示した画像をOpenCVを使って加工してみましょう！

実は通常は画像はRGBの順番で重ね合わされるのですが、OpenCVで読み込んだ場合はBGRの順番で格納します。

そのため、実際の画像と色合いが変わってしまうのです。

そこで、[Matplotlib](/matplotlib)で描画する前にBGRをRGBの順番に変換してあげる必要があるのです。

```python
image = cv2.imread(files[0])
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image_gray)
```

このように変換してあげると・・・

以下のように先程の画像よりも日本絵画っぽくなったことが分かります。

![image_nishika2](/wp-content/uploads/2021/04/imaga_nishika2-min.jpg)

続いて画像のトリミングをおこなってみましょうー！

以下のように画像の要素を一部抽出してあげるだけで顔だけをトリミングして表示することができます。

```python
mage_gray2 = image_gray[50 : 200, 40: 160]
plt.imshow(mage_gray2)
```

![image_nishika3](/wp-content/uploads/2021/04/image_nishika3-min.jpg)

## 絵画の画像認識をPython×機械学習で実装する

![python](/wp-content/uploads/2019/08/Admin-amico-min-e1613730531228-1024x914.png)

続いて画像認識をPythonで実装していきましょう！

ここまでで画像の表示や画像加工についてOpenCVを使って見てきましたが、ここからは機械学習手法を使って画像認識をおこなってきます。

### データの準備

まずは必要なライブラリをインポートします。

```python
import matplotlib.pyplot as plt
import glob
import cv2
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical
```

[Keras](/keras)とはディープラーニングを簡単に実装できるライブラリです。

Kerasを使うと簡単な記述で、いとも簡単にディープラーニングを実装できるのです！

先程と同様にまずは、画像のファイルパスを抽出しそれらを昇順で並び替えます。

```python
files = glob.glob("ご自身のパス/*.jpg")
files = sorted(files)
```

その上でそれぞれのファイルの画像情報をOpenCVで読み込みリストに格納していきます。

```python
file_list = []
for file in files:
  file = cv2.imread(file)
  file_list.append(file)
```

画像データだけではなくラベルデータも同時に読み込んでおきましょう！

```python
df_label = pd.read_csv("/content/drive/MyDrive/Stabiz/python/data-science/nishika_picture/train.csv")
```

続いて得られた画像の画素値を255で割返して正規化していきます。

```python
file_list = [file.astype(float)/255 for file in file_list] 
```

画像データとラベルデータの塊を学習データと検証データに分けていきます。

```python
train_x, valid_x, train_y, valid_y = train_test_split(file_list, df_label, test_size=0.2)
```

学習データに全てのデータを使ってしまうと[過学習](/over-fitting)という問題が起きてしまうためです。

過学習とは手元の学習データだけにフィッティングしすぎて未知のデータを上手く分類できないモデルを作ってしまうことです。

続いてラベルデータをダミー変数化していきます。

```python
# train_y, valid_y をダミー変数化
train_y = to_categorical(train_y["gender_status"])
valid_y = to_categorical(valid_y["gender_status"])
```

続いて、リスト型になっている画像データを配列型に直してあげます。

```python
train_x = np.array(train_x)
valid_x = np.array(valid_x)
```

### ディープラーニングのモデル定義

ここからディープラーニングの層を作っていきます。

![3層構造のニューラルネットワーク](/wp-content/uploads/2019/06/NN-1024x364.jpg)

ディープラーニングでは入力データに対して出力データを返すためにいくつかの層を設けて重み付けを調整し最適な出力結果を出していくんです。

この層には様々なものがあるのですが、Kerasでは簡単に層構造を記述することが可能です。

```python
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(256, 256, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(8, activation='softmax'))
```

model = models.Sequential()

層の種類は以下のようになっています。

:::box
- Sequential: モデルを生成するためのモジュール
- Conv2d: 2次元畳み込み層のモジュール
- MaxPool2D: 2次元最大プーリング層のモジュール
- Dense: 全結合層のレイヤモジュール
- Activation: 活性化関数モジュール
- Dropout: ドロップアウトモジュール
- Flatten: 入力を平滑化するモジュール

（出典：<https://qiita.com/sasayabaku/items/9e376ba8e38efe3bcf79>）
:::

Sequentialでモデルを生成し、Conv2dで2次元の[畳み込み層](/cnn)を生成します。

この畳込み層が画像認識において非常に協力な効果を発揮します。

通常機械学習モデルに組み込む時は、それぞれの画像の次元を1次元に落として特徴量としてインプットしますがそうするとどうしても位置関係などの重要な情報が損失してしまいます。

畳み込み層を使うことで2次元データの画像のまま特徴量としてインプットして精度の高い画像認識モデルを作成することが可能です。

![畳み込みニューラルネットワーク](/wp-content/uploads/2022/11/ae768ca9b7bb0b5513fadcfb62689bba.jpg)

畳み込み層を使う場合は出力する前にFlatternでデータを平滑化し1次元に変換します。

### モデル構築し画像認識

さて最後にKerasで定義した層に対して画像認識モデルを構築していきます。

```python
# モデルを構築
model.compile(optimizer=tf.optimizers.Adam(0.01), loss='categorical_crossentropy', metrics=['accuracy'])

# Early stoppingを適用してフィッティング
log = model.fit(train_x, train_y, epochs=100, batch_size=10, verbose=True,
                callbacks=[keras.callbacks.EarlyStopping(monitor='val_loss', 
                                                     min_delta=0, patience=10, 
                                                         verbose=1)],
                validation_data=(valid_x, valid_y))
```

これで簡単にモデルを構築することができました。

以下が全コードです。

```python title="Keras_pic.py"
import matplotlib.pyplot as plt
import glob
import cv2
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical

#データ準備
files = glob.glob("自分のディレクトリ/*.jpg")
files = sorted(files)
df_label = pd.read_csv("自分のディレクトリ/train.csv")

file_list = []
for file in files:
  file = cv2.imread(file)
  file_list.append(file)

#画素値を正規化
file_list = [file.astype(float)/255 for file in file_list] 
train_x, valid_x, train_y, valid_y = train_test_split(file_list, df_label, test_size=0.2)

# train_y, valid_y をダミー変数化
train_y = to_categorical(train_y["gender_status"])
valid_y = to_categorical(valid_y["gender_status"])

# リスト型を配列型に
train_x = np.array(train_x)
valid_x = np.array(valid_x)

#層の定義
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(256, 256, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(8, activation='softmax'))

# モデルを構築
model.compile(optimizer=tf.optimizers.Adam(0.01), loss='categorical_crossentropy', metrics=['accuracy'])

# Early stoppingを適用してフィッティング
log = model.fit(train_x, train_y, epochs=100, batch_size=10, verbose=True,
                callbacks=[keras.callbacks.EarlyStopping(monitor='val_loss', 
                                                     min_delta=0, patience=10, 
                                                         verbose=1)],
                validation_data=(valid_x, valid_y))
```

ぜひ層構造を変えてみて色々試してみてください！

## おまけ：文字の画像認識をPythonで実装する

![pc python](/wp-content/uploads/2019/08/Work-time-amico-min-e1613688546361-1024x875.png)

さて続いては文字の画像認識に取り組んでみましょう！

先程は絵画だったのですが、文字の画像認識も出来ます。

画像認識タスクのチュートリアルによく用いられる[Mnist](/mnist)という手書きの画像データを使っていきます。

Mnistは**Mixed National Institute of Standards and Technology database**の略で、手書き数字画像60,000枚とテスト画像10,000枚を集めた、画像データセット。

0～9の手書き数字が教師ラベルとして各画像に与えられています。

1つ1つの画像は、**文字画像をタテヨコ28×28のピクセルに分け、1つのピクセルあたり0～255の数値で白黒のスケール**を表します。

先程はRGBの3次元だったのですが、Mnistのデータは白黒スケールの1次元になります。

以下のように実装していきます。

```python title="cnn_mnist.py"
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow import keras
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical

# Kerasに付属の手書き数字画像データをダウンロード
np.random.seed(0)
(X_train_base, labels_train_base), (test_x, test_y) = mnist.load_data()

# Training set を学習データと検証データに8:2で分割する
train_x, valid_x, train_y, valid_y = train_test_split(X_train_base, labels_train_base, test_size = 0.2)

# 各画像のShapeを整形
train_x = train_x.reshape((48000, 28, 28, 1))
valid_x = valid_x.reshape((12000, 28, 28, 1))
test_x = test_x.reshape((10000,28,28,1))


#正規化
train_x = np.array(train_x).astype('float32')
valid_x = np.array(valid_x).astype('float32')
test_x = np.array(test_x).astype('float32')
train_x /= 255
valid_x /= 255
test_x /= 255

# train_y, valid_y をダミー変数化
train_y = to_categorical(train_y)
valid_y = to_categorical(valid_y)


model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

# モデルを構築
model.compile(optimizer=tf.optimizers.Adam(0.01), loss='categorical_crossentropy', metrics=['accuracy'])

# Early stoppingを適用してフィッティング
log = model.fit(train_x, train_y, epochs=100, batch_size=10, verbose=True,
                callbacks=[keras.callbacks.EarlyStopping(monitor='val_loss', 
                                                     min_delta=0, patience=10, 
                                                         verbose=1)],
                validation_data=(valid_x, valid_y))

# テストデータの出力から0~9のどの値か判断
pred_test = np.argmax(model.predict(test_x), axis=1)
sum(pred_test == test_y)/len(pred_test)
```

基本的な流れは先程と変わりません。

データを学習データと検証データに分けて、画素値を正規化してあげて、その上でKerasでモデル構築をおこなっていきます。

この手書き文字が28×28×1のデータなので、畳み込み層へのインプットの際に以下のようになっていることに注意しましょう！

```python
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
```

また最後の出力層では、0\~9の10種類の文字なので以下のように出力カテゴリが10になっていることに注意しましょう！

```python
model.add(layers.Dense(10, activation='softmax'))
```

## 画像認識をPythonで実装　まとめ

ここまでで画像認識をPythonで実装しながら簡単に解説してきました！

:::talk{who="robotan"}
画像認識の世界がすごい具体的に分かってきたよー！
:::

:::talk{who="umatan"}
画像認識の世界はまだまだこれからだ！
:::

ここで取り上げた内容は本当に一部の情報で、まだまだ画像認識の世界は非常に深いです。

ぜひご自身で色々調べてみてくださいね！

:::talk{who="umatan"}
画像認識やディープラーニングについては当メディアが運営する「[スタアカ](https://toukei-lab.com/achademy/)」というサービスの「**[ディープラーニングコース](https://toukei-lab.com/achademy/?sfwd-courses=deep-learning)**」でも詳しく解説しているので是非参考にしてみてね
:::

:::box
**[業界最安級AIデータサイエンス特化スクール：スタアカ（スタビジアカデミー）](https://toukei-lab.com/achademy/)\&#xA;**
:::

[![スタアカトップ](/wp-content/uploads/2021/11/2bc9f22d0f8dfe24080b83884b7a5ec6-1024x576.jpg)](https://toukei-lab.com/achademy/)

Pythonの勉強法やデータサイエンティストへの勉強法については以下の記事で解説していますのでぜひチェックしてみてください！

<https://toukei-lab.com/python-learn>

<https://toukei-lab.com/data-scientist>