使用したいときに忘れているためメモ。
マルチスレッドでKerasのモデルを利用したい時には、 ロードしたモデルに対して、以下のAPIを呼んで事前コンパイルしておく。 (メイン関数でロードしたモデルを別スレッドに渡して、別スレッド内で推論する場合等)
model._make_predict_function()
以上。
これまた今さらですが、LINE Messaging APIを利用したLINE BOTの作成が楽しく、色々試しております。
以下に最近作ってみたものをご紹介。
■献立提案 BOT
献立を考える助けになるかもしれないBOT
・使用技術
- Google Apps Script
・機能
- 食材からレシピを提案(写真1枚目)
- 位置情報から最寄りのお店を提案(写真2枚目)
- 特定のスタンプを送るとランダムでレシピを提案(写真3枚目)
・使用技術
- Google Apps Script
- Google Cloud Vision API(光学式文字認識(OCR))
・機能
- 送付された画像のOCR結果を返す
- 画像とOCR結果をスプレッドシートに更新してGoogleドライブ上に保存
■画像判別 BOT
画像を送ると画像判別結果を返すBOT
・使用技術
- Google Apps Script
- Google Cloud Vision API(ラベル検出)
- Microsoft Azure TranslatorAPI
・機能
- 送付された画像に対し、ラベル検出結果を返す
(ラベルは英語なので、日本語に翻訳した結果を返す)
以上。
今さらながらGASの便利さに気付き色々試しております。
本頁は、Google Apps Script をWebAPIとして利用して、Googleドライブ上のスプレッドシートに追記するメモです。
GASからアクセスできるように共有可能なリンクを取得します。
「?id=」以降がGAS側で利用するIDです。
たいしたコードでも無いので、ソースコードにそのままIDを埋め込んでも良いですが、 一応GASのプロジェクトプロパティにIDを入れておきます。
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); }
「ウェブアプリケーションとして導入」を実施します。
アプリケーションにアクセスできるユーザーは「全員(匿名ユーザーを含む)」に設定し「更新」を実施します。
初回はGoogleドライブ上へのアクセス許可を求められるはず。。 。 スクリーンショット取り忘れました。。。
テストとしてブラウザから「1,2,3, ,abcde」を指定して呼び出してみます。
スプレッドシートに追記されました。
以上。
グレースケール画像に疑似的な色を付けることを疑似カラーと言います。
以下のようなデータがあった場合に、視覚的に分かりやすい表現が出来ます
・深度センサー(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()
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
USB2.0系Webカメラ界のエース 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
ぶっちゃけ、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)
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