[:x] Ndarrayや配列における、thresholdの考え方。

今回は、thresholdの操作を紹介します。
(正式な呼称なのか知らない…)

使用目的は、データの分割や、データの一部を抽出するときのために使います。
実際の式変形を見てみましょう。

a = np.arange(24)

a = np.arange(24)
print(a)

threshold = 10

b = a[:threshold]
print(b)
c = a[threshold:]
print(c)

#a
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
#b
[0 1 2 3 4 5 6 7 8 9]
#c
[10 11 12 13 14 15 16 17 18 19 20 21 22 23]

numpyで0~23の数字が格納されたndarray型のデータを作成しました。
b, c, では、コロンがついている場所が違います。

b –> [:threshold] #thresholdよりも左側のデータ
[0 1 2 3 4 5 6 7 8 9]

c –> [threshold:] #thresholdよりも右側のデータ
[10 11 12 13 14 15 16 17 18 19 20 21 22 23]

続いて、画像データで見てみましょう。
画像が3枚、480×640のサイズ、3チャンネル(RGB)の画像が格納されたsumImageデータがあるとします。

sumImage.shape
#(3, 480, 640, 3)

それでは、sumImageデータを基にしてthresholdでのデータ分割、抽出の方法を見ていきましょう。

sumImage.shape[:1]
#(3)

(3, 480, 640, 3)の中で、1つ目のデータのみをデータ抽出しています。
※画像データが移行された訳ではない。shapeの情報を参照しているのみ。

cc = sumImage.shape[:3]
#(3, 480, 640)

同じく、3つ目よりも前の情報を取得しています。

bb = sumImage.shape[-3:]
#(480, 640, 3)

マイナスを使うことが出います。
マイナスは後ろから、という指定です。

では、shapeの情報だけではなく、画像データも分割、抽出することが出来るのでしょうか。

ff = sumImage[1:]
gg = ff.shape
#(2, 480, 640, 3)

1つ目以降の画像データ、2つ目と3つ目の画像データを含む(2, 480, 640, 3)が抽出されました。

画像データを正規化。Numpyの高次元配列のデータ型を変更

画像読み込むと、0~255階調のデータになっているのを、0~1のデータへ正規化していきます。

まずは、Numpyのデータ型の確認方法です。
dtype属性で確認します。
trainingDataというndarray型の配列の場合

trainingData.dtype

unit8

など表示されます。

0~1のデータは、floatデータです。
floatデータ型に変換しつつ、0~1に変換します。

astype メソッドを使います。
配列の中のデータを丸っとキャストすることが出来ます。

trainingData.astype(np.float32) / 255

これで、0~255階調のデータになっているのを、0~1のデータへ正規化できます。

GANでデータセットを作るために、Numpyのreshapeを使う方法

画像pngデータを活用して、データセットを作るために必要だったreshapeの使い方を紹介したいと思います。(違うやり方もあると思います。)

以前、reshapeの基本的な使い方は下記で記載しました。

本記事の操作としては、下記記事で作成したデータセットを基に話を進めていきます。

画像データは、1つの画像に対して、( 350 × 350 ) の配列に格納された画像データが生成出来ました。

しかし、機械学習をしていく際に、
1つの画像が1つのndarray型に入っている必要があります。

(もしかしたら、行と列が別々の配列でも良い可能性がありますが、今のところ学習させる際には、1つの画像が、1つの配列に入っている方がススメやすいと思います。)

もう少し説明します。
上記で作ったデータを見ていきます。

training_data.shape

(3, 350, 350)

3枚の画像が、350×350のサイズデータとして存在している。ということですね。

機械学習していく際には、( 画像個数, X )といったデータ型にする必要があります。
ここで Numpy reshapeを使います。
※X = 1次元の画像データ

batchdata = training_data.reshape(3,122500)
#122500 = 350 × 350
batchdata.shape

(3, 122500)

こういったカタチで、機械学習する際に必要なデータ型になりました。

このデータって、変換されてしまったら画像データとして存在しないのでは?と思うかもしれません。確認してみましょう。

一度、reshapeして、変換したデータを、元に戻してみます。

batchReverse = batchdata.reshape(3,350, 350)

for p in batchReverse:
  plt.imshow(p, cmap="gray")
  plt.show()

実行してみると、元の画像が表示されます。

ここで、疑問なのは、データの変換される順番とかが決まっているのか?
ということです。
いま試してみたのは、同じ操作をもとに戻しただけですが、これが複雑な操作の後に、戻そうと思った際に、どうなるのか。疑問は深まるばかりです。

Google Colaboratory で 画像データを読み込んでデータセットを作る方法

Google Colaboratory便利ですね。
Google Colaboratoryで、データセットを作成したく、色々と試してみました。

正直、これで良いのかまだ、不明なところがあるのですが、ひとまず、紹介です。
やることをざっくりと分けると、下記フローでした。

(1):画像データ一覧をZipファイルに圧縮
(2):ZipファイルをGoogle Colaboratoryへアップロード
(3):Google Colaboratoryで、zipファイルを解凍
(4):Zipファイル内の画像データのファイルパス一覧を取得
(5):画像のFilePathを個別に取得
(6):画像データをNumPy配列ndarrayとして取得
(7):画像のリサイズ
(8):NumPy配列ndarrayとして、データセットとして保存

(1):画像データ一覧をZipファイルに圧縮

これは、普通にやってください。
※犬の画像を3枚取得して。ファイル名を(a.png, b.png, c.png)としました。
※Zipファイル名をdataset_vol2.zipとしました

(2):ZipファイルをGoogle Colaboratoryへアップロード

ZipファイルをGoogle Colaboratoryへアップロードします。
Colaboratoryファイルの、左部を開くとアップロードという箇所があるので、ここから、zipファイルをアップロードします。

(3):Google Colaboratoryで、zipファイルを解凍

Colaboratoryで、Zipファイルを解凍する際はZipファイルがある場所まで移動しましょう。
まずは、自分が何処の階層にいるのかを確認しましょう。

!ls

dataset_vol2.zip
sample_data

dataset_vol2.zip がある階層です。
それでは、解凍していきましょう。
解凍するコマンドは、!unzip です。

!unzip dataset_vol2.zip

Archive: dataset_vol2.zip
creating: dataset_vol2/
inflating: dataset_vol2/b.png
creating: __MACOSX/
creating: __MACOSX/dataset_vol2/
inflating: __MACOSX/dataset_vol2/._b.png
inflating: dataset_vol2/c.png
inflating: __MACOSX/dataset_vol2/._c.png
inflating: dataset_vol2/a.png
inflating: __MACOSX/dataset_vol2/._a.png

これで、Zipファイルが解凍されました。

(4):Zipファイル内の画像データのファイルパス一覧を取得

解凍したファイルの中へ移動していきましょう。

#ファイル移動
%cd dataset_vol2
!ls

a.png b.png c.png

(5):画像のFilePathを個別に取得

必要なライブラリをimportします。

import matplotlib.pyplot as plt
import os
import cv2
import glob
import numpy as np

フォルダの中のファイルPath一覧を取得する方法として、
Pythonのglobモジュールを活用しました。 詳しくは、下記を参考にしてます。
ワイルドカード(*)などを使って柔軟にFilePathを取得できるので、便利ですね。

Pythonで条件を満たすパスの一覧を再帰的に取得するglobの使い方
https://note.nkmk.me/python-glob-usage/

また、現在位置は、dataset_vol2の中にいるので、
このままでも問題ないですが、globを使う際には、取得したいファイルの中に移動してあげるのがいいでしょう。

そのために、コマンドじゃなく、ファイル階層を移動できる下記を使いました。
os.chdir(“Path名称”)

#階層移動
os.chdir("/content/dataset_vol2")
#階層内のPathを全取得
path = glob.glob("*")
print(path)

[‘a.png’, ‘c.png’, ‘b.png’]

もちろん、今回はファイル名を(a.png, b.png, c.png)にしたので、
当たり前の結果ですが、データ個数が多くなれば必要な作業です。

(6):画像データをNumPy配列ndarrayとして取得
(7):画像のリサイズ
(8):NumPy配列ndarrayとして、データセットとして保存

ここからは、一気にデータセット作成までいきましょう。

#データセットを格納する変数
training_data = []
#リサイズ後のサイズ
IMG_SIZE = 350

#個別のFilePathに対して処理していきます。
for p in path:
   pathEach = p
   print(pathEach)

  #NumPy配列ndarrayとして読み込まれ、ndarrayを画像として保存
   imageTTTT = cv2.imread(pathEach,cv2.IMREAD_GRAYSCALE)
  #画像のりサイズ
   img_resize_array = cv2.resize(imageTTTT, (IMG_SIZE, IMG_SIZE))
   print(imageTTTT)
   print(img_resize_array.dtype)
   training_data.append(img_resize_array)
   plt.imshow(img_resize_array, cmap="gray")
   plt.show()
   print("=============")

cv2.imreadを解説します。
OpenCVライブラリでは、様々なことができます。
imreadメソッドで、画像ファイルを読み込み、
NumPy配列ndarrayとして読み込まれ、ndarrayを画像として保存することができます。

ndarray型については、下記記事にも書きましたので参照下さい。
Numpyのarray・ndarrayって何。 簡単に説明します。
http://prglog.info/home/?p=29

imreadの詳細については、下記参考

▼Python, OpenCVで画像ファイルの読み込み、保存
https://note.nkmk.me/python-opencv-imread-imwrite/

print(training_data)

[array([[ 36, 36, 36, …, 191, 193, 193],
[ 36, 36, 36, …, 191, 192, 192],
[ 36, 36, 36, …, 190, 190, 190],
…,
[223, 221, 220, …, 225, 226, 228],
[225, 223, 222, …, 226, 228, 230],
[227, 225, 224, …, 228, 230, 232]], dtype=uint8), array([[ 84, 83, 82, …, 29, 27, 27],
[ 93, 92, 91, …, 34, 33, 32],
[102, 102, 101, …, 38, 37, 36],
…,
[126, 117, 110, …, 128, 133, 121],
[123, 117, 116, …, 134, 138, 127],
[119, 118, 122, …, 138, 142, 132]], dtype=uint8), array([[158, 158, 158, …, 142, 144, 147],
[158, 158, 158, …, 144, 146, 148],
[158, 158, 157, …, 146, 148, 149],
…,
[211, 208, 208, …, 212, 212, 211],
[219, 217, 217, …, 208, 207, 206],
[224, 223, 223, …, 205, 203, 203]], dtype=uint8)]

ここで、完了かなと思います。
ただ、他の記事を見てみると、ここからarrayメソッドを使って、ndarray型にデータを変換していたりします。

training_data = np.array(training_data)
print(training_data)

[[[ 36 36 36 … 191 193 193]
[ 36 36 36 … 191 192 192]
[ 36 36 36 … 190 190 190]

[223 221 220 … 225 226 228]
[225 223 222 … 226 228 230]
[227 225 224 … 228 230 232]]

[[ 84 83 82 … 29 27 27]
[ 93 92 91 … 34 33 32]
[102 102 101 … 38 37 36]

[126 117 110 … 128 133 121]
[123 117 116 … 134 138 127]
[119 118 122 … 138 142 132]]

[[158 158 158 … 142 144 147]
[158 158 158 … 144 146 148]
[158 158 157 … 146 148 149]

[211 208 208 … 212 212 211]
[219 217 217 … 208 207 206]
[224 223 223 … 205 203 203]]]

これで、ndarray型のデータが出来上がったということなのでしょうか。
ここは少し理解が浅いところですので、調べてみます。

Numpyのarray・ndarrayって何。 簡単に説明します。

機械学習で必ず使う、Numpy。
ndarray, arrayなど混合してしまったり、Pythonのlist [a, b, c, d, e]とかと違うのか。
などなど、よく分からないことが多いと思います。

正確なことは、下記に詳細が記載されております。
分かりますでしょうか? 私は、全くわかりませんでした。

■numpy.ndarray
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html

■numpy.array
https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html

簡単に言いますと
ndarray:
Numpyの高次元配列を扱うことが可能なクラス

array:
ndarray のクラス型をしたオブジェクトをreturnする、関数

ということです。
全く、性質が異なるものですね。

詳しいことは、下記のサイトに色々と載ってます。
是非、一度見てみるといいと思います。

http://www.kamishima.net/mlmpyja/nbayes1/ndarray.html

arrayで生成するndarrayのオブジェクトと、Python配列のListは違うものなのでしょうか。実験してみましょう。

#listを準備
z = [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]
#ndarray型のオブジェクト生成
nz = np.array(z)
print(nz)
print(z)

#print(nz)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
#print(z)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

#print(nz)で出力した値は、ndarray型のオブジェクトです。
#print(z)で出力した値は、Pythonの配列 list、そのままです。

arrayの引数にデータ(z)を入れたことで、ndarray型のオブジェクトが出来上がりました。

確認してみましょう。
ndarray型のオブジェクトは、shape属性を持ちます。(配列の型を示す)

print(nz.shape)
print(z.shape)

#print(nz.shape)
(12,)
#print(z.shape)
AttributeError: ‘list’ object has no attribute ‘shape’

あたりまえですね。
Pythonの配列 list は、shape属性を持ち合わせて無いということです。

Numpyでreshapeを簡単に使う方法

Numpyのメソッドであるreshapeを、簡単に使ってみたいと思います。

reshapeメソッドとは、
Numpyで扱う高次元配列のカタチを変形できるメソッドです。

reshapeを使う際の注意点など細かくあります。
詳細は下記を参考して下さい。

https://note.nkmk.me/python-numpy-reshape-usage/
https://www.sejuku.net/blog/69254#npreshape

難しいことは横においておいて、
とにかく、簡単に、reshapeを使って、感覚を掴んでみたいと思います。

まずは、データを用意します。

# numpyをimport
import numpy as np

# データを作成
a = np.arange(24)
print(a)
print(a.shape)

#データ内容
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
#データのカタチ
(24,)

reshapeを使って配列のカタチを変形します。
下記のように、4×6の配列に変形しました。

b = np.reshape(a, (4,6))
print(b)
print(b.shape)

#データ内容
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]]
#データのカタチ
(4, 6)

続いて、上記で変形したbを、再度変形します。
現状の配列のカタチを気にせず、新しいカタチを作ることが出来ました。

c = np.reshape(b, (3, 8))
print(c)
print(c.shape)

#データ内容
[[ 0 1 2 3 4 5 6 7]
[ 8 9 10 11 12 13 14 15]
[16 17 18 19 20 21 22 23]]
#データのカタチ
(3, 8)

更に、上記で変形したbを、再度変形します。
次元を1つ増やした配列が出来ました。

d = np.reshape(c, (3, 4, 2))
print(d)
print(d.shape)

#データ内容
[[[ 0 1] [ 2 3] [ 4 5] [ 6 7]]
[[ 8 9] [10 11] [12 13] [14 15]]
[[16 17] [18 19] [20 21] [22 23]]]
#データのカタチ
(3, 4, 2)