製作目標檢測數據集(通過鼠標事件)
前言
當我們在做目標檢測的實驗時,我們可能需要自己製作一個數據集。且這些目標檢測有關的數據集很多通過xml文件進行保存。
之前在做簡單的圖像分割時,使用過鼠標事件來進行‘摳圖’,所以想着能不能將鼠標事件應用到目標檢測數據的獲取上呢?
本文通過鼠標標定,獲取數據並打印到txt文件中,再將txt文件轉換爲xml文件,以便後續實驗進行操作。
通過鼠標事件框定目標
首先我們介紹兩個處理鼠標動作的函數
-
回調函數(自己構造):
#event指鼠標操作控制,(x,y)指圖片中標定的座標位置,flags指鼠標和鍵盤合作命令效果 def on_Event(event,x,y,flags,param):
-
setMouseCallback()函數
cv2.setMouseCallback('image',on_Event)
Event | 操作 |
---|---|
EVENT_MOUSEMOVE | 滑動 |
EVENT_LBUTTONDOWN | 左鍵點擊 |
EVENT_RBUTTONDOWN | 右鍵點擊 |
EVENT_MBUTTONDOWN | 中鍵點擊 |
EVENT_LBUTTONUP | 左鍵放開 |
EVENT_RBUTTONUP | 右鍵放開 |
EVENT_MBUTTONUP | 中鍵放開 |
EVENT_LBUTTONDBLCL | 左鍵雙擊 |
EVENT_RBUTTONDBLCL | 右鍵雙擊 |
EVENT_MBUTTONDBLCL | 中鍵雙擊 |
# coding: utf-8
import cv2
import numpy as np
import glob
import os
#img = cv2.imread("D:/desktop/data/images/P0007_0512_0000.png")
# 圖像存儲位置(文件夾)
src_img_dir = "D:/desktop/333/images"
#這是txt文件的儲存位置(標註後自動生成)
src_txt_dir = 'D:/desktop/333/annotations'
'''
filenum = 0
for lists in os.listdir(src_img_dir):
filenum += 1
print(lists)
print(filenum)
'''
#找該文件下的圖片文件
img_Lists = glob.glob(src_img_dir + '/*.png')
print(img_Lists)
img_basenames = [] #文件名加文件類型
for item in img_Lists:
img_basenames.append(os.path.basename(item))
img_names = [] #文件名
for item in img_basenames:
temp1, temp2 = os.path.splitext(item)
img_names.append(temp1)
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
#打開txt文件,在txt中存放座標信息
file_handle=open(src_txt_dir + '/' + im +'.txt',mode='a')
#這裏左擊保存信息
if event == cv2.EVENT_LBUTTONDOWN:
xy = "%d,%d" % (x, y)
print(x,y) #(x,y)分別爲目標框的左上和右下座標
file_handle.write("%d %d\n"%(x,y))
cv2.circle(img, (x, y), 1, (255, 0, 0), thickness = -1)
cv2.putText(img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
1.0, (0,0,0), thickness = 1)
cv2.imshow("image", img)
file_handle.close()
for im in img_names:
img = cv2.imread(src_img_dir + '/' + im + '.png')
cv2.namedWindow("image")
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN) #cv2.setMouseCallback
cv2.imshow("image", img)
while(True):
try:
cv2.waitKey(100)
except Exception:
cv2.destroyWindow("image")
break
cv2.waitKey(0)
cv2.destroyAllWindow()
效果如圖:
txt文件轉化爲xml文件
# ! /usr/bin/python
# -*- coding:UTF-8 -*-
import os, sys
import glob
from PIL import Image
#圖像存儲位置
src_img_dir = "D:/desktop/333/images/"
#圖像的ground truth的txt 文件存放位置
src_txt_dir = "D:/desktop/333/annotations/"
# 生成xml文件存放位置
src_xml_dir = "D:/desktop/333/"
img_Lists = glob.glob(src_img_dir + '/*.png')
img_basenames = [] # e.g. 100.jpg
for item in img_Lists:
img_basenames.append(os.path.basename(item))
img_names = [] # e.g. 100
for item in img_basenames:
temp1, temp2 = os.path.splitext(item)
img_names.append(temp1)
for img in img_names:
im = Image.open((src_img_dir + '/' + img + '.png'))
try:
gt = open(src_txt_dir + '/' + img + '.txt').read().splitlines()
except:
continue #跳過這次循環,進入下一張圖片循環
myfile = open(src_txt_dir + '/' + img + '.txt')
lines = len(myfile.readlines())
print(lines)
xml_file = open((src_xml_dir + '/' + img + '.xml'), 'w')
xml_file.write('<?xml version="1.0" ?>\n')
xml_file.write('<annotation>\n')
xml_file.write('<folder>VOC2007</folder>\n')
xml_file.write('<filename>' + '000024' + '.jpg' + '</filename>\n')
xml_file.write('<source>\n')
xml_file.write('<database>The VOC2007 Database</database>\n')
xml_file.write('<annotation>PASCAL VOC2007</annotation>\n')
xml_file.write('<image>flickr</image>\n')
xml_file.write('<flickrid>322409915</flickrid>\n')
xml_file.write('</source>\n')
xml_file.write('<owner>\n')
xml_file.write('<flickrid>knautia</flickrid>\n')
xml_file.write('<name>yang</name>\n')
xml_file.write('</owner>\n')
xml_file.write('<size>\n')
xml_file.write('<width>' + '800' + '</width>\n')
xml_file.write('<height>' + '800' + '</height>\n')
xml_file.write('<depth>0</depth>\n')
xml_file.write('</size>\n')
xml_file.write('<segmented>0</segmented>\n')
i=0
for i in range(lines):
spt = gt[i].split(' ')
print(spt)
#由於製作的txt奇數行是xmin和ymin,偶數行是xmax和ymax,所以這裏我們用 i%2 判斷一下
if i%2 == 0:
xml_file.write('<object>\n')
xml_file.write('<name>' + 'large-vehicle' + '</name>\n') #類別名稱
xml_file.write('<pose>Unspecified</pose>\n')
xml_file.write('<truncated>1</truncated>\n')
xml_file.write('<difficult>0</difficult>\n')
xml_file.write('<bndbox>\n')
xml_file.write('<xmin>' + str(spt[0]) + '</xmin>\n')
xml_file.write('<ymin>' + str(spt[1]) + '</ymin>\n')
i += 1
else:
xml_file.write('<xmax>' + str(spt[0]) + '</xmax>\n')
xml_file.write('<ymax>' + str(spt[1]) + '</ymax>\n')
xml_file.write('</bndbox>\n')
xml_file.write('</object>\n')
i += 1
xml_file.write('</annotation>')
print('finish {}'.format(img))
結果可視化
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os,cv2
#xml文件
xml_file='D:/desktop/Pretreatment/xml/P0004_0000_0000.xml'
tree=ET.parse(xml_file)
root=tree.getroot()
#圖片文件
imgfile='D:/desktop/data/images/P0004_0000_0000.png'
im = cv2.imread(imgfile)
for object in root.findall('object'):
#找xml內的數據
object_name=object.find('name').text
Xmin=int(object.find('bndbox').find('xmin').text)
Ymin=int(object.find('bndbox').find('ymin').text)
Xmax=int(object.find('bndbox').find('xmax').text)
Ymax=int(object.find('bndbox').find('ymax').text)
#cv2框定的基本操作
color = (4, 250, 7)
cv2.rectangle(im,(Xmin,Ymin),(Xmax,Ymax),color,2)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(im, object_name, (Xmin,Ymin - 7), font, 0.5, (6, 230, 230), 2)
cv2.imshow('2',im)
cv2.imwrite('D:/desktop/5.png', im)