我正在尝试根据新图像的宽度和高度转换xml文件中的边界框坐标。示例xml文件如下所示:
<annotations>
<image height="940" id="3" name="C_00080.jpg" width="1820">
<box label="Objects" occluded="0" xbr="801.99255" xtl="777.78656" ybr="506.9955" ytl="481.82132">
<attribute name="Class">B</attribute>
</box>
<box label="Objects" occluded="0" xbr="999.319" xtl="963.38654" ybr="519.2735" ytl="486.68628">
<attribute name="Class">A</attribute>
</box>
</image>
<annotations>
xml中的原始图像宽度和高度为1820x940
,框坐标相同。我想将方框坐标更改为新图像的宽度和高度1080x720
。我已经写了这个代码,有人能帮我验证或告诉我下面代码的更好方法吗。
import xml.etree.ElementTree as ET
label_file = '1.xml'
tree = ET.parse(label_file)
root = tree.getroot()
for image in root.findall('image'):
image.attrib['width'] = '1080' # Original width = 1820
image.attrib['height'] = '720' # Original width = 940
for allBboxes in image.findall('box'):
xmin = float(allBboxes.attrib['xtl'])
xminNew = float(xmin / (1820/1080))
xminNew = float("{:.5f}".format(xminNew))
allBboxes.attrib['xtl'] = str(xminNew)
ymin = float(allBboxes.attrib['ytl'])
yminNew = float(ymin / (940/720))
yminNew = float("{:.5f}".format(yminNew))
allBboxes.attrib['ytl'] = str(yminNew)
xmax = float(allBboxes.attrib['xbr'])
xmaxNew = float(xmax / (1820/1080))
xmaxNew = float("{:.5f}".format(xmaxNew))
allBboxes.attrib['xbr'] = str(xmaxNew)
ymax = float(allBboxes.attrib['ybr'])
ymaxNew = float(ymax / (940/720))
ymaxNew = float("{:.5f}".format(ymaxNew))
allBboxes.attrib['ybr'] = str(ymaxNew)
tree.write(label_file)
要改进代码,可以:
- 在循环之前计算比率
- 删除无用的浮点转换
- 去掉除法(除法就是乘法(
- 浮子可能不需要倒圆
- 将语句按连贯的顺序分组
- 将allBoxes重命名为box,因为它只代表一个框
这里有一个可能的代码:
import xml.etree.ElementTree as ET
label_file = '1.xml'
tree = ET.parse(label_file)
root = tree.getroot()
r_w = 1080 / 1820
r_h = 720 / 940
for image in root.findall('image'):
image.attrib['width'] = '1080' # Original width = 1820
image.attrib['height'] = '720' # Original width = 940
for box in image.findall('box'):
xmin = float(box.attrib['xtl'])
ymin = float(box.attrib['ytl'])
xmax = float(box.attrib['xbr'])
ymax = float(box.attrib['ybr'])
xminNew = xmin * r_w
yminNew = ymin * r_h
xmaxNew = xmax * r_w
ymaxNew = ymax * r_h
box.attrib['xtl'] = str(xminNew)
box.attrib['ytl'] = str(yminNew)
box.attrib['xbr'] = str(xmaxNew)
box.attrib['ybr'] = str(ymaxNew)
tree.write(label_file)
您可以通过将所有这些封装在函数中来进一步改进代码,以提高可用性、清晰度和可能的重用性。
考虑使用Python的第三方模块lxml
的参数化XSLT解决方案,在该模块中,您可以从Python传递新的宽度和高度值,以便将公式动态应用于XML属性。
XSLT (另存为.xsl文件(
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<!-- PARAMS WITH DEFAULTS -->
<xsl:param name="new_width" select="1080"/>
<xsl:param name="new_height" select="720"/>
<!-- IDENTITY TRANSFORM -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- WIDTH AND HEIGHT ATTRS CHANGE -->
<xsl:template match="image">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="width"><xsl:value-of select="$new_width"/></xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="$new_height"/></xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- X ATTRS CHANGE -->
<xsl:template match="box/@xbr|box/@xtl">
<xsl:variable select="ancestor::image/@width" name="curr_width"/>
<xsl:attribute name="{name(.)}">
<xsl:value-of select="format-number(. div ($curr_width div $new_width) , '#.00000')"/>
</xsl:attribute>
</xsl:template>
<!-- Y ATTRS CHANGE -->
<xsl:template match="box/@ybr|box/@ytl">
<xsl:variable select="ancestor::image/@height" name="curr_height"/>
<xsl:attribute name="{name(.)}">
<xsl:value-of select="format-number(. div ($curr_height div $new_height), '#.00000')"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Python(无for
循环或if
逻辑(
import lxml.etree as et
# LOAD XML AND XSL SCRIPT
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')
# PASS PARAMETERS TO XSLT
transform = et.XSLT(xsl)
result = transform(xml, new_width = et.XSLT.strparam(str(1080)),
new_height = et.XSLT.strparam(str(720)))
# SAVE RESULT TO FILE
with open("Output.xml", 'wb') as f:
f.write(result)
输出
<?xml version="1.0" encoding="utf-8"?>
<annotations>
<image height="720" id="3" name="C_00080.jpg" width="1080">
<box label="Objects" occluded="0" xbr="475.90767" xtl="461.54367" ybr="388.33698" ytl="369.05463">
<attribute name="Class">B</attribute>
</box>
<box label="Objects" occluded="0" xbr="593.00248" xtl="571.67992" ybr="397.74140" ytl="372.78098">
<attribute name="Class">A</attribute>
</box>
</image>
</annotations>