「ゼロから作るDeep Learning」(斎藤 康毅 著 オライリー・ジャパン刊)を読んでいる時に、参照したサイト等をメモしていきます。 その19 ← → その20
前回は、Data Augmentation 用の画像を Pillow で加工しましたが、ライブラリを使わずに加工してみようかと思います。
##左右反転
import numpy as np
import math
import matplotlib.pyplot as plt
def flip_img(img):
return img[:, ::-1, :]
画像をnp.arrayにして、x軸の項目を ::-1 として反転させるだけ。
##移動
def trans_horiz_img(img, r=0.1):
h, w, c = img.shape
imgr = np.zeros_like(img)
wr = int(w*r)
if wr>0:
imgr[:, wr:, :] = img[:, :w-wr, :]
else:
imgr[:, :w+wr, :] = img[:, -wr:, :]
return imgr
def trans_vert_img(img, r=0.1):
h, w, c = img.shape
imgr = np.zeros_like(img)
hr = int(h*r)
if hr>0:
imgr[hr:, :, :] = img[:h-hr, :, :]
else:
imgr[:h+hr, :, :] = img[-hr:, :, :]
return imgr
def trans_img(img, rw=0.1, rh=0.1):
imgr = trans_vert_img(img, rh)
imgr = trans_horiz_img(imgr, rw)
return imgr
これも配列の要素を移動させただけ。
##回転
三角関数を使って回転させてみた。
import math
def rotate_img(img, deg=30):
imgr = np.zeros_like(img)
rad = - math.radians(deg) # 頭の - は、座標系のy軸を調整
mc=math.cos(rad)
ms=math.sin(rad)
h, w, c = img.shape
h0 = h/2
w0 = w/2
for i in range(h):
y=i-h0
for j in range(w):
x=j-w0
x2 = int(x*mc - y*ms + w0)
y2 = int(y*mc + x*ms + h0)
if(x2>=0 and x2<w and y2>=0 and y2<h):
imgr[y2, x2, :] = img[i, j, :]
return imgr
imgR=rotate_img(img, -30)
fig = plt.figure(figsize=(40, 40))
im = fig.add_subplot(1, 8, 1)
im.imshow(imgR, cmap=plt.cm.binary)
座標を変換するときの端数処理で、へんな模様ができてしまいました。
それらしく変換できればいいということなら、こういった姑息なやりかたでも、90度未満の回転なら、それらしくなります。
def rotate_img(img, deg=30):
imgr = np.zeros_like(img)
rad = - math.radians(deg) # 頭の - は、座標系のy軸を調整
mc=math.cos(rad)
ms=math.sin(rad)
h, w, c = img.shape
h0 = h/2
w0 = w/2
for i in range(h):
y=i-h0
for j in range(w-1):
x=j-w0
x2 = int(x*mc - y*ms + w0)
y2 = int(y*mc + x*ms + h0)
if(x2>=0 and x2<w-1 and y2>=0 and y2<h):
imgr[y2, x2, :] = img[i, j, :]
imgr[y2, x2+1, :] = img[i,j+1, :] #角度を無視して、右隣の点を右隣にコピーしただけ
return imgr
さすがに、ちゃんとした説明と方法もQiitaにはあります。
三角関数、何に使うの? 画像の回転処理と行列
ちゃんとした説明があったので、穴が空かない方法で作り直してみました。
def rotate_img(img, deg=30):
imgr = np.zeros_like(img)
rad = math.radians(deg)
mc = math.cos(rad)
ms = math.sin(rad)
h, w, c = img.shape
h0 = h/2
w0 = w/2
# x , y は、回転後の画像の座標
# x0, y0は、画像中心を原点にするように変換した x,y
for y in range(h):
y0 = y - h0
for x in range(w):
x0 = x - w0
xx = int(x0*mc - y0*ms + w0) # xx は回転前の x座標
yy = int(y0*mc + x0*ms + h0) # yy は回転前の y座標
if(xx>=0 and xx<w and yy>=0 and yy<h):
imgr[y, x, :] = img[yy, xx, :]
return imgr
##拡大縮小
まず、配列を resize する関数を作りました。
def resize_img(img, wr, hr): # 画像とリサイズ後の横と縦のサイズを指定
h, w, c = img.shape
rw = wr / w
rh = hr / h
imgr = np.zeros((hr,wr,3), dtype=int)
# x , y は、リサイズ後の画像の座標
for y in range(hr):
y0 = int(y / rh) # y0 , y1 は、リサイズ前の y 座標
dy = y/rh - y0
y1 = y0 + 1
if y1>=h:
y1=y0
for x in range(wr):
x0 = int(x / rw) # x0 , x1 は、リサイズ前の x 座標
dx = x/rw - x0
x1 = x0 + 1
if x1>=w:
x1=x0
imgr[y,x,:]=img[y0,x0,:]*(1-dx)*(1-dy) \
+ img[y1,x0,:]*(1-dx)*dy \
+ img[y0,x1,:]*dx*(1-dy) \
+ img[y1,x1,:]*dx*dy
return imgr
リサイズ後の配列の画素が、リサイズ前の配列のどの点と点の間にあるかを判定し、その前後の点の値で線形補間して、セットしています。
このサイトを参考にしました。
C言語で画像の拡大縮小(線形補間編)
次に、拡大した画像の中央から、元画像と同じ大きさの分を切り出す関数を作りました。
def cropp_img(img, rw = 1.2, rh = 1.4): # 画像と拡大率を指定
imgr = np.zeros_like(img)
h, w, c = img.shape
wr = int(w * rw)
hr = int(h * rh)
imgRS = resize_img(img, wr, hr)
if rw>1:
ws = int((wr - w)/2)
we = ws + w
rws = 0
rwe = w
else:
ws = 0
we = wr
rws = int((w - wr)/2)
rwe = rws + wr
if rh>1:
hs = int((hr - h)/2)
he = hs + h
rhs = 0
rhe = h
else:
hs = 0
he = hr
rhs = int((h - hr)/2)
rhe = rhs + hr
imgr[rhs:rhe,rws:rwe,:] = imgRS[hs:he,ws:we,:]
return imgr
実行結果
import numpy as np
import math
import matplotlib.pyplot as plt
img = dataset['train_img'][1] # np.array
imgC = cropp_img(img, 1.3, 1.5)
imgF = flip_img(img)
imgR = rotate_img(img, -30)
imgH = trans_horiz_img(img,0.2)
imgV = trans_vert_img(img, -0.1)
imgT = trans_img(img, 0.1, 0.1)
fig = plt.figure(figsize=(20, 20))
im = fig.add_subplot(1, 8, 1)
im.imshow(img, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 2)
im.imshow(imgC, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 3)
im.imshow(imgF, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 4)
im.imshow(imgR, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 5)
im.imshow(imgH, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 6)
im.imshow(imgV, cmap=plt.cm.binary)
im = fig.add_subplot(1, 8, 7)
im.imshow(imgT, cmap=plt.cm.binary)
pillow を使えばできることを、わざわざ自分でプログラミングする必要はないのですが、三角関数を思い出せたし、アルゴリズムの勉強にもなりました。
Kaggleの猫と犬のデータセットについては、その6の2
メモの目次等はこちらから 読めない用語集