TX2でYOLOがどのくらいのスピードになるか?
ちょっと埃をかぶってますが、以下の動画は紛れもなくこのTX2で実行してます。
これは、weightデータがTiny YOLOではなく標準のYOLO V2です。使ったデータは今回の場合80クラスを認識しますが、コンピューターにとって全世界が80項目しかないので誤認識があります。でもハマったものはなかなか素晴らしい結果でした。
今回TX2でYOLOを実行させた結果です。画像のスピードは問題なし。YOLOの認識速度もなかなか!!(画像がボケているのにこの辺りがAIですかね......)
前の記事でJetson XvierにインストールしたopenFrameworksでYOLOを動かしてみましたが、なかなか良い結果が出たので、じゃーTX2で実行したらどうなるのかってのが今回の実験です。
TX2へのOpenframeworksのインストールはこの記事を参照して下さい。
で、YOLOのインストールは
TX2でXavierに勝とうっていうのは所詮無理な話で、
少しでもXavierに近づけるためにマルチスレッドを利用します(OF上ではofThread
を利用)。Xavierでも裏スレッドを1個使って実現させましたが、今回は2個使います。GPUはマルチスレッド対応していないということが頭に入ってました。でも、「微妙に時間をずらすことでGPUをうまく使えないか」ってことが今回の発想です。ここでもやはりデータ変換が鍵を握ってて、ちょっと時間がかかりましたが、なんとなく狙い通りになってるようです。
まずyolov2.cfgの設定ですが
最初の方を
batch=32
subdivisions=8
weight=416
height=416
にしました。weight、heightとも608にするのが理想的ですが、あまり認識に変化が無いようなのでスピード重視です。yolov2.cfgが何者かは、前の記事を確認して下さい。
また、Web CameraのopenFrameworks側設定画像は640x480。相当粗い画像ですがYOLOはそれでも満足の行く結果を出してしまいます。これもスピード対策。openFrameworkeのソースは次の通りです。
ただし、まだバグが残っているようでmake runしてもエラーが出る場合があります。その場合は、何度もmake run してみて下さい(Xavierも同じ)
main.cpp
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
ofSetupOpenGL(640,480, OF_WINDOW); // <-------- setup the GL context
// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp( new ofApp());
}
で、ofApp.h
#pragma once
#include "ofMain.h"
#include "ofxCv.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y);
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ofVideoGrabber video;
ofImage img;
最後にofApp.cpp
#include "ofApp.h"
#include "src1/yolo_v2_class.hpp" // imported functions from DLL
std::string names_file = "data/coco.names";
std::string cfg_file = "cfg/yolov2.cfg";
std::string weights_file = "yolov2.weights";
float const thresh = 0.20;
cv::Mat mat;
ofTrueTypeFont cop20,cop50;
Detector detector(cfg_file, weights_file);
std::vector result_vec,result_vec1,result_vec2 ;
float ttt,ttt1,ttt2,sss,sss1; //Time
image_t xxx,yyy,zzz;
std::vector objects_names_from_file(std::string const filename) {
std::ifstream file(filename);
std::vector file_lines;
if (!file.is_open()) return file_lines;
for(std::string line; getline(file, line);) file_lines.push_back(line);
std::cout << "object names loaded \n";
file.close();
return file_lines;
}
std::vector obj_names;
void show_console_result(std::vector const result_vec, std::vector const obj_names) {
for (auto &i : result_vec) {
if (obj_names.size() > i.obj_id)
ofNoFill();
ofSetLineWidth(1);
//Color Set!!
int const colors[6][3] = { { 1,0,1 },{ 0,0,1 },{ 0,1,1 },{ 0,1,0 },{ 1,1,0 },{ 1,0,0 } };
int const offset = i.obj_id * 123457 % 6;
int const color_scale = 150 + (i.obj_id * 123457) % 100;
ofSetColor(colors[offset][0]*color_scale, colors[offset][1]*color_scale, colors[offset][2]*color_scale);
ofDrawRectRounded(i.x,i.y,i.w,i.h,5);
//Mozi Draw!!
string ss;
ss=" "+ obj_names[i.obj_id]+" "+ofToString(i.prob*100,1);
//ofFill();
//ofDrawRectangle(i.x,i.y,i.w,20);
ofSetColor(255);
cop20.drawString(ss, i.x,i.y+15);
}
}
static image_t make_empty_image(int w, int h, int c)
{
image_t out;
out.data = 0;
out.h = h;
out.w = w;
out.c = c;
return out;
}
static image_t make_image_custom(int w, int h, int c)
{
image_t out = make_empty_image(w, h, c);
out.data = (float *)calloc(h*w*c, sizeof(float));
return out;
}
static image_t ipl_to_image(IplImage* src)
{
unsigned char *data = (unsigned char *)src->imageData;
int h = src->height;
int w = src->width;
int c = src->nChannels;
int step = src->widthStep;
image_t out = make_image_custom(w, h, c);
int count = 0;
for (int k = 0; k < c; ++k) {
for (int i = 0; i < h; ++i) {
int i_step = i*step;
for (int j = 0; j < w; ++j) {
out.data[count++] = data[i_step + j*c + k] / 255.;
}
}
}
return out;
}
void detect_x(image_t x)
{
result_vec = detector.detect(x,thresh,false);
}
void detect_y(image_t x)
{
result_vec1 = detector.detect(x,thresh,true);
}
void detect_z(image_t x)
{
result_vec2 = detector.detect(x,thresh,true);
}
//--------------------------------------------------------------
// DetectNet部分をマルチスレッドにする。
class Detect_x: public ofThread {
public:
void threadedFunction(){
ok=false;
detect_x(xxx);
ok2=true ;
ok=true;
}
bool ok;
};
Detect_x Found_X;
//--------------------------------------------------------------
// DetectNet部分をマルチスレッドにする。
class Detect_y: public ofThread {
public:
void threadedFunction(){
ok1=false;
cv::Mat imgy;
cv::cvtColor(mat, imgy, cv::COLOR_RGB2BGR);
std::shared_ptr image_ptr1(new image_t, [](image_t *imgy) { detector.free_image(*imgy); delete imgy; });
std::shared_ptr ipl_small1 = std::make_shared(imgy);
*image_ptr1 = ipl_to_image(ipl_small1.get());
yyy=*image_ptr1;
detect_y(yyy);
ok3=true ;
ok1=true;
}
bool ok1;
};
Detect_y Found_Y;
//--------------------------------------------------------------
void ofApp::setup(){
obj_names = objects_names_from_file(names_file);
cop20.load("cooperBlack.ttf",10,true,true,true);
cop50.load("cooperBlack.ttf",30,true,true,true);
img.allocate(640,480,OF_IMAGE_COLOR);
video.setDeviceID( 0 );
//video.setDesiredFrameRate( 30 );
video.setup(640,480,OF_PIXELS_RGBA);
Found_X.ok=true;
Found_Y.ok1=true;
ok2=true;
ok3=true;
}
//--------------------------------------------------------------
void ofApp::update(){
//ofLog() << ofGetFrameRate();
video.update();
if(video.isFrameNew()==true){
img.setFromPixels(video.getPixels().getData(),video.getWidth(),video.getHeight(),OF_IMAGE_COLOR);
mat=ofxCv::toCv(img);
if (Found_X.ok){
cv::Mat imgx;
cv::cvtColor(mat,imgx, cv::COLOR_RGB2BGR);
std::shared_ptr image_ptr(new image_t, [](image_t *imgx) { detector.free_image(*imgx); delete imgx; });
std::shared_ptr ipl_small = std::make_shared(imgx);
*image_ptr = ipl_to_image(ipl_small.get());
xxx=*image_ptr;
Found_X.startThread();
}
else if(Found_Y.ok1) Found_Y.startThread();
}
}
//--------------------------------------------------------------
void ofApp::draw(){
ofSetColor(255);
video.draw( 0, 0 );
Found_X.lock();
show_console_result(result_vec, obj_names);
Found_X.unlock();
Found_Y.lock();
show_console_result(result_vec1, obj_names);
Found_Y.unlock();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}