Take’s diary

Macとマイコンに関すること--ワクワクの製作日記

Jetson TX2 にインストールした OpenFremeworks でも YOLO その2 (Yolo on Jetson TX2 with OpenFremeworks(Part 2))

  1. 前回の記事で、 In the last article,

 Jetson TX2 にインストールした OpenFremeworks でも 16bit浮動小数点YOLOを動かしてみました。が、アプリを立ち上げた途端止まってしまったり、早そうだけどそうでも無いような感じでした。しかも2つのスレッドで動かしているため、認識スピードの計測が難しそうなので無視していました。

    f:id:TAKEsan:20181007074429j:plain

 YOLO3は今回作成したソフトの場合、TX2ではメモリーオーバーで動かないようですが、本来のYOLO3が遅いながらも実行できるので、もう少しトライしてみる価値がありそうです。

 で、引き続きYOLO2のweightデータを使います。インストール方法は前回の通りです。

Even OpenFremeworks installed on Jetson TX 2 tried running 16 bit floating point YOLO. Although it stopped as soon as the application was launched, it seemed to be fast, but it seemed like it was not so. Moreover, because it moves with two threads, it seems to be difficult to measure recognition speed, so I ignored it.
In the case of software created this time YOLO 3 seems not to work with memory over in TX 2, but since original YOLO 3 can be executed slowly, it seems to be worth a little more trying.
We will continue to use YOLO 2's weight data. The installation method is as last time.

まず、立ち上げた時頻繁に止まる現象は First, the phenomenon that stops frequently when launched

 yolov2.chgの設定が原因のようでした。最初の方のbachとsubdivisionsの設定数値を下記のようにすると、最悪2回程度のアプリ立ち上げ直しで上手く動きます。要はメモリー設定がらみです。

It seemed to be caused by setting yolov2.chg. If you set the setting values ​​of bach and subdivisions of the first one like the following, it will work well with restarting the app about twice the worst. The point is in memory setting.

f:id:TAKEsan:20181006232037p:plain

今回は、This time,

 より正確に複数スレッドを動作させるために修正したソースofApp.cppを最後に付けました。これで、かなり正確に認識スピードが計測できるようになりました。また、認識スピードや認識の正確さに関係のあるyolov2.cfgのweightとheightの値を両方とも試しに352に設定してみます。これで実行した動画が........。

Lastly we added the modified source ofApp.cpp to make multiple threads work more accurately. With this, it is possible to measure recognition speed fairly accurately. Also try setting both the weight and height values ​​of yolov2.cfg, which are related to recognition speed and accuracy of recognition, to 352 for testing. The video that I ran in this .........

    

         画像上左上のターミナル画面が認識スピード

 ここで確認できるのは、後半ターボが効いているように最高30~40fpsくらいで画像の認識をしている?こと。画像で写しているMacBook上の動画は、早回ししているものを利用していますが十分追従しているようです。つまり、エエーホントかよーでした。ここで使っているWEB CAMERAは最高30fpsなので、1コマあたり2回ぐらい認識している場合があるようです。動画前半のように、画像全体が白っぽいと15fpsぐらいに下がってしまうところが興味深いのですが、このあたりはガンマ補正で修正できる範囲です。前回と違って明らかにクラスを表示しているボックスの表示が早いことが確認できると思います。しかも結構正確!!。認識したいクラスを絞っで、独自の学習をさせたデータを利用すると、かなりの物が作れそうです。

※2019/6/20   Jetpack4.2  及び最新のDarknetでは14fpsが上限でした。なぜこの当時早くなったか只今調査中です。

 ちなみに608x608では5.5fps前後、416x416では10.8fps前後でした。こちらの方は画像のホワイトバランスの影響が出ないので、TX2にとって352x352(32の倍数)前後の設定がもっとも効率が良いのかもしれませんね。現場で今回のソースを応用する場合、Xavierは必要ないかもしれません。(安くなったし....Switchで成功してしばらく販売継続しそうだし...)

As you can see here, do you recognize the image as much as 30 to 40 fps as the second half turbo works? about. The movie on the MacBook shot in the image seems to be tracking enough although it is using the one being fast-forwarded. Really ?Since WEB CAMERA used here has a maximum of 30 fps, it seems there are cases where it is recognized about twice per frame. As in the first half of the movie, if the entire image is whitish, it is interesting that it goes down to around 15 fps, but this area is a range that can be corrected by gamma correction. Unlike the last time I think that it is possible to confirm that the display of the box clearly showing the class is fast. And pretty accurate! ! .

By the way it was around 5.5 fps at 608 x 608, around 10.8 fps at 416 x 416. As this case has no influence of the white balance of the image, the setting around 352 x 352 (multiples of 32) for TX 2 may be the most efficient. Xavier may not be necessary when applying this source for the case. (It became cheap and it seems to continue selling for a while after succeeding at Nintendo Switch ...)

以下ofApp.cpp

 ここでのビデオ入力画像の大きさを640x480(setup()内)に設定しています。これを大きくすることでYOLOの認識率がアップするようですが、TX2にとっては結構負担になるので入力画像は小さくしています。今回YOLO側の読み込み画像が352x352なのであまり問題にならないようです。


#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.25;

cv::Mat 		mat;
ofTrueTypeFont cop20,cop50;
Detector detector(cfg_file, weights_file);
std::vector result_vec,result_vec1 ,result_vec2;
image_t xxx,yyy;
std::vector<bbox_t> 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<bbox_t> const result_vec, std::vector<std::string> 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_resized(x,640,480,thresh,false);
}
void detect_y(image_t x)
{
	    result_vec1 = detector.detect_resized(x,640,480,thresh,false);
}
//--------------------------------------------------------------
//  DetectNet部分をマルチスレッドにする。No1
class Detect_x: public ofThread {
public:
	void threadedFunction(){
		ok=false;
		detect_x(xxx);
		ok=true;
	}
	bool ok;
};
Detect_x Found_X;
//--------------------------------------------------------------
//  DetectNet部分をマルチスレッドにする。No2
class Detect_y: public ofThread {
public:
	void threadedFunction(){
		ok1=false;
		detect_y(yyy);
		ok1=true;
	}
	bool ok1;
};
Detect_y Found_Y;
int a1=0,b1=0;
//--------------------------------------------------------------
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.setup(640,480,OF_PIXELS_RGBA);
	Found_X.ok=true;
	Found_Y.ok1=true;
}
//--------------------------------------------------------------
void ofApp::update(){
bool q1,q2;
	video.update();
	if(video.isFrameNew()==true){
    img.setFromPixels(video.getPixels().getData(),video.getWidth(),video.getHeight(),OF_IMAGE_COLOR);
		mat=ofxCv::toCv(img);
        q1=false;
	    q2=false;
	  while(q1==false && q2==false){  //2つのスレッドのどちらかがスタートできるまで待つ-->全体のFPSが下がるが正確な計測ができる。
            if (Found_X.ok){
                cv::Mat imgx;
                cv::cvtColor(mat,imgx, cv::COLOR_RGB2BGR);
                std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *imgx) { detector.free_image(*imgx); delete imgx; });
			    std::shared_ptr<IplImage> ipl_small = std::make_shared<IplImage>(imgx);
                *image_ptr = ipl_to_image(ipl_small.get());
                xxx=*image_ptr;
                       
                Found_X.startThread();
                q1=true;
            }
            else if(Found_Y.ok1)  {      //elseが必要!! これでないとプログラムがハングする。
                cv::Mat imgy;
                cv::cvtColor(mat,imgy, cv::COLOR_RGB2BGR);
                std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *imgy) { detector.free_image(*imgy); delete imgy; });
			    std::shared_ptr<IplImage> ipl_small = std::make_shared<IplImage>(imgy);
                *image_ptr = ipl_to_image(ipl_small.get());
                yyy=*image_ptr;
                Found_Y.startThread();
                q2=true;
            }
      }
    }
}
//--------------------------------------------------------------
void ofApp::draw(){

    ofLog() << ofGetFrameRate();  //zissitu FPS!!
    ofSetColor(255);
    video.draw( 0, 0 );
    bool q1=false;
    bool q2=false;
    while(q1==false && q2==false){
        if (Found_X.ok){
            Found_X.lock();
            show_console_result(result_vec, obj_names);
            result_vec2=result_vec;
            Found_X.unlock();
            q1=true;
        }
        if(Found_Y.ok1) {  //els は必要なし!!スレッドが動いていなければどちらか又は両方表示させる。--->ちらつき防止
            Found_Y.lock();
            show_console_result(result_vec1, obj_names);
            result_vec2=result_vec1;
            Found_Y.unlock();
            q2=true;
        }

    }
}
//--------------------------------------------------------------
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){
}

               では。また.......。 See you !