# 利用eval()讀取物體及對(duì)應(yīng)顏色信息到數(shù)據(jù)
@staticmethod
def load_labels(filepath):
label_colors = {}
with open(filepath, 'r') as f:
line = f.readline().rstrip()
while line:
label, color = eval(line)
label_colors[label] = color
line = f.readline().rstrip()
return label_colors
# 讀取圖像文件和對(duì)應(yīng)標(biāo)注框信息(如果有的話)
@staticmethod
def load_sample(filepath):
img = cv2.imread(filepath)
bbox_filepath = get_bbox_name(filepath)
bboxes = []
if os.path.exists(bbox_filepath):
bboxes = SimpleBBoxLabeling.load_bbox(bbox_filepath)
return img, bboxes
# 導(dǎo)出當(dāng)前標(biāo)注框信息并清空
def _export_n_clean_bbox(self):
bbox_filepath = os.sep.join([self._data_dir, get_bbox_name(self._filelist[self._index])])
self.export_bbox(bbox_filepath, self._bboxes)
self._clean_bbox()
# 刪除當(dāng)前樣本和對(duì)應(yīng)的標(biāo)注框信息
def _delete_current_sample(self):
filename = self._filelist[self._index]
filepath = os.sep.join([self._data_dir, filename])
if os.path.exists(filepath):
os.remove(filepath)
filepath = get_bbox_name(filepath)
if os.path.exists(filepath):
os.remove(filepath)
self._filelist.pop(self._index)
print('{} is deleted!'.format(filename))
# 開(kāi)始OpenCV窗口循環(huán)的方法,定義了程序的主邏輯
def start(self):
# 之前標(biāo)注的文件名,用于程序判斷是否需要執(zhí)行一次圖像讀取
last_filename = ''
# 標(biāo)注物體在列表中的下標(biāo)
label_index = 0
# 所有標(biāo)注物體名稱的列表
labels = self.label_colors.keys()
# 待標(biāo)注物體的種類數(shù)
n_labels = len(labels)
# 定義窗口和鼠標(biāo)回調(diào)
cv2.namedWindow(self.window_name)
cv2.setMouseCallback(self.window_name, self._mouse_ops)
key = KEY_EMPTY
# 定義每次循環(huán)的持續(xù)時(shí)間
delay = int(1000 / FPS)
# 只要沒(méi)有按下Esc鍵,就持續(xù)循環(huán)
while key != KEY_ESC:
# 上下鍵用于選擇當(dāng)前標(biāo)注物體
if key == KEY_UP:
if label_index == 0:
pass
else:
label_index -= 1
elif key == KEY_DOWN:
if label_index == n_labels - 1:
pass
else:
label_index += 1
# 左右鍵切換當(dāng)前標(biāo)注的圖片
elif key == KEY_LEFT:
# 已經(jīng)到了第一張圖片的話就不需要清空上一張
if self._index > 0:
self._export_n_clean_bbox()
self._index -= 1
if self._index < 0:
self._index = 0
elif key == KEY_RIGHT:
# 已經(jīng)到了最后一張圖片的話就不需要清空上一張
if self._index < len(self._filelist) - 1:
self._export_n_clean_bbox()
self._index += 1
if self._index > len(self._filelist) - 1:
self._index = len(self._filelist) - 1
# 刪除當(dāng)前圖片和對(duì)應(yīng)標(biāo)注信息
elif key == KEY_DELETE:
if askyesno('Delete Sample', 'Are you sure?'):
self._delete_current_sample()
key = KEY_EMPTY
continue
# 如果鍵盤(pán)操作執(zhí)行了換圖片,則重新讀取,更新圖片
filename = self._filelist[self._index]
if filename != last_filename:
filepath = os.sep.join([self._data_dir, filename])
img, self._bboxes = self.load_sample(filepath)
# 更新當(dāng)前標(biāo)注物體名稱
self._cur_label = labels[label_index]
# 把標(biāo)注和相關(guān)信息畫(huà)在圖片上并顯示指定的時(shí)間
canvas = self._draw_bbox(img)
cv2.imshow(self.window_name, canvas)
key = cv2.waitKey(delay)
# 當(dāng)前文件名就是下次循環(huán)的老文件名
last_filename = filename
print('Finished!')
cv2.destroyAllWindows()
# 如果退出程序,需要對(duì)當(dāng)前進(jìn)行保存
self.export_bbox(os.sep.join([self._data_dir, get_bbox_name(filename)]), self._bboxes)
print('Labels updated!')
if __name__ == '__main__':
dir_with_images = askdirectory(title='Where are the images?')
labeling_task = SimpleBBoxLabeling(dir_with_images)
labeling_task.start()
需要注意的是幾個(gè)比較通用且獨(dú)立的方法前加上了一句@staticmethod,表明是個(gè)靜態(tài)方法。執(zhí)行這個(gè)程序,并選擇samples文件夾,標(biāo)注時(shí)的畫(huà)面如下圖:
評(píng)論
查看更多