python实现一个简单的【图像中物体坐标】标注小工具
有时候需要对于数据集进行预处理,通过标注获取坐标信息,再进行后续的操作。使用python能够快速读取图片,并能够通过人工标注,记录一下每个点的横竖坐标,如下记录学习笔记。
参考链接:https://lcqbit11.blog.csdn.net/article/details/69951249
参考链接:https://blog.csdn.net/wuzuyu365/article/details/52523061?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242
参考链接:https://blog.csdn.net/qq_26697045/article/details/101461525
参考链接:https://www.jb51.net/article/157968.htm
源码
整个目录的结构如下:
根目录
——images:存放图片
——outputs:存放标注坐标信息
图片存放位置:E:\Python\biaozhu\images\001(图片仅仅是用来测试的,应存放数据集)
from __future__ import division
import tkinter as tk
from tkinter import Frame
from tkinter import BOTH
from tkinter import *
import tkinter.messagebox
from PIL import Image, ImageTk
import os
import glob
import random w0 = 1; #图片原始宽度
h0 = 1; #图片原始高度 # colors for the bboxes
COLORS = ['red', 'blue', 'yellow', 'pink', 'cyan', 'green', 'black']
# image sizes for the examples
SIZE = 960, 600 #指定缩放后的图像大小
DEST_SIZE = 960, 600 class LabelTool(): def __init__(self, master): # set up the main frame self.parent = master self.parent.title("图像标注") self.frame = Frame(self.parent) self.frame.pack(fill=BOTH, expand=1) self.parent.resizable(width = TRUE, height = TRUE) # initialize global state self.imageDir = '' self.imageList= [] self.egDir = '' self.egList = [] self.outDir = '' self.cur = 0 self.total = 0 self.category = 0 self.imagename = '' self.labelfilename = '' self.tkimg = None # initialize mouse state self.STATE = {} self.STATE['click'] = 0 self.STATE['x'], self.STATE['y'] = 0, 0 # reference to bbox self.bboxIdList = [] self.bboxId = None self.bboxList = [] self.hl = None self.vl = None # ----------------- GUI stuff --------------------- # dir entry & load self.label = Label(self.frame, text = "Image Dir:") self.label.grid(row = 0, column = 0, sticky = E) self.entry = Entry(self.frame) self.entry.grid(row = 0, column = 1, sticky = W+E) self.ldBtn = Button(self.frame, text = "Load", command = self.loadDir) self.ldBtn.grid(row = 0, column = 2, sticky = W+E) # main panel for labeling self.mainPanel = Canvas(self.frame, cursor='tcross') self.mainPanel.bind("<Button-1>", self.mouseClick) self.mainPanel.bind("<Motion>", self.mouseMove) self.parent.bind("<Escape>", self.cancelBBox) # press <Espace> to cancel current bbox self.parent.bind("s", self.cancelBBox) self.parent.bind("a", self.prevImage) # press 'a' to go backforward self.parent.bind("d", self.nextImage) # press 'd' to go forward self.mainPanel.grid(row = 1, column = 1, rowspan = 4, sticky = W+N) # showing bbox info & delete bbox self.lb1 = Label(self.frame, text = 'Bounding boxes:') self.lb1.grid(row = 1, column = 2, sticky = W+N) self.listbox = Listbox(self.frame, width = 28, height = 12) self.listbox.grid(row = 2, column = 2, sticky = N) self.btnDel = Button(self.frame, text = 'Delete', command = self.delBBox) self.btnDel.grid(row = 3, column = 2, sticky = W+E+N) self.btnClear = Button(self.frame, text = 'ClearAll', command = self.clearBBox) self.btnClear.grid(row = 4, column = 2, sticky = W+E+N) # control panel for image navigation self.ctrPanel = Frame(self.frame) self.ctrPanel.grid(row = 5, column = 1, columnspan = 2, sticky = W+E) self.prevBtn = Button(self.ctrPanel, text='<< Prev', width = 10, command = self.prevImage) self.prevBtn.pack(side = LEFT, padx = 5, pady = 3) self.nextBtn = Button(self.ctrPanel, text='Next >>', width = 10, command = self.nextImage) self.nextBtn.pack(side = LEFT, padx = 5, pady = 3) self.progLabel = Label(self.ctrPanel, text = "Progress: / ") self.progLabel.pack(side = LEFT, padx = 5) self.tmpLabel = Label(self.ctrPanel, text = "Go to Image No.") self.tmpLabel.pack(side = LEFT, padx = 5) self.idxEntry = Entry(self.ctrPanel, width = 5) self.idxEntry.pack(side = LEFT) self.goBtn = Button(self.ctrPanel, text = 'Go', command = self.gotoImage) self.goBtn.pack(side = LEFT) # example pannel for illustration self.egPanel = Frame(self.frame, border = 10) self.egPanel.grid(row = 1, column = 0, rowspan = 5, sticky = N) self.tmpLabel2 = Label(self.egPanel, text = "Examples:") self.tmpLabel2.pack(side = TOP, pady = 5) self.egLabels = [] for i in range(3): self.egLabels.append(Label(self.egPanel)) self.egLabels[-1].pack(side = TOP) # display mouse position self.disp = Label(self.ctrPanel, text='') self.disp.pack(side = RIGHT) self.frame.columnconfigure(1, weight = 1) self.frame.rowconfigure(4, weight = 1) # for debugging
## self.setImage()
## self.loadDir() def loadDir(self, dbg = False): if not dbg: s = self.entry.get() self.parent.focus() self.category = int(s) else: s = r'E:/Python/get_picture/picture'
## if not os.path.isdir(s):
## tkMessageBox.showerror("Error!", message = "The specified dir doesn't exist!")
## return # get image list print('self.category =%d' %(self.category ) ) self.imageDir = os.path.join(r'./images', '%03d' %(self.category)) print("imageDir=",self.imageDir) self.imageList = glob.glob(os.path.join(self.imageDir, '*.jpg')) if len(self.imageList) == 0: print('No .jpg images found in the specified dir!' )return else: print('num=%d' %(len(self.imageList)) ) # default to the 1st image in the collection self.cur = 1 self.total = len(self.imageList) # set up output dir self.outDir = os.path.join(r'./outputs', '%03d' %(self.category)) if not os.path.exists(self.outDir): os.mkdir(self.outDir) # load example bboxes self.egDir = os.path.join(r'./Examples', '%03d' %(self.category)) #if not os.path.exists(self.egDir): # return filelist = glob.glob(os.path.join(self.egDir, '*.jpg')) self.tmp = [] self.egList = [] random.shuffle(filelist) for (i, f) in enumerate(filelist): if i == 3: break im = Image.open(f) r = min(SIZE[0] / im.size[0], SIZE[1] / im.size[1]) new_size = int(r * im.size[0]), int(r * im.size[1]) self.tmp.append(im.resize(new_size, Image.ANTIALIAS)) self.egList.append(ImageTk.PhotoImage(self.tmp[-1])) self.egLabels[i].config(image = self.egList[-1], width = SIZE[0], height = SIZE[1]) self.loadImage() print('%d images loaded from %s' %(self.total, s)) def loadImage(self): # load image imagepath = self.imageList[self.cur - 1] pil_image = Image.open(imagepath) # get the size of the image #获取图像的原始大小 global w0,h0 w0, h0 = pil_image.size #缩放到指定大小 pil_image = pil_image.resize((DEST_SIZE[0], DEST_SIZE[1]), Image.ANTIALIAS) #pil_image = imgresize(w, h, w_box, h_box, pil_image) self.img = pil_image self.tkimg = ImageTk.PhotoImage(pil_image) self.mainPanel.config(width = max(self.tkimg.width(), 400), height = max(self.tkimg.height(), 400)) self.mainPanel.create_image(0, 0, image = self.tkimg, anchor=NW) self.progLabel.config(text = "%04d/%04d" %(self.cur, self.total)) # load labels self.clearBBox() self.imagename = os.path.split(imagepath)[-1].split('.')[0] labelname = self.imagename + '.txt' self.labelfilename = os.path.join(self.outDir, labelname) bbox_cnt = 0 if os.path.exists(self.labelfilename): with open(self.labelfilename) as f: for (i, line) in enumerate(f): if i == 0: bbox_cnt = int(line.strip()) continue print(line) tmp = [(t.strip()) for t in line.split()] print("********************" ) print( DEST_SIZE) #tmp = (0.1, 0.3, 0.5, 0.5) print("tmp[0,1,2,3]===%.2f, %.2f, %.2f, %.2f" %(float(tmp[0]), float(tmp[1]), float(tmp[2]), float(tmp[3]))) #print "%.2f,%.2f,%.2f,%.2f" %(tmp[0] tmp[1] tmp[2] tmp[3] ) print("********************") #tx = (10, 20, 30, 40) #self.bboxList.append(tuple(tx)) self.bboxList.append(tuple(tmp)) tmp[0] = float(tmp[0]) tmp[1] = float(tmp[1]) tmp[2] = float(tmp[2]) tmp[3] = float(tmp[3]) tx0 = int(tmp[0]*DEST_SIZE[0]) ty0 = int(tmp[1]*DEST_SIZE[1]) tx1 = int(tmp[2]*DEST_SIZE[0]) ty1 = int(tmp[3]*DEST_SIZE[1]) print("tx0, ty0, tx1, ty1") print(tx0, ty0, tx1, ty1) tmpId = self.mainPanel.create_rectangle(tx0, ty0, tx1, ty1, width = 2, outline = COLORS[(len(self.bboxList)-1) % len(COLORS)]) self.bboxIdList.append(tmpId) self.listbox.insert(END, '(%.2f,%.2f)-(%.2f,%.2f)' %(tmp[0], tmp[1], tmp[2], tmp[3]) ) # self.listbox.insert(END, '(%d, %d) -> (%d, %d)' %(tmp[0], tmp[1], tmp[2], tmp[3])) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) def saveImage(self): #print "-----1--self.bboxList---------" print(self.bboxList) #print "-----2--self.bboxList---------" with open(self.labelfilename, 'w') as f: f.write('%d\n' %len(self.bboxList)) for bbox in self.bboxList: f.write(' '.join(map(str, bbox)) + '\n') print('Image No. %d saved' %(self.cur)) def mouseClick(self, event): if self.STATE['click'] == 0: self.STATE['x'], self.STATE['y'] = event.x, event.y else: x1, x2 = min(self.STATE['x'], event.x), max(self.STATE['x'], event.x) y1, y2 = min(self.STATE['y'], event.y), max(self.STATE['y'], event.y) x1, x2 = x1 / DEST_SIZE[0], x2 / DEST_SIZE[0]; y1, y2 = y1 / DEST_SIZE[1], y2 / DEST_SIZE[1]; self.bboxList.append((x1, y1, x2, y2)) self.bboxIdList.append(self.bboxId) self.bboxId = None self.listbox.insert(END, '(%.2f, %.2f)-(%.2f, %.2f)' %(x1, y1, x2, y2)) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) self.STATE['click'] = 1 - self.STATE['click'] def mouseMove(self, event): self.disp.config(text = 'x: %.2f, y: %.2f' %(event.x/DEST_SIZE[0], event.y/DEST_SIZE[1])) if self.tkimg: if self.hl: self.mainPanel.delete(self.hl) self.hl = self.mainPanel.create_line(0, event.y, self.tkimg.width(), event.y, width = 2) if self.vl: self.mainPanel.delete(self.vl) self.vl = self.mainPanel.create_line(event.x, 0, event.x, self.tkimg.height(), width = 2) if 1 == self.STATE['click']: if self.bboxId: self.mainPanel.delete(self.bboxId) self.bboxId = self.mainPanel.create_rectangle(self.STATE['x'], self.STATE['y'], event.x, event.y, width = 2, outline = COLORS[len(self.bboxList) % len(COLORS)]) def cancelBBox(self, event): if 1 == self.STATE['click']: if self.bboxId: self.mainPanel.delete(self.bboxId) self.bboxId = None self.STATE['click'] = 0 def delBBox(self): sel = self.listbox.curselection() if len(sel) != 1 : return idx = int(sel[0]) self.mainPanel.delete(self.bboxIdList[idx]) self.bboxIdList.pop(idx) self.bboxList.pop(idx) self.listbox.delete(idx) def clearBBox(self): for idx in range(len(self.bboxIdList)): self.mainPanel.delete(self.bboxIdList[idx]) self.listbox.delete(0, len(self.bboxList)) self.bboxIdList = [] self.bboxList = [] def prevImage(self, event = None): self.saveImage() if self.cur > 1: self.cur -= 1 self.loadImage() def nextImage(self, event = None): self.saveImage() if self.cur < self.total: self.cur += 1 self.loadImage() def gotoImage(self): idx = int(self.idxEntry.get()) if 1 <= idx and idx <= self.total: self.saveImage() self.cur = idx self.loadImage() ## def setImage(self, imagepath = r'test2.png'):
## self.img = Image.open(imagepath)
## self.tkimg = ImageTk.PhotoImage(self.img)
## self.mainPanel.config(width = self.tkimg.width())
## self.mainPanel.config(height = self.tkimg.height())
## self.mainPanel.create_image(0, 0, image = self.tkimg, anchor=NW) def imgresize(w, h, w_box, h_box, pil_image): ''''' resize a pil_image object so it will fit into a box of size w_box times h_box, but retain aspect ratio ''' f1 = 1.0*w_box/w # 1.0 forces float division in Python2 f2 = 1.0*h_box/h factor = min([f1, f2]) #print(f1, f2, factor) # test # use best down-sizing filter width = int(w*factor) height = int(h*factor) return pil_image.resize((width, height), Image.ANTIALIAS) if __name__ == '__main__': root = tk.Tk() tool = LabelTool(root) root.mainloop()
效果
由于代码中将路径设置为:
self.imageDir = os.path.join(r'./images', '%03d' %(self.category))
print("imageDir=",self.imageDir)
所以,不需要输入001,只需要输入1即可。
然后,得到的图像标注坐标为:
python实现一个简单的【图像中物体坐标】标注小工具相关推荐
- python绘制一个简单的函数图像使用到了matplotlib库和numpy库
文章目录 效果展示: 视频链接 实现的思想 使用到的函数包 图片一对应的代码展示 图片二 对应的代码展示 注意事项 效果展示: 视频链接 python绘制一个简单的函数图像(B站视频) 实现的思想 其 ...
- Python实现一个简单的目标检测
Python实现一个简单的目标检测 相关介绍 实验环境 基本思路 代码实现 输出结果 相关介绍 选择性搜索(Select Search)算法属于候选区域算法,用分割不同区域的办法来识别潜在的物体.在分 ...
- python编写一个登陆验证程序_用python实现一个简单的验证码
我们经常在登录一个网站,或者注册的时候需要输入一个验证码,有时候觉得很烦,因为有些验证码不仅复杂还看不清,许多用户就会因为这些而懒得再登录或者注册之类的. 既然验证码会造成流失用户的风险,为什么大家都 ...
- 用python做一个简单GUI小软件
用python做一个简单软件 前言 这是一个课设,用python做一个扫描王软件 我主要做的GUI部分,记录分享一下.也是第一次用python做小软件,python的方便果然是名不虚传 遇到问题 1. ...
- 编程实战(4)——python识别图像中的坐标点并保存坐标数据
编程实战(4)--python识别图像中的坐标点并保存坐标数据 文章目录 编程实战(4)--python识别图像中的坐标点并保存坐标数据 综述 代码思路 库的安装 图片预处理 图像细化 图像二极化 提 ...
- 用python做一个简单的游戏,用python写一个小游戏
大家好,本文将围绕如何用python做一个简单的小游戏展开说明,python编写的入门简单小游戏是一个很多人都想弄明白的事情,想搞清楚用python做一个简单的游戏需要先了解以下几个事情. 1.Pyt ...
- python实现一个简单的项目建议书范文_建议收藏,22个Python迷你项目(附源码)
Python部落在使用Python的过程中,我最喜欢的就是Python的各种第三方库,能够完成很多操作. 下面就给大家介绍22个通过Python构建的项目,以此来学习Python编程. 大家也可根据项 ...
- python实现一个简单的项目建议书范文_建议收藏,18个Python迷你项目(附源码)
在使用Python的过程中,我最喜欢的就是Python的各种第三方库,能够完成很多操作. 下面就给大家介绍22个通过Python构建的项目,以此来学习Python编程. 大家也可根据项目的目的及提示, ...
- 使用OpenCV测量图像中物体的大小
本文翻译自pyimagesearch技术博客上的一篇文章,<Measuring size of objects in an image with OpenCV>,原文作者:Adrian R ...
最新文章
- 【codeforces 242E】XOR on Segment
- JS保留4位小数(合集)
- Eclipse如何提高开发效率
- android 半浮层框架,GitHub - Jodragon/AnyLayer: Android稳定高效的浮层创建管理框架
- 文件I0通用的IO模型
- centos6.5安装mongodb2.6
- EPS 转 pdf 在线
- Bootstrap+DataTables后端排序分页详解
- 开源:Taurus.MVC 框架 (已支持.NET Core)
- 默认情况下linux主机在机房托管期间被,托管机房作业未传之秘
- 泰坦尼克号数据集下载
- android 展开收起功能,Android非常简单的TextView展开和收起,在列表中TextView文章展开全部和收起...
- 数学分析教程(科大)——6.4笔记+习题
- macd ema java源码_MACD指标源码汇总,成功率极高,买卖点提前一目了然!
- 通过负载均衡器+域名实现容灾切换-(11)深信服负载均衡器
- 阿里云服务器被攻击危害有多大
- 2022年郑州市初级焊工考试模拟试题及答案
- linux系统中同时开启wifi与热点的办法
- NOIP2021 T3 方差
- 2017JAVA秋招总结
热门文章
- CSS-Position用法的理解
- php路径伪静态化,URL地址伪静态化
- 使用vue-cli来搭建vue项目
- LeetCode 674 最长连续递增子序列
- Windows平台下NS2网络仿真环境的搭建
- python的整除运算_Python3基础 ** 幂运算 // 整除运算
- ubuntu服务器系统不识别,U盘安装16.04server版 安装好后重启 无法进入系统
- 台式计算机华硕电源,美声大师+智能电源 华硕台式电脑M51AC
- mysql 生成短网址_生成短链接的URL
- 语言 泰克示波器程序_示波器再升级,EMI测试不求人