トップページ -> 最新情報技術の実習と研究ツール -> 画像分類、物体検出 -> 一般物体検出(pierluigiferrari/ssd_keras の SSD を使用)を行ってみる
[サイトマップへ]  

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


前準備

Anaconda, git のインストール

前準備として,Python 開発環境のAnaconda のインストールと git のインストールが終わっていること.

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

隔離された Python 環境の作成.spyder, numpy, OpenCV, Tensorflow, matplotlib, pillow, sciklit-learn のインストール

Windows での 手順は、 「Windows で,隔離された Python 環境 + Keras + TensorFlow + OpenCV + spyder + Dlib 環境を作る(Anaconda を利用)」のページで説明しています.

以下,Windows での Anaconda と git をインストール済み, 隔離された Python 環境(名前は ai)に、spyder, numpy, OpenCV, Tensorflow, matplotlib, pillow, sciklit-learn をインストール済みであるものとして説明を続けます.


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

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

    Python 環境を切り替えたいときは、コマンドプロンプトで,次のコマンドを実行し,Python 環境(下の手順では、名前は ai)に切り替える

    activate ai
    

  2. imageio tqdm beautifulsoup4 のインストール
    conda install -y 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 でコマンドプロンプトを実行

    Python 環境を切り替えたいときは、コマンドプロンプトで,次のコマンドを実行し,Python 環境(下の手順では、名前は ai)に切り替える

    activate ai
    

  2. 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 
    

  3. 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 に置く

  4. 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 プログラムを動かしたい. そのために, IPython シェルのコンソールで、Python 環境(名前は ai)を使う

Anacondaに入っている開発環境 spyder を実行し,右下の ipython コンソールを使うのが簡単.

※ Windows のスタートメニューで、 「spyder」の方ではなく、 「spyder(ai)」を開く。 これで、spyder の中で、Python環境aiが有効になる

※「spyder(ai)」がない!というときは、Windowsのコマンドプロントで次を実行

activate ai
conda install -y -c spyder-ide spyder 

※ Windows のスタートメニューで起動できないときは、Windowsのコマンドプロントで次を実行

activate ai
spyder

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 に記載のプログラムを使用しています

    Python プログラムを動かしたい. そのために, IPython シェルのコンソールで、Python 環境(名前は ai)を使う

    Anacondaに入っている開発環境 spyder を実行し,右下の ipython コンソールを使うのが簡単.

    ※ Windows のスタートメニューで、 「spyder」の方ではなく、 「spyder(ai)」を開く。 これで、spyder の中で、Python環境aiが有効になる

    ※ Windows のスタートメニューで起動できないときは、Windowsのコマンドプロントで次を実行

    activate ai
    spyder
    
    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 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
      

    3. 学習済みニューラルネットワークの重みデータの読み込み
      # 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)
      

    4. 画像ファイルの読み込みと予測
      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})
      

      結果を確認