Python3 – NumpyとPythonの配列のスライスでマイナス使った場合

  • 開始位置より終了位置が小さい場合は空。
  • マイナスの場合、後ろから数える。一番最後が-1。
  • 終了位置が実際の配列の最後より大きい場合は、実際の配列の最後になる。
  • 開始位置は0だったら0番目も含まれるが、終了位置が例えば10だった場合、9番目までが含まれる。
  • 終了位置が-1だったら、-2までが含まれる。

コード

a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
print('numpy array')
print(a[-1 : 3])
print(a[0 : 3])
print(a[-1 : 100])
print(a[1 : 100])
print(a[-1])
print(a[-2])
print(a[-3 : 10])
print(a[-3 : -1])
print()

b = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print('python array')
print(b[-1 : 3])
print(b[0 : 3])
print(b[-1 : 100])
print(b[1 : 100])
print(b[-1])
print(b[-2])
print(b[-3 : 10])
print(b[-3 : -1])

結果

numpy array
[]
[1 2 3]
[9]
[2 3 4 5 6 7 8 9]
9
8
[7 8 9]
[7 8]

python array
[]
[1, 2, 3]
[9]
[2, 3, 4, 5, 6, 7, 8, 9]
9
8
[7, 8, 9]
[7, 8]

Numpy – reshape

np.reshapeがややこしいので試してみる。

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6])
print(a)
b = np.reshape(a, (2, 3))
print(b)

[1 2 3 4 5 6]
[[1 2 3]
[4 5 6]]

配列aを、2行3列に変換しろ!といっております。試しに(2, 4)とか、(2, 2)とかでやってみましたがエラーになりました。ちょうどいい数字になってないとエラーになるようです。

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6])
print(a)
b = np.reshape(a, (2, 3))
print(b)
b[0][0] = 10
print(a)
print(b)

[1 2 3 4 5 6]
[[1 2 3]
[4 5 6]]
[10 2 3 4 5 6]
[[10 2 3]
[ 4 5 6]]

bの要素を変えるとaも変わります。bはaの参照を持っているということでしょうか?なんか不思議です。

c = a.reshape(3, 2)
print(c)

上記のような書き方もできます。np.arrayには、reshapeというのがついてるようです。
cもbもaの参照を持っているようです。参照を持ちつつ形を変えております。numpyの配列は高機能です。

e = c.reshape(1, -1)
print(e)

上記のように-1を使うと、これは「おまかせ」ってことになります。
分からないからよきにはからえと伝えております。例えば、[1, 10, 4, 2, …..]といった感じの1次元配列があり、5個ずつ配列を分けたいというときは、(-1, 5)とやります。?行5列となりますので、5列ずつの配列をどんどんつくっていけということになります。ただ、ここで大本の配列の要素数が5で割り切れない場合は、エラーになるのか確かめてみます。

e = c.reshape(-1, 4)
print(e)

cはaの要素数6の1次元配列の参照を持っております。4列ずつに分けろと言われてもやはり無理だったようです。当然(-1, 3)であれば成功します。

Python – NumPyで画像を配列として取得する

from PIL import Image
from numpy import *

im  = array(Image.open('img.jpg').convert('L'))
print(im.shape, im.dtype)
print(im)

(533, 800) uint8
[[156 159 162 …, 135 132 130]
[156 155 155 …, 133 132 133]
[155 153 155 …, 134 133 131]
…,
[ 87 88 85 …, 71 71 70]
[ 86 87 87 …, 70 72 73]
[ 89 95 95 …, 74 73 73]]

と表示される。最初の行のタプルは、(行数、列数、色数)を表してる。上記はグレースケールに変換しており、その場合は、色数は表示されない。uint8は、要素のデータ型。通常、画像は符号なし8ビット整数で符号化されるらしい。im自体を出力したら上記のような配列が表示された。

im  = array(Image.open('img.jpg'))
print(im.shape, im.dtype)

これだとグレースケール変換していないので、下記のように色数も表示される。赤、緑、青という並びなんだろうか。
(533, 800, 3) uint8

im  = array(Image.open('img.jpg'))
print(im)

これだと、色が3色があるので、配列は下記のようになっている。

[[[150 156 178]
[153 159 181]
[154 162 183]
…,
[121 137 163]
[119 134 163]
[116 131 162]]

[[148 156 177]
[149 155 177]
[149 155 177]
…,
[119 135 161]
[118 134 160]
[119 134 165]]

[[147 155 176]
[147 153 175]
[149 155 177]
…,
[120 136 162]
[119 135 161]
[118 132 167]]

…,
[[ 88 88 86]
[ 88 89 84]
[ 86 86 84]
…,
[ 72 71 76]
[ 72 71 76]
[ 71 70 75]]

[[ 87 87 85]
[ 87 88 83]
[ 88 88 86]
…,
[ 69 70 74]
[ 71 72 76]
[ 72 73 77]]

[[ 91 90 86]
[ 97 96 92]
[ 96 95 93]
…,
[ 73 74 78]
[ 72 73 77]
[ 72 73 77]]]

色を反転させて保存する

これはhtmlでつかってる0-255の数字と一緒であります。各数値を255から引くことで色を反転させることができます。

from PIL import Image
from numpy import *

im  = array(Image.open('img.jpg'))
Image.fromarray(255 - im).save('img2.jpg')

下記のようになりました。

img2

配列から画像を作ってみる

下記のようにすると、白から黒に向けたグラデーションになる。[赤、緑、青]なので、赤を全部0にすると、青緑の薄いから濃いのグラデーションになる。

from PIL import Image
import numpy as np

a = np.array([
    [
        [230,230,230],[210,210,210],[190,190,190],[170,170,170],[150,150,150]
    ],
    [
        [230,230,230],[210,210,210],[190,190,190],[170,170,170],[150,150,150]
    ],
    [
        [230,230,230],[210,210,210],[190,190,190],[170,170,170],[150,150,150]
    ],
    [
        [230,230,230],[210,210,210],[190,190,190],[170,170,170],[150,150,150]
    ],
    [
        [230,230,230],[210,210,210],[190,190,190],[170,170,170],[150,150,150]
    ],
])

Image.fromarray(np.uint8(a)).save('img2.jpg')

for row in a:
    for col in row:
        col[0] = 0

Image.fromarray(np.uint8(a)).save('img3.jpg')

img2.jpg
img2

img3.jpg
img3