目標檢測mAP計算方法-簡單易懂


本次將整理一份map計算方法,主要分為三部分,第一部分簡單了解原理,第二部分理解如何調用coco等相關庫得到map,第三部分教會讀者如何結合模型(任何可計算map的網絡模型)調用而生成map,而本博客希望讀者能掌握使用模型預測map,其重點也為第三部分:

 

第一部分介紹map原理,主要引用部分他人結果,

 

第二部分說明如何整理真實標簽的數據及預測數據,調用pycocotools庫實現map的計算,以下便是本博客的整理(附帶轉換coco json代碼)

 

第三部分說明如何在模型中直接預測map,即結合模型預測+本博客代碼樣列,便可預測map,樣列如下:

 

以下是根據模型運用Computer_map類主代碼,詳細,我將在第三部分展示細節代碼。

 1 def computer_main(data_root, model):
 2     '''
 3     data_root:任何文件夾,但必須保證每個圖片與對應xml必須放在同一個文件夾中
 4     model:模型,用於預測
 5     '''
 6     C = Computer_map()
 7     img_root_lst = C.get_img_root_lst(data_root)  # 獲得圖片絕對路徑與圖片產生image_id映射關系
 8 
 9     # 在self.coco_json中保存categories,便於產生coco_json和predetect_json
10     categories = model.CLASSES  # 可以給txt路徑讀取,或直接給列表  #*********************得到classes,需要更改的地方***********##
11     C.get_categories(categories)
12 
13     # 產生coco_json格式
14     xml_root_lst = [name[:-3] + 'xml' for name in img_root_lst]
15     for xml_root in xml_root_lst: C.xml2cocojson(xml_root)  # 產生coco json 並保存到self.coco_json中
16 
17     # 產生預測的json
18     for img_path in img_root_lst:
19 
20         parse_result = predict(model, img_path)  ####**********************需要更改的地方***********************####
21 
22 
23         result, classes = parse_result['result'], parse_result['classes']
24         # restult 格式為列表[x1,y1,x2,y2,score,label],若無結果為空
25         img_name = C.get_strfile(img_path)
26         C.detect2json(result, img_name)
27     C.computer_map()  # 計算map

 

 

 

 

 

 

一.map原理:

定義內容均來自此網址:https://zhuanlan.zhihu.com/p/70667071

Accuracy:准確率

✔️ 准確率=預測正確的樣本數/所有樣本數,即預測正確的樣本比例(包括預測正確的正樣本和預測正確的負樣本,不過在目標檢測領域,沒有預測正確的負樣本這一說法,所以目標檢測里面沒有用Accuracy的)。

[公式]

Precision:查准率

✔️ recision表示某一類樣本預測有多准。

✔️ Precision針對的是某一類樣本,如果沒有說明類別,那么Precision是毫無意義的(有些地方不說明類別,直接說Precision,是因為二分類問題通常說的Precision都是正樣本的Precision)。

[公式]

Recall:召回率

✔️ Recall和Precision一樣,脫離類別是沒有意義的。說道Recall,一定指的是某個類別的Recall。Recall表示某一類樣本,預測正確的與所有Ground Truth的比例。

✍️ Recall計算的時候,分母是Ground Truth中某一類樣本的數量,而Precision計算的時候,是預測出來的某一類樣本數。

[公式]

F1 Score:平衡F分數

F1分數,它被定義為查准率和召回率的調和平均數

[公式]

[公式]

更加廣泛的會定義 [公式] 分數,其中 [公式] 和 [公式] 分數在統計學在常用,並且, [公式] 分數中,召回率的權重大於查准率,而 [公式] 分數中,則相反。

[公式]

AP: Average Precision

以Recall為橫軸,Precision為縱軸,就可以畫出一條PR曲線,PR曲線下的面積就定義為AP,即:

PR曲線

由於計算積分相對困難,因此引入插值法,計算AP公式如下:

[公式]

計算面積:

原理:

[公式]

 

 

 

 

 

二.代碼-用於實現map:

 

本部分才是本博客重要內容,我將介紹2部分,第一部分如何使用有標記的真實數據產生coco json格式與如何使用模型預測結果產生預測json格式,第二部分如何使用代碼計算map。

①.json格式

真實數據json格式實際是coco json 格式,主要是如下圖:

 

 其中images格式如下圖:

 

 

annotations格式如下:

 

 categories格式為:

 

 以上為真實數據轉換為json的格式。

預測結果數據json格式轉換,主要是如下圖:

                                   

 

 以上右圖是整體結構,實際為列表,左圖是預測信息,保存為字典,其詳細內容如下:

 

 特別注意:image id 對應真實coco json圖像的image-id,類別id也是對應真實coco json中的類別id。

 ②.實際代碼,借助pycocotools 庫中評估類別,具體代碼如下圖:

 1 from pycocotools.coco import COCO
 2 from pycocotools.cocoeval import COCOeval
 3 
 4 if __name__ == "__main__":
 5     cocoGt = COCO('coco_json_format.json')        #標注文件的路徑及文件名,json文件形式
 6     cocoDt = cocoGt.loadRes('predect_format.json')  #自己的生成的結果的路徑及文件名,json文件形式
 7     cocoEval = COCOeval(cocoGt, cocoDt, "bbox")
 8     cocoEval.evaluate()
 9     cocoEval.accumulate()
10     cocoEval.summarize()

 

 

③結果展示:

 

 

 

二.代碼-模型預測map:

 

使用模型實現代碼的類:

 

模型預測map:

 

  1 class Computer_map():
  2     '''
  3     主代碼樣列
  4     def computer_main(data_root, model):#data_root:任何文件夾,但必須保證每個圖片與對應xml必須放在同一個文件夾中,model:模型,用於預測
  5         C = Computer_map()
  6         img_root_lst = C.get_img_root_lst(data_root)  # 獲得圖片絕對路徑與圖片產生image_id映射關系
  7 
  8         # 在self.coco_json中保存categories,便於產生coco_json和predetect_json
  9         categories = model.CLASSES  # 可以給txt路徑讀取,或直接給列表  #*********************得到classes,需要更改的地方***********##
 10         C.get_categories(categories)
 11 
 12         # 產生coco_json格式
 13         xml_root_lst = [name[:-3] + 'xml' for name in img_root_lst]
 14         for xml_root in xml_root_lst: C.xml2cocojson(xml_root)  # 產生coco json 並保存到self.coco_json中
 15 
 16         # 產生預測的json
 17         for img_path in img_root_lst:
 18 
 19             parse_result = predict(model, img_path)  ####**********************需要更改的地方***********************####
 20 
 21             result, classes = parse_result['result'], parse_result['classes']
 22             # restult 格式為列表[x1,y1,x2,y2,score,label],若無結果為空
 23             img_name = C.get_strfile(img_path)
 24             C.detect2json(result, img_name)
 25         C.computer_map()  # 計算map
 26 
 27     '''
 28 
 29     def __init__(self):
 30         self.img_format = ['png', 'jpg', 'JPG', 'PNG', 'bmp', 'jpeg']
 31         self.coco_json = {'images': [], 'type': 'instances', 'annotations': [], 'categories': []}
 32         self.predetect_json = []  # 保存字典
 33         self.image_id = 10000000  # 圖像的id,每增加一張圖片便+1
 34         self.anation_id = 10000000
 35         self.imgname_map_id = {}  # 圖片名字映射id
 36 
 37     def read_txt(self, file_path):
 38         with open(file_path, 'r') as f:
 39             content = f.read().splitlines()
 40         return content
 41 
 42     def get_categories(self, categories):
 43         '''
 44         categories:為字符串,指絕對路徑;為列表,指類本身
 45         return:將categories存入coco json中
 46         '''
 47         if isinstance(categories, str):
 48             categories = self.read_txt(categories)
 49         elif isinstance(categories, list or tuple):
 50             categories = list(categories)
 51 
 52         category_json = [{"supercategory": cat, "id": i + 1, "name": cat} for i, cat in enumerate(categories)]
 53         self.coco_json['categories'] = category_json
 54 
 55     def computer_map(self, coco_json_path=None, predetect_json_path=None):
 56         from pycocotools.coco import COCO
 57         from pycocotools.cocoeval import COCOeval
 58         from collections import defaultdict
 59         import time
 60         import json
 61         from pycocotools import mask as maskUtils
 62         import numpy as np
 63         # 繼承修改coco json文件
 64         class COCO_modify(COCO):
 65             def __init__(self, coco_json_data=None):
 66                 """
 67                 Constructor of Microsoft COCO helper class for reading and visualizing annotations.
 68                 :param annotation_file (str): location of annotation file
 69                 :param image_folder (str): location to the folder that hosts images.
 70                 :return:
 71                 """
 72                 # load dataset
 73                 self.dataset, self.anns, self.cats, self.imgs = dict(), dict(), dict(), dict()
 74                 self.imgToAnns, self.catToImgs = defaultdict(list), defaultdict(list)
 75                 if coco_json_data is not None:
 76                     print('loading annotations into memory...')
 77                     tic = time.time()
 78                     if isinstance(coco_json_data, str):
 79                         with open(coco_json_data, 'r') as f:
 80                             dataset = json.load(f)
 81                         assert type(dataset) == dict, 'annotation file format {} not supported'.format(type(dataset))
 82                         print('Done (t={:0.2f}s)'.format(time.time() - tic))
 83                     else:
 84                         dataset = coco_json_data
 85                     self.dataset = dataset
 86                     self.createIndex()
 87 
 88             def loadRes(self, predetect_json_data):
 89                 import copy
 90                 """
 91                 Load result file and return a result api object.
 92                 :param   resFile (str)     : file name of result file
 93                 :return: res (obj)         : result api object
 94                 """
 95                 res = COCO_modify()
 96                 res.dataset['images'] = [img for img in self.dataset['images']]
 97 
 98                 print('Loading and preparing results...')
 99                 tic = time.time()
100 
101                 if isinstance(predetect_json_data, str):
102                     with open(predetect_json_data, 'r') as f:
103                         anns = json.load(f)
104 
105                     print('Done (t={:0.2f}s)'.format(time.time() - tic))
106                 else:
107                     anns = predetect_json_data
108 
109                 assert type(anns) == list, 'results in not an array of objects'
110                 annsImgIds = [ann['image_id'] for ann in anns]
111                 assert set(annsImgIds) == (set(annsImgIds) & set(self.getImgIds())), \
112                     'Results do not correspond to current coco set'
113                 if 'caption' in anns[0]:
114                     imgIds = set([img['id'] for img in res.dataset['images']]) & set([ann['image_id'] for ann in anns])
115                     res.dataset['images'] = [img for img in res.dataset['images'] if img['id'] in imgIds]
116                     for id, ann in enumerate(anns):
117                         ann['id'] = id + 1
118                 elif 'bbox' in anns[0] and not anns[0]['bbox'] == []:
119                     res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
120                     for id, ann in enumerate(anns):
121                         bb = ann['bbox']
122                         x1, x2, y1, y2 = [bb[0], bb[0] + bb[2], bb[1], bb[1] + bb[3]]
123                         if not 'segmentation' in ann:
124                             ann['segmentation'] = [[x1, y1, x1, y2, x2, y2, x2, y1]]
125                         ann['area'] = bb[2] * bb[3]
126                         ann['id'] = id + 1
127                         ann['iscrowd'] = 0
128                 elif 'segmentation' in anns[0]:
129                     res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
130                     for id, ann in enumerate(anns):
131                         # now only support compressed RLE format as segmentation results
132                         ann['area'] = maskUtils.area(ann['segmentation'])
133                         if not 'bbox' in ann:
134                             ann['bbox'] = maskUtils.toBbox(ann['segmentation'])
135                         ann['id'] = id + 1
136                         ann['iscrowd'] = 0
137                 elif 'keypoints' in anns[0]:
138                     res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
139                     for id, ann in enumerate(anns):
140                         s = ann['keypoints']
141                         x = s[0::3]
142                         y = s[1::3]
143                         x0, x1, y0, y1 = np.min(x), np.max(x), np.min(y), np.max(y)
144                         ann['area'] = (x1 - x0) * (y1 - y0)
145                         ann['id'] = id + 1
146                         ann['bbox'] = [x0, y0, x1 - x0, y1 - y0]
147                 print('DONE (t={:0.2f}s)'.format(time.time() - tic))
148 
149                 res.dataset['annotations'] = anns
150                 res.createIndex()
151                 return res
152 
153         coco_json_data = coco_json_path if coco_json_path is not None else self.coco_json
154         cocoGt = COCO_modify(coco_json_data)  # 標注文件的路徑及文件名,json文件形式
155         predetect_json_data = predetect_json_path if predetect_json_path is not None else self.predetect_json
156         cocoDt = cocoGt.loadRes(predetect_json_data)  # 自己的生成的結果的路徑及文件名,json文件形式
157 
158         cocoEval = COCOeval(cocoGt, cocoDt, "bbox")
159         cocoEval.evaluate()
160         cocoEval.accumulate()
161         cocoEval.summarize()
162 
163     def get_img_root_lst(self, root_data):
164         import os
165         img_root_lst = []
166         for dir, file, names in os.walk(root_data):
167             img_lst = [os.path.join(dir, name) for name in names if name[-3:] in self.img_format]
168             img_root_lst = img_root_lst + img_lst
169             for na in img_lst:  # 圖片名字映射image_id
170                 self.image_id += 1
171                 self.imgname_map_id[self.get_strfile(na)] = self.image_id
172         return img_root_lst  # 得到圖片絕對路徑
173 
174     def get_strfile(self, file_str, pos=-1):
175         '''
176         得到file_str / or \\ 的最后一個名稱
177         '''
178         endstr_f_filestr = file_str.split('\\')[pos] if '\\' in file_str else file_str.split('/')[pos]
179         return endstr_f_filestr
180 
181     def read_xml(self, xml_root):
182         '''
183         :param xml_root: .xml文件
184         :return: dict('cat':['cat1',...],'bboxes':[[x1,y1,x2,y2],...],'whd':[w ,h,d])
185         '''
186 
187         import xml.etree.ElementTree as ET
188         import os
189 
190         dict_info = {'cat': [], 'bboxes': [], 'box_wh': [], 'whd': []}
191         if os.path.splitext(xml_root)[-1] == '.xml':
192             tree = ET.parse(xml_root)  # ET是一個xml文件解析庫,ET.parse()打開xml文件。parse--"解析"
193             root = tree.getroot()  # 獲取根節點
194             whd = root.find('size')
195             whd = [int(whd.find('width').text), int(whd.find('height').text), int(whd.find('depth').text)]
196             xml_filename = root.find('filename').text
197             dict_info['whd'] = whd
198             dict_info['xml_filename'] = xml_filename
199             for obj in root.findall('object'):  # 找到根節點下所有“object”節點
200                 cat = str(obj.find('name').text)  # 找到object節點下name子節點的值(字符串)
201                 bbox = obj.find('bndbox')
202                 x1, y1, x2, y2 = [int(bbox.find('xmin').text),
203                                   int(bbox.find('ymin').text),
204                                   int(bbox.find('xmax').text),
205                                   int(bbox.find('ymax').text)]
206                 b_w = x2 - x1 + 1
207                 b_h = y2 - y1 + 1
208 
209                 dict_info['cat'].append(cat)
210                 dict_info['bboxes'].append([x1, y1, x2, y2])
211                 dict_info['box_wh'].append([b_w, b_h])
212 
213         else:
214             print('[inexistence]:{} suffix is not xml '.format(xml_root))
215         return dict_info
216 
217     def xml2cocojson(self, xml_root):
218         '''
219         處理1個xml,將其真實json保存到self.coco_json中
220         '''
221         assert len(self.coco_json['categories']) > 0, 'self.coco_json[categories] must exist v'
222         categories = [cat_info['name'] for cat_info in  self.coco_json['categories']]
223         xml_info = self.read_xml(xml_root)
224         if len(xml_info['cat']) > 0:
225             xml_filename = xml_info['xml_filename']
226             xml_name = self.get_strfile(xml_root)
227             img_name = xml_name[:-3] + xml_filename[-3:]
228             # 轉為coco json時候,若add_file為True則在coco json文件的file_name增加文件夾名稱+圖片名字
229 
230             image_id = self.imgname_map_id[img_name]
231             w, h, d = xml_info['whd']
232             # 構建json文件字典
233             image_json = {'file_name': img_name, 'height': h, 'width': w, 'id': image_id}
234             ann_json = []
235             for i, category in enumerate(xml_info['cat']):
236                 # 表示有box存在,可以添加images信息
237 
238                 category_id = categories.index(category) + 1  # 給出box對應標簽索引為類
239                 self.anation_id = self.anation_id + 1
240                 xmin, ymin, xmax, ymax = xml_info['bboxes'][i]
241 
242                 o_width, o_height = xml_info['box_wh'][i]
243 
244                 if (xmax <= xmin) or (ymax <= ymin):
245                     print('code:[{}] will be abandon due to  {} min of box w or h more than max '.format(category,
246                                                                                                          xml_root))  # 打印錯誤的box
247                 else:
248                     ann = {'area': o_width * o_height, 'iscrowd': 0, 'image_id': image_id,
249                            'bbox': [xmin, ymin, o_width, o_height],
250                            'category_id': category_id, 'id': self.anation_id, 'ignore': 0,
251                            'segmentation': []}
252                     ann_json.append(ann)
253 
254             if len(ann_json) > 0:  # 證明存在 annotation
255                 for ann in ann_json:  self.coco_json['annotations'].append(ann)
256                 self.coco_json['images'].append(image_json)
257 
258     def detect2json(self, predetect_result, img_name,score_thr=-1):
259         '''
260         predetect_result:為列表,每個列表中包含[x1, y1, x2, y2, score, label]
261         img_name: 圖片的名字
262         '''
263         if len(predetect_result) > 0:
264             categories = [cat_info['name'] for cat_info in  self.coco_json['categories']]
265             for result in predetect_result:
266                 x1, y1, x2, y2, score, label = result
267                 if score>score_thr:
268                     w, h = int(x2 - x1), int(y2 - y1)
269                     x1, y1 = int(x1), int(y1)
270                     img_name_new = self.get_strfile(img_name)
271                     image_id = self.imgname_map_id[img_name_new]
272                     category_id = list(categories).index(label) + 1
273                     detect_json = {
274                         "area": w * h,
275                         "iscrowd": 0,
276                         "image_id": image_id,
277                         "bbox": [
278                             x1,
279                             y1,
280                             w,
281                             h
282                         ],
283                         "category_id": category_id,
284                         "id": image_id,
285                         "ignore": 0,
286                         "segmentation": [],
287                         "score": score
288                     }
289                     self.predetect_json.append(detect_json)
290 
291     def write_json(self,out_dir):
292         import os
293         import json
294         coco_json_path=os.path.join(out_dir,'coco_json_data.json')
295         with open(coco_json_path, 'w') as f:
296             json.dump(self.coco_json, f, indent=4)  # indent表示間隔長度
297         predetect_json_path=os.path.join(out_dir,'predetect_json_data.json')
298         with open(predetect_json_path, 'w') as f:
299             json.dump(self.predetect_json, f, indent=4)  # indent表示間隔長度

 

結果展示:左圖為mmdet2.19模型結果,右圖為yolov5模型結果

 

 

 

 

 

 

 

 

 

 

 

 

 

附帶xml轉換coco json代碼:

 

  1 import os
  2 import json
  3 import xml.etree.ElementTree as ET
  4 import cv2  # 無xml時候需要讀取圖片高與寬
  5 # from cope_data.cope_utils import *
  6 from tqdm import tqdm
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 def read_xml(xml_root):
 16     '''
 17     :param xml_root: .xml文件
 18     :return: dict('cat':['cat1',...],'bboxes':[[x1,y1,x2,y2],...],'whd':[w ,h,d])
 19     '''
 20     dict_info = {'cat': [], 'bboxes': [], 'box_wh': [], 'whd': []}
 21     if os.path.splitext(xml_root)[-1] == '.xml':
 22         tree = ET.parse(xml_root)  # ET是一個xml文件解析庫,ET.parse()打開xml文件。parse--"解析"
 23         root = tree.getroot()  # 獲取根節點
 24         whd = root.find('size')
 25         whd = [int(whd.find('width').text), int(whd.find('height').text), int(whd.find('depth').text)]
 26         xml_filename = root.find('filename').text
 27         dict_info['whd']=whd
 28         dict_info['xml_filename']=xml_filename
 29         for obj in root.findall('object'):  # 找到根節點下所有“object”節點
 30             cat = str(obj.find('name').text)  # 找到object節點下name子節點的值(字符串)
 31             bbox = obj.find('bndbox')
 32             x1, y1, x2, y2 = [int(bbox.find('xmin').text),
 33                               int(bbox.find('ymin').text),
 34                               int(bbox.find('xmax').text),
 35                               int(bbox.find('ymax').text)]
 36             b_w = x2 - x1 + 1
 37             b_h = y2 - y1 + 1
 38 
 39             dict_info['cat'].append(cat)
 40             dict_info['bboxes'].append([x1, y1, x2, y2])
 41             dict_info['box_wh'].append([b_w, b_h])
 42 
 43     else:
 44         print('[inexistence]:{} suffix is not xml '.format(xml_root))
 45     return dict_info
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 # xml轉換為訓練集
 54 def train_multifiles(root_data, json_name='train.json', categories=None, out_dir=None, add_file=False,refuse_category=[],category_path=None):
 55     '''
 56     json文件中的file_name包含文件夾/名字
 57     :param json_name: 保存json文件名字,最終結果在out_dir+json_name(若out_dir有路徑情況),否則在root_data下面
 58     :param categories: 類別信息,為None則將self.root文件夾的名字作為類別信息
 59     add_file :True表示cocojson中添加文件名,否則不添加
 60     refuse_category:拒絕裝換為cocojson的類的列表
 61     :return:
 62     '''
 63 
 64 
 65 
 66     def read_txt(file_path):
 67         with open(file_path, 'r') as f:
 68             content = f.read().splitlines()
 69         return content
 70     def write_txt(text_lst, out_dir):
 71         '''
 72         每行內容為列表,將其寫入text中
 73         '''
 74         file_write_obj = open(out_dir, 'w')  # 以寫的方式打開文件,如果文件不存在,就會自動創建
 75         for text in text_lst:
 76             file_write_obj.writelines(text)
 77             file_write_obj.write('\n')
 78         file_write_obj.close()
 79         return out_dir
 80 
 81     def get_strfile(file_str, pos=-1):
 82         '''
 83         得到file_str / or \\ 的最后一個名稱
 84         '''
 85         endstr_f_filestr = file_str.split('\\')[pos] if '\\' in file_str else file_str.split('/')[pos]
 86         return endstr_f_filestr
 87 
 88     # coco json文件格式
 89     json_dict = {"images": [], "type": "instances", "annotations": [], "categories": []}
 90     image_id = 10000000
 91     anation_id = 10000000
 92     xml_root_lst = []
 93     for dir, dir_file, dir_names in os.walk(root_data):
 94         name_lst = [os.path.join(dir, name) for name in dir_names if name[-3:] == 'xml']
 95         xml_root_lst = xml_root_lst + name_lst
 96     if category_path is None:
 97         if categories is None:
 98             categories = []
 99         elif isinstance(categories, list):
100             categories = categories
101         else:
102             raise IOError('categories must be list or None')
103     else:
104         categories=read_txt(category_path)
105 
106 
107     count_categories = {}
108     for xml_root in tqdm(xml_root_lst):
109         try:
110             xml_info=read_xml(xml_root)
111             if len(xml_info['cat'])>0:
112                 xml_filename = xml_info['xml_filename']
113                 xml_name = get_strfile(xml_root)
114                 img_name = xml_name[:-3] + xml_filename[-3:]
115                 # 轉為cocojson時候,若add_file為True則在cocojson文件的file_name增加文件夾名稱+圖片名字
116                 file_name = get_strfile(xml_root, pos=-2) + '/' + img_name  if add_file else img_name  # 只記錄圖片名字
117 
118                 image_id = image_id + 1
119 
120                 w,h,d=xml_info['whd']
121                 # 構建json文件字典
122                 image = {'file_name': file_name, 'height': h, 'width': w, 'id': image_id}
123                 for i, category in enumerate(xml_info['cat']):
124 
125                     if category  in refuse_category:
126                         print('refuse {} code will not convert coojson format '.format(category))
127                         continue
128                     # 若categories列表不包含該code則增加該code到列表中
129                     if category not in categories and category_path is None:
130                         categories.append(category)
131                     # 計數每個cat的數量
132                     count_categories[category]=1  if category not in count_categories else count_categories[category]+1
133 
134 
135                     # 表示有box存在,可以添加images信息
136                     if image not in json_dict['images']:
137                         json_dict['images'].append(image)  # 將圖像信息添加到json中
138                     category_id = categories.index(category) + 1  # 給出box對應標簽索引為類
139                     anation_id = anation_id + 1
140                     xmin,ymin,xmax,ymax=xml_info['bboxes'][i]
141 
142                     o_width,o_height=xml_info['box_wh'][i]
143 
144                     if (xmax <= xmin) or (ymax <= ymin):
145                         print('code:[{}] will be abandon due to  {} min of box w or h more than max '.format(category,xml_root))  # 打印錯誤的box
146 
147                     else:
148                         ann = {'area': o_width * o_height, 'iscrowd': 0, 'image_id': image_id,
149                                'bbox': [xmin, ymin, o_width, o_height],
150                                'category_id': category_id, 'id': anation_id, 'ignore': 0,
151                                'segmentation': []}
152                         json_dict['annotations'].append(ann)
153         except:
154             print('xml file: {} not read error!'.format(xml_root))
155 
156 
157     for cid, cate in enumerate(categories):
158         cat = {'supercategory': cate, 'id': cid + 1, 'name': cate}
159         json_dict['categories'].append(cat)
160     if out_dir is not None:
161         build_dir(self.out_dir)
162         out_dir = os.path.join(out_dir, json_name)
163         out_dir_txt=os.path.join(out_dir, 'classes.txt')
164     else:
165         out_dir = os.path.join(root_data, json_name)
166         out_dir_txt = os.path.join(root_data, 'classes.txt')
167     with open(out_dir, 'w') as f:
168         json.dump(json_dict, f, indent=4)  # indent表示間隔長度
169 
170     write_txt(categories,out_dir_txt)
171 
172 
173     print('categories count : \n',count_categories)
174 
175 
176 
177 
178 if __name__ == '__main__':
179     root_path = r'D:\DATA\coco2017_train_val\data_coco_clear_2017\val'
180     category_path=r'D:\DATA\coco2017_train_val\data_coco_clear_2017\classes.txt'
181     train_multifiles(root_path,category_path=category_path)
xml2cocojson

 

 

 

 

 

 

 

 

 

借鑒博客:https://blog.csdn.net/qq_35916487/article/details/89076570

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM