darknet原始碼剖析(六)
阿新 • • 發佈:2019-02-06
繼續分析load_data_detection,進入fill_truth_detection函式。fill_truth_detection的作用是讀取圖片對應的標註資訊。
首先進入find_replace函式。
void find_replace(char *str, char *orig, char *rep, char *output) { char buffer[4096] = {0}; char *p; sprintf(buffer, "%s", str); if(!(p = strstr(buffer, orig))){ // Is 'orig' even in 'str'? sprintf(output, "%s", str); return; } *p = '\0'; sprintf(output, "%s%s%s", buffer, rep, p+strlen(orig)); }
該函式的作用是首先查詢orig是否存在,若不存在則將str的值直接賦給output並返回;若存在則將orig替換為rep。
find_replace(path, "images", "labels", labelpath);
find_replace(labelpath, "JPEGImages", "labels", labelpath);
find_replace(labelpath, "raw", "labels", labelpath);
從以上程式碼可以知道,圖片可以存放在images、JPEGImages、raw路徑下,上述路徑會被替換為labels。上述程式碼同時說明標籤檔案需要放置在labels資料夾下。
find_replace(labelpath, ".jpg", ".txt", labelpath);
find_replace(labelpath, ".png", ".txt", labelpath);
find_replace(labelpath, ".JPG", ".txt", labelpath);
find_replace(labelpath, ".JPEG", ".txt", labelpath);
上述程式碼的功能是將*.jpg/png/JPG/JPEG替換為*.txt,同時表明darknet僅支援jpg與png兩種格式。
獲取標籤路徑後,讀取標註。
box_label *boxes = read_boxes(labelpath, &count);
randomize_boxes(boxes, count);
correct_boxes(boxes, count, dx, dy, sx, sy, flip);
呼叫read_boxes讀取標註資料,randomize_boxes隨機交換標註資料順序,correct_boxes根據圖片調整比例,調整標註框的大小。
read_boxes函式如下:
box_label *read_boxes(char *filename, int *n)
{
FILE *file = fopen(filename, "r");
if(!file) file_error(filename);
float x, y, h, w;
int id;
int count = 0;
int size = 64;
box_label *boxes = calloc(size, sizeof(box_label));
while(fscanf(file, "%d %f %f %f %f", &id, &x, &y, &w, &h) == 5){
if(count == size) {
size = size * 2;
boxes = realloc(boxes, size*sizeof(box_label));
}
boxes[count].id = id;
boxes[count].x = x;
boxes[count].y = y;
boxes[count].h = h;
boxes[count].w = w;
boxes[count].left = x - w/2;
boxes[count].right = x + w/2;
boxes[count].top = y - h/2;
boxes[count].bottom = y + h/2;
++count;
}
fclose(file);
*n = count;
return boxes;
}
通過left、right、top、bottom的計算方法,可以知曉x、y是物體的中心位置。同時x、y、w、h需要注意是歸一化後的結果。
這一點可以從產生的voc標註的程式碼驗證,在yolo官網中可以下載該工具,在generate_annotation/voc_label.py中。
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
回到darknet程式碼中。
if(count > num_boxes) count = num_boxes;
float x,y,w,h;
int id;
int i;
int sub = 0;
若標註數量大於num_boxes則將count設為num_boxes,表明會隨機的丟棄一些標註框。僅取前num_boxes個框,因此需要呼叫randomize_boxes函式,調整標註框的順序。
for (i = 0; i < count; ++i) {
x = boxes[i].x;
y = boxes[i].y;
w = boxes[i].w;
h = boxes[i].h;
id = boxes[i].id;
if ((w < .001 || h < .001)) {
++sub;
continue;
}
truth[(i-sub)*5+0] = x;
truth[(i-sub)*5+1] = y;
truth[(i-sub)*5+2] = w;
truth[(i-sub)*5+3] = h;
truth[(i-sub)*5+4] = id;
}
free(boxes);
最後將boxes的資訊放入truth中,w或h小於0.001,則捨棄該標註框。