LoginSignup
1
0

More than 3 years have passed since last update.

「ゼロから作るDeep Learning」自習メモ(その19の2)Data Augmentation 続き

Last updated at Posted at 2021-01-06

「ゼロから作る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)

2-4.jpg

座標を変換するときの端数処理で、へんな模様ができてしまいました。
それらしく変換できればいいということなら、こういった姑息なやりかたでも、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

2-5.jpg

さすがに、ちゃんとした説明と方法も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

2-6.jpg

拡大縮小

まず、配列を 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)

p-192.jpg

pillow を使えばできることを、わざわざ自分でプログラミングする必要はないのですが、三角関数を思い出せたし、アルゴリズムの勉強にもなりました。
Kaggleの猫と犬のデータセットについては、その6の2

その19 ← → その20

メモの目次等はこちらから 読めない用語集

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0