1. 程式人生 > >基於yolo提取車和人的檢測與影象裁剪

基於yolo提取車和人的檢測與影象裁剪

   這次換一個嚴謹的寫作風格。因為之前在做yolo演算法移植到ros上面,已經成功了,但是實驗室老師又出了做姿勢識別的么蛾子。我真是一萬個。。。。無語了。感覺,對深度學習只有一個簡單的瞭解,現在還在讀很多有關的論文,一邊看cs231n的課程,在自學著入門。但是奈何自己的實戰能力太差,實戰經驗太少了,只是學過那一年的c,很多關於指標的操作什麼的,真的太差了,現在還在教一個小孩c語言,我都不好意思教人家了,決定從這星期開始,每天刷一些c的基礎知識題,真的得好好補補了。

    回到正題,環境仍然是ubuntu16.04+cuda9.0+NVIDIA GTX1050+OPENCV3.4.1,首先解決第一個問題,在yolo的基礎上,提取人和車,其他的標籤過濾掉。有兩個解決方法,一個是自己訓練車和人的訓練庫,另一個就是在程式中剔除出人和車以外的標籤。第一個方法原來想做一下,但是看網上真正做過的,可能要訓練一個星期,而且可能需要在伺服器上訓練,因為真的沒做過,時間催的很緊,只能採取第二種方法了,等後面有時間了,一定自己訓練一下,試一下,真正做過才能有話語權。那就來說一下,是怎麼在程式裡面實現的剔除其他標籤的。首先,要明確是在,image.c裡面的draw_detections這個函式裡面去改動。

for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        for(j = 0; j < classes; ++j){
            if (probs[i][j] > thresh){
            printf("probs:%f\n", probs[i][j]);
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    class = j;
                } else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                }
                printf("%s: %.0f%%\n", names[j], probs[i][j]*100);
            }

        }

    在這個for迴圈裡,num是檢測到的物體個數,classes是能夠檢測的物體種類,這裡的classes是80,說明yolov2能檢測80個種類的物體,這裡的for迴圈在篩選概率大於閾值然後輸出概率的類別和大小。

int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;

            int bot   = (b.y+b.h/2.)*im.h;

    這裡獲得預檢測區域(bounding box)的位置。下面就該新增我自己的程式。

    bool Is_person = false;
            bool Is_car = false;
            
        Is_person = !strcmp(labelstr, "person");
        Is_car = !strcmp(labelstr, "car");
        Is_car = !strcmp(labelstr, "truck");

        if(Is_person || Is_car)
        {

                draw_box_width(im, left, top, right, bot, width, red, green, blue);
                if (alphabet) {
                    image label = get_label(alphabet, labelstr, (im.h*.03)/10);
                    draw_label(im, top + width, left, label, rgb);
                    free_image(label);
                }//這一部分在給已經畫出框的物體打label,追蹤這裡的draw_label就會發現他的標籤是通過索引拼在一起的
                if (masks){
                    image mask = float_to_image(14, 14, 1, masks[i]);
                    image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
                    image tmask = threshold_image(resized_mask, .5);
                    embed_image(tmask, im, left, top);
                    free_image(mask);
                    free_image(resized_mask);
                    free_image(tmask);
                }

    所以,通過這段程式碼就可以篩選出來只是人和車的,因為車的種類有很多,但是我只選出來了car和truck這兩個標籤,後面再看看是否有更多的關於車的標籤。

    因為實驗室要求做姿態識別,類似交警的指揮手勢,什麼手勢識別出來是向左轉什麼是向右轉。之前也查閱了一些姿態估計和骨骼識別的資料,但是感覺出來的效果來達到老師們所要求的還有點遠。現在想的是,先在yolo上面把檢測出來的人分割出來,在這個影象上做些其他特徵的識別。比如:輪廓識別。但是這又涉及到背景是否複雜等等。所以還沒有考慮到後面,現在只是,先把人從原始影象中裁剪出來。

    因為原始碼對影象的處理是用的一維陣列,所以要想在原影象上裁剪ROI區域我還採用的,先把一維陣列轉化成二維影象,然後再用opencv的函式進行影象裁剪。

   這段程式碼在darknet_ros包上改的,因為darknet_ros包和darknet的原始碼還是有一點點不一樣,darknet_ros包檢測動態視訊的時候用的就是draw_detections這個函式,而原始碼裡面,這個函式只是在檢測圖片時用的這個函式。

    所以在程式裡面就自己仿照他的寫法把原始碼中的image結構體中存放的一維陣列轉化成二維影象類在image.c裡面定義:

void Image_to_iplimage(image im, IplImage* img)
{
    int x, y, k;

    image copy = copy_image(im);

    if(copy.c == 3) rgbgr_image(copy);

    int step = img->widthStep;

    for(y = 0; y < copy.h; ++y){
        for(x = 0; x < copy.w; ++x){
            for(k= 0; k < copy.c; ++k){
                img->imageData[y*step + x*copy.c + k] = (unsigned char)(get_pixel(copy,x,y,k)*255);
            }
        }
    }

}


通過這個函式就可以把一維陣列類轉換成二維影象類。

void draw_detections_1(image im, int num, float thresh, box *boxes, float **probs, float **masks, char **names, image **alphabet, int classes, box *target_box)
{
    int i,j;

    for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        for(j = 0; j < classes; ++j){
            if (probs[i][j] > thresh){
            printf("probs:%f\n", probs[i][j]);
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    class = j;
                } else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                }
                printf("%s: %.0f%%\n", names[j], probs[i][j]*100);
            }
        }

    /***這裡應該找出站的最近的人進行分割,因為視野當中可能有多個人,no code***/
        if(class >= 0){
            int width = im.h * .006;

            /*
               if(0){
               width = pow(prob, 1./2.)*10+1;
               alphabet = 0;
               }
             */

            //printf("%d %s: %.0f%%\n", i, names[class], prob*100);
            int offset = class*123457 % classes;
            float red = get_color(2,offset,classes);
            float green = get_color(1,offset,classes);
            float blue = get_color(0,offset,classes);
            float rgb[3];

            //width = prob*20+2;

            rgb[0] = red;
            rgb[1] = green;
            rgb[2] = blue;
            box b = boxes[i];

            int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;
            int bot   = (b.y+b.h/2.)*im.h;

            if(left < 0) left = 0;
            if(right > im.w-1) right = im.w-1;
            if(top < 0) top = 0;
            if(bot > im.h-1) bot = im.h-1;

        bool Is_person = false;
            bool Is_car = false;
            
        Is_person = !strcmp(labelstr, "person");
        Is_car = !strcmp(labelstr, "car");
        Is_car = !strcmp(labelstr, "truck");

        if(Is_person || Is_car)
        {
        target_box->x = left*1.0;
        target_box->y = top*1.0;
                target_box->w = (right - left)*1.0;
        target_box->h = (bot - top)*1.0;
        
                draw_box_width(im, left, top, right, bot, width, red, green, blue);
                if (alphabet) {
                    image label = get_label(alphabet, labelstr, (im.h*.03)/10);
                    draw_label(im, top + width, left, label, rgb);
                    free_image(label);
                }
                if (masks){
                    image mask = float_to_image(14, 14, 1, masks[i]);
                    image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
                    image tmask = threshold_image(resized_mask, .5);
                    embed_image(tmask, im, left, top);
                    free_image(mask);
                    free_image(resized_mask);
                    free_image(tmask);
                }
        }
        }
    }
}



因為我們想要得到bounding box的座標區域,所以我們需要draw_detections這個函式把bounding box的引數傳回主函式,所以要加一個引數,又因為,draw_detections這個函式用到很多地方,所以我就仿照draw_detections寫了一個相同的函式,只是多了一個傳回來的引數,void draw_detections_1(image im, int num, float thresh, box *boxes, float **probs, float **masks, char **names, image **alphabet, int classes, box *target_box)。

    目前就先寫這樣,後期會陸陸續續更關於yolo演算法本身的原理,只不過可能又要到後面了,最近可能還要做一些影象分割或者骨骼識別的東西。

    最後的最後,還是要感謝我的王叔叔,男票大神啊,每次都是跟著他的指導,我才能完成任務,謝謝王叔叔。