高橋かずひとのプログラミング、その他、備忘録。

日々調べてたことや、作ってみたものをメモしているブログ。 お決まりの断り文句ですが、このブログに書かれている内容は個人の見解であり、所属する組織の公式見解ではありません。チラ裏。

【Keras】メモ:Kerasのモデルを別スレッドで使用する

使用したいときに忘れているためメモ。

マルチスレッドでKerasのモデルを利用したい時には、 ロードしたモデルに対して、以下のAPIを呼んで事前コンパイルしておく。 (メイン関数でロードしたモデルを別スレッドに渡して、別スレッド内で推論する場合等)

model._make_predict_function()

以上。

【LINE】個人的に色々作ったBOT

これまた今さらですが、LINE Messaging APIを利用したLINE BOTの作成が楽しく、色々試しております。

以下に最近作ってみたものをご紹介。

 

■献立提案 BOT

 献立を考える助けになるかもしれないBOT

 ・使用技術

  - 楽天レシピAPI

  - ホットペッパー グルメサーチAPI

  - Google Apps Script

 ・機能

  - 食材からレシピを提案(写真1枚目)

  - 位置情報から最寄りのお店を提案(写真2枚目)

  - 特定のスタンプを送るとランダムでレシピを提案(写真3枚目)

f:id:Kazuhito00:20180318025837p:plain
f:id:Kazuhito00:20180318025956p:plain
f:id:Kazuhito00:20180318025958p:plain

 

OCR BOT

  画像を送るとOCR結果を返すBOT

 ・使用技術

  - Google Apps Script

  - Google Cloud Vision API(光学式文字認識(OCR))

 ・機能

  - 送付された画像のOCR結果を返す

  - 画像とOCR結果をスプレッドシートに更新してGoogleドライブ上に保存

f:id:Kazuhito00:20180318025959p:plain

 

■画像判別 BOT

  画像を送ると画像判別結果を返すBOT

 ・使用技術

  - Google Apps Script

  - Google Cloud Vision API(ラベル検出)

  - Microsoft Azure TranslatorAPI

 ・機能

  - 送付された画像に対し、ラベル検出結果を返す

    (ラベルは英語なので、日本語に翻訳した結果を返す)

f:id:Kazuhito00:20180318030001p:plain

 

以上。

【GAS】Googleドライブ上のスプレッドシートを追記するWeb API

今さらながらGASの便利さに気付き色々試しております。

本頁は、Google Apps Script をWebAPIとして利用して、Googleドライブ上のスプレッドシートに追記するメモです。


Googleドライブ上にスプレッドシートを用意します。 f:id:Kazuhito00:20180318023626j:plain

GASからアクセスできるように共有可能なリンクを取得します。 f:id:Kazuhito00:20180318023637j:plain

「?id=」以降がGAS側で利用するIDです。 f:id:Kazuhito00:20180318023651j:plain

たいしたコードでも無いので、ソースコードにそのままIDを埋め込んでも良いですが、 一応GASのプロジェクトプロパティにIDを入れておきます。 f:id:Kazuhito00:20180318023708j:plain f:id:Kazuhito00:20180318023716j:plain

GAS上のソースコードは以下です。 リクエストパラメータは手抜きしてactionをそのまま使用。。。

function doGet(e) {
  // action未指定の場合
  if(!e.parameter.action) { 
    return ContentService.createTextOutput(JSON.stringify({'status': 'NG'}))
           .setMimeType(ContentService.MimeType.JSON);
  }

  // スプレッドシートに記録
  // プロジェクトプロパティからスプレッドシートのIDを取得
  var PROPERTIES = PropertiesService.getScriptProperties();
  var SPREAD_SHEET = PROPERTIES.getProperty('SPREAD_SHEET')
  var sheet = SpreadsheetApp.openById(SPREAD_SHEET);
  // スプレッドシートに追記するCSVデータを生成
  var appendData = new Array();
  var cells = e.parameter.action.split(",")
  for(var i = 0; i<cells.length;i++){
    appendData.push(cells[i])
  }
  // スプレッドシートの最終行に追記
  sheet.appendRow(appendData);

  return ContentService.createTextOutput(JSON.stringify({'status': 'OK'}))
         .setMimeType(ContentService.MimeType.JSON);
}

ウェブアプリケーションとして導入」を実施します。 f:id:Kazuhito00:20180318023731j:plain

アプリケーションにアクセスできるユーザーは「全員(匿名ユーザーを含む)」に設定し「更新」を実施します。

初回はGoogleドライブ上へのアクセス許可を求められるはず。。 。 スクリーンショット取り忘れました。。。 f:id:Kazuhito00:20180318023743j:plain

テストとしてブラウザから「1,2,3, ,abcde」を指定して呼び出してみます。 f:id:Kazuhito00:20180318023754j:plain

スプレッドシートに追記されました。 f:id:Kazuhito00:20180318023808j:plain

以上。

【Python】OpenCVで疑似カラー(Pseudo color)

グレースケール画像に疑似的な色を付けることを疑似カラーと言います。
以下のようなデータがあった場合に、視覚的に分かりやすい表現が出来ます
 ・深度センサー(KinectやRealSenseやXtion等のDepthカメラ)
 ・サーモグラフィー
 ・照明ムラ
  など

OpenCVに疑似カラーを付けるAPI(applyColorMap())があったため、本投稿にメモ。

動画は以下。
www.youtube.com

ソースコードは以下。
本来ならサーモグラフィー等の画像を取り込みたいところですが、
Webカメラしかなかったので、グレースケール画像を取り込んで疑似カラーを付けてます。
色々なパターンがあるため、N押下で切り替えれるようにサンプルを作成。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import copy

colormap_table_count = 0
colormap_table = [
    ['COLORMAP_AUTUMN',  cv2.COLORMAP_AUTUMN ],
    ['COLORMAP_JET',     cv2.COLORMAP_JET    ],
    ['COLORMAP_WINTER',  cv2.COLORMAP_WINTER ],
    ['COLORMAP_RAINBOW', cv2.COLORMAP_RAINBOW],
    ['COLORMAP_OCEAN',   cv2.COLORMAP_OCEAN  ],
    ['COLORMAP_SUMMER',  cv2.COLORMAP_SUMMER ],
    ['COLORMAP_SPRING',  cv2.COLORMAP_SPRING ],
    ['COLORMAP_COOL',    cv2.COLORMAP_COOL   ],
    ['COLORMAP_HSV',     cv2.COLORMAP_HSV    ],
    ['COLORMAP_PINK',    cv2.COLORMAP_PINK   ],
    ['COLORMAP_HOT',     cv2.COLORMAP_HOT    ]
]

video_input = cv2.VideoCapture(0)

while(1):
    ret, frame = video_input.read()

    # グレースケール化
    grayscale_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 疑似カラーを付与
    apply_color_map_image = cv2.applyColorMap(grayscale_image, colormap_table[colormap_table_count % len(colormap_table)][1])

    cv2.putText(apply_color_map_image, colormap_table[colormap_table_count % len(colormap_table)][0], (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,0),2);
    cv2.imshow('apply_color_map_image',apply_color_map_image)

    k = cv2.waitKey(50) & 0xff
    if k == 110: # N
        colormap_table_count = colormap_table_count + 1
    if k == 27:  # ESC
        break

video_input.release()
cv2.destroyAllWindows()

【Windows】【Python】OpenCV3.3.1のdnnモジュールサンプル(mobilenet_ssd_python.py)

OpenCV3.3で公式にサポートされたDNN(深層ニューラルネットワーク)モジュールの
Python版mobilenetサンプルを動作させてみました。

学習済みモデルは以下URLにあるはずだが、リンク切れていたため、
https://github.com/chuanqi305/MobileNet-SSD/blob/master/MobileNetSSD_train.caffemodel
ひとまず、以下のURLから取得。
https://drive.google.com/file/d/0BwY-lpO6tzxHRHNCdlRKczIzaEU/view?usp=sharing

動画は以下。
CPUのみでもそこそこ動く。
www.youtube.com

ソースコードは以下。
基本的には、「opencv\sources\samples\dnn\mobilenet_ssd_python.py」と同じ。
自分の環境構築が悪いのか、そのままで動作しなかったところを一部修正。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import argparse

try:
    #import cv2 as cv
    import cv2                #[修正] cv2呼び出ししているため、as cvを削除
    from cv2 import dnn       #[修正] dnnモジュールをインポート
except ImportError:
    raise ImportError('Can\'t find OpenCV Python module. If you\'ve built it from sources without installation, '
                      'configure environemnt variable PYTHONPATH to "opencv_build_dir/lib" directory (with "python3" subdirectory if required)')

inWidth = 300
inHeight = 300
WHRatio = inWidth / float(inHeight)
inScaleFactor = 0.007843
meanVal = 127.5

classNames = ('background',
              'aeroplane', 'bicycle', 'bird', 'boat',
              'bottle', 'bus', 'car', 'cat', 'chair',
              'cow', 'diningtable', 'dog', 'horse',
              'motorbike', 'person', 'pottedplant',
              'sheep', 'sofa', 'train', 'tvmonitor')

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--video", help="path to video file. If empty, camera's stream will be used")
    parser.add_argument("--prototxt", default="MobileNetSSD_300x300.prototxt",
                        help="path to caffe prototxt")
    parser.add_argument("-c", "--caffemodel", help="path to caffemodel file, download it here: "
                             "https://github.com/chuanqi305/MobileNet-SSD/blob/master/MobileNetSSD_train.caffemodel")
    parser.add_argument("--thr", default=0.2, help="confidence threshold to filter out weak detections")
    args = parser.parse_args()

    net = dnn.readNetFromCaffe(args.prototxt, args.caffemodel)

    #if len(args.video):      #[修正] --video未指定時にlen()で長さ取得できないはずなので修正
    if args.video != None:
        cap = cv2.VideoCapture(args.video)
    else:
        cap = cv2.VideoCapture(0)

    while True:
        # Capture frame-by-frame
        ret, frame = cap.read()
        blob = dnn.blobFromImage(frame, inScaleFactor, (inWidth, inHeight), meanVal)
        net.setInput(blob)
        detections = net.forward()

        cols = frame.shape[1]
        rows = frame.shape[0]

        if cols / float(rows) > WHRatio:
            cropSize = (int(rows * WHRatio), rows)
        else:
            cropSize = (cols, int(cols / WHRatio))

        y1 = (rows - cropSize[1]) / 2
        y2 = y1 + cropSize[1]
        x1 = (cols - cropSize[0]) / 2
        x2 = x1 + cropSize[0]
        frame = frame[y1:y2, x1:x2]

        cols = frame.shape[1]
        rows = frame.shape[0]

        for i in range(detections.shape[2]):
            confidence = detections[0, 0, i, 2]
            if confidence > args.thr:
                class_id = int(detections[0, 0, i, 1])

                xLeftBottom = int(detections[0, 0, i, 3] * cols)
                yLeftBottom = int(detections[0, 0, i, 4] * rows)
                xRightTop   = int(detections[0, 0, i, 5] * cols)
                yRightTop   = int(detections[0, 0, i, 6] * rows)

                cv2.rectangle(frame, (xLeftBottom, yLeftBottom), (xRightTop, yRightTop),
                              (0, 255, 0))
                label = classNames[class_id] + ": " + str(confidence)
                labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)

                cv2.rectangle(frame, (xLeftBottom, yLeftBottom - labelSize[1]),
                                     (xLeftBottom + labelSize[0], yLeftBottom + baseLine),
                                     (255, 255, 255), cv2.FILLED)
                cv2.putText(frame, label, (xLeftBottom, yLeftBottom),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))

        cv2.imshow("detections", frame)
        if cv2.waitKey(1) >= 0:
            break

ロジクール c922 購入 + OpenCV カメラ設定メモ

USB2.0Webカメラ界のエース c920rの後継機
https://www.amazon.co.jp/Logicool-%E3%83%AD%E3%82%B8%E3%82%AF%E3%83%BC%E3%83%AB-C922-%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0-%E3%82%A6%E3%82%A7%E3%83%96%E3%82%AB%E3%83%A0/dp/B01LYTKPDT

f:id:Kazuhito00:20161013014225j:plain

ぶっちゃけ、c920rとほぼほぼ性能に差はないが、
「720p(60fps)」と言う表記に惹かれ購入。
USB3.0系の産業用カメラならまだしも、市販機で60fpsを謳っているWebカメラは珍しい。

最近ほとんど使っていなかったOpenCVのカメラ設定周りのAPIを忘れないようにメモ↓

video_input.set(cv2.CAP_PROP_FPS, 60)           # カメラFPSを60FPSに設定
video_input.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) # カメラ画像の横幅を1280に設定
video_input.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # カメラ画像の縦幅を720に設定

print video_input.get(cv2.CAP_PROP_FPS)
print video_input.get(cv2.CAP_PROP_FRAME_WIDTH)
print video_input.get(cv2.CAP_PROP_FRAME_HEIGHT)

【Ubuntu】【Python】dlibを用いた物体追跡

OpneCVの物体追跡はちょくちょくサンプルを動かしたことがるのだけど、
dlibは動かしたことがなかったため、ちょっとお試し。

モーションブラーとかにも付いて行ってて、結構性能良さそうな感じ。

動画は以下。
youtu.be


ソースコードは以下。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
correlation_tracker.py.

Usage:
  correlation_tracker.py [<video source>] [<resize rate>]
'''

import sys
import dlib
import cv2
import time
import copy

# マウスイベントハンドラ
mouse_start_x, mouse_start_y = 0, 0
mouse_end_x, mouse_end_y = 0, 0
selecting = False
tracker_start_flag = False
tracking_flag = False
def select_roi(event,x,y,flags,param):
    global selecting, tracker_start_flag
    global mouse_start_x, mouse_start_y
    global mouse_end_x, mouse_end_y
    if event == cv2.EVENT_LBUTTONDOWN:
        selecting = True
        mouse_start_x, mouse_start_y = x,y

    elif event == cv2.EVENT_MOUSEMOVE:
        if selecting == True:
            mouse_end_x, mouse_end_y = x, y
        else:
            pass
    elif event == cv2.EVENT_LBUTTONUP:
        mouse_end_x, mouse_end_y = x, y
        selecting = False
        tracker_start_flag = True

# 引数解釈
try:
    fn = sys.argv[1]
    if fn.isdigit() == True:
        fn = int(fn)
except:
    fn = 0
try:
    resize_rate = sys.argv[2]
    resize_rate = int(resize_rate)
except:
    resize_rate = 1

# トラッカー生成
tracker = dlib.correlation_tracker()

video_input = cv2.VideoCapture(fn)
if (video_input.isOpened() == True):
    ret, frame = video_input.read()
    cv2.imshow('correlation tracker', frame)
    cv2.setMouseCallback('correlation tracker', select_roi)

camera_fps = 30
frame_width, frame_height = 640, 480
video_input.set(cv2.CAP_PROP_FPS, camera_fps)            # カメラFPSを設定
video_input.set(cv2.CAP_PROP_FRAME_WIDTH, frame_width)   # カメラ画像の横幅を設定
video_input.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_height) # カメラ画像の縦幅を設定

while(video_input.isOpened() == True):
    ret, frame = video_input.read()
    temp_frame = copy.deepcopy(frame)

    # 処理負荷軽減のための対象フレーム縮小(引数指定時)
    height, width = frame.shape[:2]
    temp_frame = cv2.resize(frame, (int(width/resize_rate), int(height/resize_rate)))

    if tracker_start_flag == True:
        # 追跡開始
        tracker.start_track(temp_frame, dlib.rectangle(mouse_start_x, mouse_start_y, mouse_end_x, mouse_end_y))
        tracking_flag = True
        tracker_start_flag = False
    elif tracking_flag == True:
        # 追跡更新
        tracker.update(temp_frame)

    # 描画
    if selecting == True:
        cv2.rectangle(frame, (mouse_start_x, mouse_start_y), (mouse_end_x, mouse_end_y), (0, 0, 255), 2)
    if tracking_flag == True:
        tracking_point = tracker.get_position()
        tracking_point_x1 = int(tracking_point.left())
        tracking_point_y1 = int(tracking_point.top())
        tracking_point_x2 = int(tracking_point.right())
        tracking_point_y2 = int(tracking_point.bottom())
        cv2.rectangle(frame, (tracking_point_x1, tracking_point_y1), (tracking_point_x2, tracking_point_y2), (0, 0, 255), 2)

    cv2.imshow('correlation tracker', frame)

    c = cv2.waitKey(int(1000/camera_fps)) & 0xFF

    if c==27: # ESC
        break