製作目標檢測數據集(通過鼠標事件)

製作目標檢測數據集(通過鼠標事件)

前言

當我們在做目標檢測的實驗時,我們可能需要自己製作一個數據集。且這些目標檢測有關的數據集很多通過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)

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章