トップページ -> 実践知識 -> 画像分類、物体検出 -> 一般物体検出(pierluigiferrari/ssd_keras の SSD を使用)を行ってみる
[サイトマップへ]

一般物体検出(pierluigiferrari/ssd_keras の SSD を使用)を行ってみる

サイト構成 連絡先,業績など 実践知識 データの扱い コンピュータ 教材 サポートページ

前準備

Python, 主要パッケージ, OpenCV, git のインストール

Python のパッケージで必要なものは、numpy, OpenCV, Tensorflow, matplotlib, pillow, sciklit-learn です

以下,Windows でインストール済みであるものとして説明を続ける.


必要な Python パッケージのインストール

  1. Window でコマンドプロンプトを実行

  2. (オプション)もし、virtualenv のPython 仮想環境にインストールしていて、そこにインストールしたいとき、それを有効化する

    ※ 「workon ai」は、名前が ai の Python 仮想環境の使用を開始するためのコマンド. virtualenv のPython 仮想環境を有効化したいときに限る(「ai」のところは、Python仮想環境の名前に変えること)

    workon ai
    

  3. imageio tqdm beautifulsoup4 のインストール
    pip install -U imageio tqdm beautifulsoup4
    

この Web ページで説明のために使用する画像

https://github.com/opencv/opencv/tree/master/samples/data で公開されている fruits.jpg, home.jpg を使うことにします (感謝)

  1. まず、C:\image のような作業用のディレクトリ(フォルダ)を作る

  2. 次の Web ページを開く

    https://github.com/opencv/opencv/tree/master/samples/data

  3. fruits.jpg を選ぶ

  4. クリックしたら、ダウンロード画面に変わるので「Download」をクリック.

  5. 画像ファイルを、C:\image の下に保存

  6. 今度は、home.jpg を選ぶ

  7. クリックしたら、ダウンロード画面に変わるので「Download」をクリック.

  8. 画像ファイルを、C:\image の下に保存

  9. 今度は、次の画像ファイルを、C:\image の下に保存

  10. 次のようになる


物体検出(SSD を使用)を行ってみる

SSD の原論文 (https://arxiv.org/abs/1512.02325) では VGG-16 を使用.

https://github.com/pierluigiferrari/ssd_keras では SSD のプログラム、 Pascal VOC2007, Pascal VOC2012, COCO, ILSVRC を用いての学習済みニューラルネットワークの重みデータが配布されている

Pascal VOC2007, Pascal COC2012 は、画像約10000個と、それぞれ20種類のラベルのデータである

準備

  1. Window でコマンドプロンプトを実行

  2. (オプション)もし、virtualenv のPython 仮想環境にインストールしていて、そこにインストールしたいとき、それを有効化する

    ※ 「workon ai」は、名前が ai の Python 仮想環境の使用を開始するためのコマンド. virtualenv のPython 仮想環境を有効化したいときに限る(「ai」のところは、Python仮想環境の名前に変えること)

    workon ai
    

  3. pierluigiferrari/ssd_keras のインストール
    mkdir c:\pytools
    cd c:\pytools
    rmdir /s /q ssd_keras
    

    cd c:\pytools
    git clone https://github.com/pierluigiferrari/ssd_keras
    

  4. COCO を用いての学習済みニューラルネットワークの重みデータをダウンロード

    ファイル名は、 VGG_coco_SSD_300x300_iter_400000.h5

    1. Web ページを開く

      https://github.com/pierluigiferrari/ssd_keras

    2. 「COCO models:」の下の「SSD300*」をクリック

    3. ファイル VGG_coco_SSD_300x300_iter_400000.h5 をダウンロードし、 C:\pytools\ssd_keras に置く

  5. Pascal VOC2007, Pascal VOC2012 を用いての学習済みニューラルネットワークの重みデータをダウンロード

    ファイル名は、 VGG_VOC0712_SSD_300x300_iter_120000.h5

    1. Web ページを開く

      https://github.com/pierluigiferrari/ssd_keras

    2. 「07+12」の右の「SSD300*」をクリック

      このWebページの下の方にある

    3. ファイル VGG_VOC0712_SSD_300x300_iter_120000.h5 をダウンロードし、 C:\pytools\ssh_keras に置く

以上で準備ができた


物体検出してみる

謝辞:https://github.com/pierluigiferrari/ssd_keras/blob/master/ssd300_inference.ipynb に記載のプログラムを使用している

  • Python プログラムを動かす

    そのために, PyCharmなどにある Python コンソールを使う

    COCO を用いての学習済みニューラルネットワークの重みデータを使う。

    1. まず、IPython シェルのコンソールで、カレントディレクトリの変更
      cd C:/pytools/ssd_keras
      

    2. 準備
      from keras import backend as K
      from keras.models import load_model
      from keras.preprocessing import image
      from keras.optimizers import Adam
      from scipy.misc import imread
      import numpy as np
      from matplotlib import pyplot as plt
      %matplotlib inline
      import sys
      
      from models.keras_ssd300 import ssd_300
      from keras_loss_function.keras_ssd_loss import SSDLoss
      from keras_layers.keras_layer_AnchorBoxes import AnchorBoxes
      from keras_layers.keras_layer_DecodeDetections import DecodeDetections
      from keras_layers.keras_layer_DecodeDetectionsFast import DecodeDetectionsFast
      from keras_layers.keras_layer_L2Normalization import L2Normalization
      
      from ssd_encoder_decoder.ssd_output_decoder import decode_detections, decode_detections_fast
      
      from data_generator.object_detection_2d_data_generator import DataGenerator
      from data_generator.object_detection_2d_photometric_ops import ConvertTo3Channels
      from data_generator.object_detection_2d_geometric_ops import Resize
      from data_generator.object_detection_2d_misc_utils import apply_inverse_transforms
      
      # Set the image size.
      img_height = 300
      img_width = 300
      

    3. ニューラルネットワークの定義、COCO を用いての学習済みニューラルネットワークの重みデータの読み込み 、コンパイル
      # 1: Build the Keras model
      
      K.clear_session() 
      
      model = ssd_300(image_size=(img_height, img_width, 3),
                      n_classes=80,
                      mode='inference',
                      l2_regularization=0.0005,
                      scales=[0.07, 0.15, 0.33, 0.51, 0.69, 0.87, 1.05], # The scales for Pascal VOC are [0.1, 0.2, 0.37, 0.54, 0.71, 0.88, 1.05]
                      aspect_ratios_per_layer=[[1.0, 2.0, 0.5],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5],
                                               [1.0, 2.0, 0.5]],
                      two_boxes_for_ar1=True,
                      steps=[8, 16, 32, 64, 100, 300],
                      offsets=[0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
                      clip_boxes=False,
                      variances=[0.1, 0.1, 0.2, 0.2],
                      normalize_coords=True,
                      subtract_mean=[123, 117, 104],
                      swap_channels=[2, 1, 0],
                      confidence_thresh=0.01,
                      iou_threshold=0.45,
                      top_k=200,
                      nms_max_output_size=400)
      
      # 2: Load the trained weights into the model.
      
      # TODO: Set the path of the trained weights.
      weights_path = 'C:/pytools/ssd_keras/VGG_coco_SSD_300x300_iter_400000.h5'
      
      model.load_weights(weights_path, by_name=True)
      
      # 3: Compile the model so that Keras won't complain the next time you load it.
      
      adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
      
      ssd_loss = SSDLoss(neg_pos_ratio=3, alpha=1.0)
      
      model.compile(optimizer=adam, loss=ssd_loss.compute_loss)
      

    4. 画像ファイルの読み込みと予測

      画像ファイル名は、「img_path = 'C:/image/home.jpg'」の行で設定

      colors = plt.cm.hsv(np.linspace(0, 1, 81)).tolist()
      orig_images = [] # Store the images here.
      input_images = [] # Store resized versions of the images here.
      
      # We'll only load one image in this example.
      img_path = 'C:/image/home.jpg'
      
      orig_images.append(imread(img_path))
      img = image.load_img(img_path, target_size=(img_height, img_width))
      img = image.img_to_array(img) 
      input_images.append(img)
      input_images = np.array(input_images)
      
      y_pred = model.predict(input_images)
      
      confidence_threshold = 0.075
      y_pred_thresh = [y_pred[k][y_pred[k,:,1] > confidence_threshold] for k in range(y_pred.shape[0])]
      
      plt.figure(figsize=(20,12))
      plt.imshow(orig_images[0])
      
      current_axis = plt.gca()
      
      for box in y_pred_thresh[0]:
          # Transform the predicted bounding boxes for the 300x300 image to the original image dimensions.
          xmin = box[2] * orig_images[0].shape[1] / img_width
          ymin = box[3] * orig_images[0].shape[0] / img_height
          xmax = box[4] * orig_images[0].shape[1] / img_width
          ymax = box[5] * orig_images[0].shape[0] / img_height
          color = colors[int(box[0])]
          label = '{}: {:.2f}'.format(box[0], box[1])
          current_axis.add_patch(plt.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, color=color, fill=False, linewidth=2))  
          current_axis.text(xmin, ymin, label, size='x-large', color='white', bbox={'facecolor':color, 'alpha':1.0})
      

      結果の確認

    5. 別の画像 fruits.jpg で試す

      プログラムでは「img_path = 'C:/image/fruits.jpg'」のように変えて、実行(他の部分は変えない)

      colors = plt.cm.hsv(np.linspace(0, 1, 81)).tolist()
      orig_images = [] # Store the images here.
      input_images = [] # Store resized versions of the images here.
      
      # We'll only load one image in this example.
      img_path = 'C:/image/fruits.jpg'
      
      orig_images.append(imread(img_path))
      img = image.load_img(img_path, target_size=(img_height, img_width))
      img = img.ravel()
      input_images = np.array(img)
      
      y_pred = model.predict(input_images)
      
      confidence_threshold = 0.1
      y_pred_thresh = [y_pred[k][y_pred[k,:,1] > confidence_threshold] for k in range(y_pred.shape[0])]
      
      plt.figure(figsize=(20,12))
      plt.imshow(orig_images[0])
      
      current_axis = plt.gca()
      
      for box in y_pred_thresh[0]:
          # Transform the predicted bounding boxes for the 300x300 image to the original image dimensions.
          xmin = box[2] * orig_images[0].shape[1] / img_width
          ymin = box[3] * orig_images[0].shape[0] / img_height
          xmax = box[4] * orig_images[0].shape[1] / img_width
          ymax = box[5] * orig_images[0].shape[0] / img_height
          color = colors[int(box[0])]
          label = '{}: {:.2f}'.format(box[0], box[1])
          current_axis.add_patch(plt.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, color=color, fill=False, linewidth=2))  
          current_axis.text(xmin, ymin, label, size='x-large', color='white', bbox={'facecolor':color, 'alpha':1.0})
      

    6. 別の画像 1.png で試す

      プログラムでは「img_path = 'C:/image/1.png'」のように変えて、実行(他の部分は変えない)

      colors = plt.cm.hsv(np.linspace(0, 1, 81)).tolist()
      orig_images = [] # Store the images here.
      input_images = [] # Store resized versions of the images here.
      
      # We'll only load one image in this example.
      img_path = 'C:/image/1.png'
      
      orig_images.append(imread(img_path))
      img = image.load_img(img_path, target_size=(img_height, img_width))
      img = image.img_to_array(img) 
      input_images.append(img)
      input_images = np.array(input_images)
      
      y_pred = model.predict(input_images)
      
      confidence_threshold = 0.1
      y_pred_thresh = [y_pred[k][y_pred[k,:,1] > confidence_threshold] for k in range(y_pred.shape[0])]
      
      plt.figure(figsize=(20,12))
      plt.imshow(orig_images[0])
      
      current_axis = plt.gca()
      
      for box in y_pred_thresh[0]:
          # Transform the predicted bounding boxes for the 300x300 image to the original image dimensions.
          xmin = box[2] * orig_images[0].shape[1] / img_width
          ymin = box[3] * orig_images[0].shape[0] / img_height
          xmax = box[4] * orig_images[0].shape[1] / img_width
          ymax = box[5] * orig_images[0].shape[0] / img_height
          color = colors[int(box[0])]
          label = '{}: {:.2f}'.format(box[0], box[1])
          current_axis.add_patch(plt.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, color=color, fill=False, linewidth=2))  
          current_axis.text(xmin, ymin, label, size='x-large', color='white', bbox={'facecolor':color, 'alpha':1.0})
      


      PASCAL VOC のデータを使用

      物体検出してみる

      謝辞:https://github.com/pierluigiferrari/ssd_keras/blob/master/ssd300_inference.ipynb に記載のプログラムを使用している

    7. Python プログラムを動かす

      そのために, PyCharmなどにある Python コンソールを使う

    8. Python コンソールで、カレントディレクトリの変更
      cd C:/pytools/ssd_keras
      

    9. 設定
      from keras import backend as K
      from keras.models import load_model
      from keras.preprocessing import image
      from keras.optimizers import Adam
      from imageio import imread
      import numpy as np
      from matplotlib import pyplot as plt
      
      from models.keras_ssd300 import ssd_300
      from keras_loss_function.keras_ssd_loss import SSDLoss
      from keras_layers.keras_layer_AnchorBoxes import AnchorBoxes
      from keras_layers.keras_layer_DecodeDetections import DecodeDetections
      from keras_layers.keras_layer_DecodeDetectionsFast import DecodeDetectionsFast
      from keras_layers.keras_layer_L2Normalization import L2Normalization
      
      from ssd_encoder_decoder.ssd_output_decoder import decode_detections, decode_detections_fast
      
      from data_generator.object_detection_2d_data_generator import DataGenerator
      from data_generator.object_detection_2d_photometric_ops import ConvertTo3Channels
      from data_generator.object_detection_2d_geometric_ops import Resize
      from data_generator.object_detection_2d_misc_utils import apply_inverse_transforms
      
      %matplotlib inline
      
      
      # Set the image size.
      img_height = 300
      img_width = 300
      

    10. 学習済みニューラルネットワークの重みデータの読み込み
      # 1: Build the Keras model
      
      K.clear_session() # Clear previous models from memory.
      
      model = ssd_300(image_size=(img_height, img_width, 3),
                      n_classes=20,
                      mode='inference',
                      l2_regularization=0.0005,
                      scales=[0.1, 0.2, 0.37, 0.54, 0.71, 0.88, 1.05], # The scales for MS COCO are [0.07, 0.15, 0.33, 0.51, 0.69, 0.87, 1.05]
                      aspect_ratios_per_layer=[[1.0, 2.0, 0.5],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5, 3.0, 1.0/3.0],
                                               [1.0, 2.0, 0.5],
                                               [1.0, 2.0, 0.5]],
                      two_boxes_for_ar1=True,
                      steps=[8, 16, 32, 64, 100, 300],
                      offsets=[0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
                      clip_boxes=False,
                      variances=[0.1, 0.1, 0.2, 0.2],
                      normalize_coords=True,
                      subtract_mean=[123, 117, 104],
                      swap_channels=[2, 1, 0],
                      confidence_thresh=0.5,
                      iou_threshold=0.45,
                      top_k=200,
                      nms_max_output_size=400)
      
      # 2: Load the trained weights into the model.
      
      # TODO: Set the path of the trained weights.
      weights_path = 'C:/pytools/ssd_keras/VGG_VOC0712_SSD_300x300_iter_120000.h5'
      
      model.load_weights(weights_path, by_name=True)
      
      # 3: Compile the model so that Keras won't complain the next time you load it.
      
      adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
      
      ssd_loss = SSDLoss(neg_pos_ratio=3, alpha=1.0)
      
      model.compile(optimizer=adam, loss=ssd_loss.compute_loss)
      

    11. 画像ファイルの読み込みと予測
      colors = plt.cm.hsv(np.linspace(0, 1, 21)).tolist()
      classes = ['background',
                 'aeroplane', 'bicycle', 'bird', 'boat',
                 'bottle', 'bus', 'car', 'cat',
                 'chair', 'cow', 'diningtable', 'dog',
                 'horse', 'motorbike', 'person', 'pottedplant',
                 'sheep', 'sofa', 'train', 'tvmonitor']
      
      orig_images = [] # Store the images here.
      input_images = [] # Store resized versions of the images here.
      
      # We'll only load one image in this example.
      img_path = 'C:/image/home.jpg'
      
      orig_images.append(imread(img_path))
      img = image.load_img(img_path, target_size=(img_height, img_width))
      img = image.img_to_array(img) 
      input_images.append(img)
      input_images = np.array(input_images)
      
      y_pred = model.predict(input_images)
      
      confidence_threshold = 0.5
      y_pred_thresh = [y_pred[k][y_pred[k,:,1] > confidence_threshold] for k in range(y_pred.shape[0])]
      
      plt.figure(figsize=(20,12))
      plt.imshow(orig_images[0])
      
      current_axis = plt.gca()
      
      for box in y_pred_thresh[0]:
          # Transform the predicted bounding boxes for the 300x300 image to the original image dimensions.
          xmin = box[2] * orig_images[0].shape[1] / img_width
          ymin = box[3] * orig_images[0].shape[0] / img_height
          xmax = box[4] * orig_images[0].shape[1] / img_width
          ymax = box[5] * orig_images[0].shape[0] / img_height
          color = colors[int(box[0])]
          label = '{}: {:.2f}'.format(classes[int(box[0])], box[1])
          current_axis.add_patch(plt.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, color=color, fill=False, linewidth=2))  
          current_axis.text(xmin, ymin, label, size='x-large', color='white', bbox={'facecolor':color, 'alpha':1.0})
      

      結果を確認