【学习笔记】使用python批量读取并修改xml文件(2)_root.getelementsbytagname_Masec的博客-程序员秘密

技术标签: xml修改  TensorFlow学习记录  

在大老板的安排下最近在某公司实习,实习期间要求实现一个图像识别模块的封装。无奈基础太薄弱,只能将任务细分,单独学习来实现。以此为背景……


这一篇记录一些在实际使用中踩到的。在实际使用中,我在A文件夹下对图片进行了标注,随后将图片移动到B文件夹下。那么相应的,标注后的xml文件中,<path>标签的值就应该修改。

最初的思路是,我遍历了xml文件,那么我只需要将‘新地址’+xml文件写入到新的<path>中即可。

paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+xmlFile

即这一句代码,使用后发现自己脑子抽了……<path>中的标签值为:

<path>/home/kanghao/learning_something/about_xml/yibiao512/img/a0000000.jpg</path>

重点是后面跟随的是图片的扩展名。

于是想到是否可以再次遍历图片文件夹,获取图片信息之后再与新地址相连?在实际操作中不知如何同时遍历两个文件夹……_(°:з」∠)_秃头

于是采取小黄鸭debug方法,在与小伙伴讲解诉求的过程中猛然发现,我要获取的不就是<filename>标签的值吗?获取了这个值之后,添加的新地址后面就好了呀。于是按照这个思路,完整代码如下:

#coding:utf-8
### V1.0版
### 针对xml文件,要修改的地方是<folder><path><width><height><bndbox>
### 程序瑕疵,在计算bud box时使用float格式,openCV画框函数为int格式
### 因此会产生误差

import os
import os.path
import xml.dom.minidom

#path="../xml/"
path='/home/kanghao/SSD-Tensorflow/yibiao512/Annotations/'
files=os.listdir(path) #得到文件夹下所有文件名称
for xmlFile in files: #遍历文件夹
	
	if not os.path.isdir(xmlFile): #判断是否是文件夹,不是文件夹才打开
		print xmlFile
			
		#xml读取操作		
		#将获取到的xml文件名送入到dom解析
		#错误代码:dom=xml.dom.minidom.parse(xmlFile)
		dom=xml.dom.minidom.parse(os.path.join(path,xmlFile))
		root=dom.documentElement
		
		###获取标签对xmin/ymin之间的值
		# ~ folder=root.getElementsByTagName('folder')
		paths=root.getElementsByTagName('path')
		filenames=root.getElementsByTagName('filename')
		# ~ xmin=root.getElementsByTagName('xmin')
		# ~ ymin=root.getElementsByTagName('ymin')

		# ~ #修改相应标签的值
		# ~ # 修改<folder>
		# ~ for i in range(len(folder)):
			# ~ print folder[i].firstChild.data
			# ~ folder[i].firstChild.data='xml'
			# ~ print folder[i].firstChild.data
		for i in range(len(filenames)):
			fn = filenames[i].firstChild.data
		
		###############################################################################################################		
		### 如何修改path?每个xml文件对应不同名字的图片???                                                                
		### 解决方式如下,测试成功×----------->开始的思路有问题,                                                            
		###paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+fn语句中,fn使用的是xmlFiles    
		###那么修改后的path中后缀加的是xml文件,不是对应的jpg文件。 思路2————————>直接读取filename标签中的值,添加到地址后即可     
		###############################################################################################################   
		# 修改<path>
		for i in range(len(paths)):
			print paths[i].firstChild.data
			paths[i].firstChild.data='/home/kanghao/SSD-Tensorflow/yibiao512/JPEGImages/'+fn
			print paths[i].firstChild.data
		# ~ # 修改<xmin>	
		# ~ for k in range(len(xmin)):
			# ~ print xmin[k].firstChild.data
			# ~ xia = unicode.encode(xmin[k].firstChild.data)
			# ~ xmin[k].firstChild.data=float(xia)/1.25
			# ~ print xmin[k].firstChild.data
		# ~ # 修改<ymin>	
		# ~ for j in range(len(ymin)):
			# ~ print ymin[j].firstChild.data
			# ~ yia = unicode.encode(ymin[j].firstChild.data)
			# ~ ymin[j].firstChild.data=float(yia)/1.0666667
			# ~ print ymin[j].firstChild.data

		#保存修改到xml文件中
		with open(os.path.join(path,xmlFile),'w') as fh:
			dom.writexml(fh)
		# ~ with open(os.path.join(path2,jpgFile),'w') as fh:
			# ~ dom.writexml(fh)
			print('恭喜,写入xmin/ymin成功!')

那一大坨注释,就是为了方便自己理解……_(°:з」∠)_秃头again。

对了,#coding:utf-8要写在开头,编译器才能以utf-8的各种编译。

one more thing……

我想用openCV的cv2.rectangle()函数来画框,验证我按比例变化是否准确,相关代码如下:

#coding:utf-8
import os
import cv2
import numpy as np
import xml.dom.minidom
import pandas as pd
from PIL import Image, ImageDraw, ImageFont

input_file="/home/kanghao/learning_something/about_xml/xml/"
dirs_name=os.listdir("/home/kanghao/learning_something/about_xml/jpg/") #图片地址


for img in dirs_name:
	
	im=cv2.imread("/home/kanghao/learning_something/about_xml/jpg/"+img) #读取图片
	dom=xml.dom.minidom.parse(input_file+img[:-4]+".xml") # 读取图片对应的label信息 xml文件
	root=dom.documentElement
	
	objs=root.getElementsByTagName("object")
	
	name=[]
	xmin=[]
	ymin=[]
	xmax=[]
	ymax=[] 
	
	for obj in objs:
		
		name1=obj.getElementsByTagName('name')
		n=name1[0].firstChild.data
		xmin1=obj.getElementsByTagName('xmin')
		xi=xmin1[0].firstChild.data
		ymin1=obj.getElementsByTagName('ymin')
		yi=ymin1[0].firstChild.data
		xmax1=obj.getElementsByTagName('xmax')
		xa=xmax1[0].firstChild.data
		ymax1=obj.getElementsByTagName('ymax')
		ya=ymax1[0].firstChild.data
		
		xmin.append(float(xi.strip()))
		print(xmin)
		ymin.append(float(yi.strip()))
		xmax.append(float(xa.strip()))
		ymax.append(float(ya.strip()))
		name.append(n.strip())
		
	for i in range(0,len(xmin)):
		
		#画box
		cv2.rectangle(im, (int(xmin[i]),int(ymin[i])), (int(xmax[i]),int(ymax[i])), (0,255,0), 4)
	
	cv2img = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
	pilimg = Image.fromarray(cv2img)
	draw = ImageDraw.Draw(pilimg)
	# ~ # 写标注
	# ~ for i in range(0,len(xmin)):
		# ~ font = ImageFont.truetype("simhei.ttf", 40, encoding="utf-8")
		# ~ draw.text((xmin[i], ymin[i]-40), name[i], (255, 0, 0), font=font)
		
	cv2charimg = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
	
	#保存图片
	cv2.imwrite("/home/kanghao/learning_something/about_xml/xml/"+img,cv2charimg)

但是问题来了,cv2.rectangle函数中都是int型的数据类型,我在做了除法之后都是float型数据,因此会在取整时产生误差。误差大概如下图所示:

感觉还能接受……但是还是希望看到的大神指点一下,谢谢!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yourgreatfather/article/details/84031289

智能推荐

INVALID_HANDLE_VALUE 与 NULL_Stef若木的博客-程序员秘密

[cpp] view plaincopy#include &quot;stdafx.h&quot;  #include &amp;lt;Windows.h&amp;gt;  #include &amp;lt;iostream&amp;gt;      using namespace std;      int _tmain(int argc, _TCHAR* argv[])  {      HANDLE m_hCom = CreateFile(_T...

计算机科学与导论期末考,计算机科学导论 题库 期末考试 汇总 三.doc_weixin_39982452的博客-程序员秘密

文档介绍:判断题(1).未来计算机可能朝着量子计算机、光子计算机和生物计算机等方向发展。( a )正确错误(2).进行加减运算时补码比原码更难实现。(b )正确错误(3).UTF-8中也存在字节序问题。( b )正确错误(4).Unicode是一种多字节字符编码方案。( a )正确错误(5).在工作中,...

序列化和反序列化_proto文件,对数据的约束_IT狗探求的博客-程序员秘密

序列化和反序列化  摘要  序列化和反序列化几乎是工程师们每天都要面对的事情,但是要精确掌握这两个概念并不容易:一方面,它们往往作为框架的一部分出现而湮没在框架之中;另一方面,它们会以其他更容易理解的概念出现,例如加密、持久化。然而,序列化和反序列化的选型却是系统设计或重构一个重要的环节,在分布式、大数据量系统设计里面更为显著。恰当的序列化协议不仅可以提高系统的通用性、强健

这份Java面试宝典,你值得拥有(2020版下篇)_2020java面试宝典_NObug-369的博客-程序员秘密

63. 深拷贝和浅拷贝区别是什么?浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(例:assign())深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝(例:JSON.parse()和JSON.stringify(),但是此方法无法复制函数类型)六、Java Web64. jsp ...

写通信时发现_hktk120320的博客-程序员秘密

偶然感悟:          写程序是考验人耐心的体力活,才接触不久的人 都会像我样的因为代码摆放得太零乱 导致自己的思维混乱不堪 就算是自己的代码实现了自己想要的功能后  想要优化一下自己的代码都会觉得没什么头绪  看着自己写的这一块那一块的代码头都大了 开始要优化它的想法早就被厌烦感替代了 习惯很重要 一个优秀的程序员写出来的代码就是要比生手写的代码看上去要舒服很多 不要不以为然 人与人的...

随便推点

onkeyup input前端限制输入_input onkeyup_不管,我要跨世纪的博客-程序员秘密

input 限制输入&lt;!-- οnkeyup="非数字替换并保留两位小数" --&gt;&lt;input onkeyup="this.value=this.value.replace(/^\D*([1-9]\d*\.?\d{0,2})?.*$/,'$1')" onafterpaste="this.value=this.value.replace(/^\D*([1-9]\d*\.?\d{0,2})?.*$/,'$1')" [maxlength]="10" pla

PsSetCreateProcessNotifyRoutine进程黑名单_wzsy的博客-程序员秘密

通过PsSetCreateProcessNotifyRoutine可以设置一个进程回调当有进程被创建的时候 回调用这个通知我写了一段代码通过检测进程对应的文件的版本信息来拒绝进程运行360以前就这么干的主要是怎么通过进程ID获取进程的全路径还有怎么在驱动里面访问程序的资源#ifndef _SHIELDER_H#define _SHIELDER_H#ifdef

css 创建盒子(div)_盒子模型的宽度怎么设置全屏_Amy777777的博客-程序员秘密

盒子模型--div一个盒子占据的控件是边框 + 内边距 + 内容区域Margin:外边距Width=(margin+border+padding)*2+content一个盒子中主要的5个属性:width、height、padding、border、margin。width是“宽度”的意思,CSS中width指的是内容的宽度,而不是盒子的宽度。height是“高度”的

wamp如何升级php版本,wamp升级php_悠玲的博客-程序员秘密

标签:1.停止WAMP服务器.2.去网站windows.php.net下载php-5.4.31-nts-Win32-VC9-x86.zip(32位的). 不要下载THE INSTALLER.3. 在wamp/bin/php创建php5.4.31文件夹4. 把下载的zip包解压到php5.4.31文件夹中5. 从已存在的php版本文件中(如php5.3.10,(eg. wamp...

高数-不定积分--凑积分(第一类换元法)_第一类积分法_Jtooo的博客-程序员秘密

一、定理步骤:----------------------------------------------------习题-----------------------1、2、

kafka启动一段时候后自动停止_youngitman的博客-程序员秘密

使用守护进程方式启动bin/kafka-server-start.sh -daemon ./config/server.properties  &amp;amp;