简体   繁体   English

根据新的图像宽度和高度更改 xml 文件中的边界框坐标

[英]Changing bounding box coordinates in xml file as per new image width and height

I am trying to convert bounding box coordinates in xml file with respect to a new image's width and height.我正在尝试将 xml 文件中的边界框坐标转换为新图像的宽度和高度。 The sample xml file is given below:示例 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>

Original image width and height in xml is 1820x940 and box coordinates are same. xml 中的原始图像宽度和高度为1820x940 ,框坐标相同。 I want to change the box coordinates to a new image's width and height that is 1080x720 .我想将框坐标更改为新图像的宽度和高度,即1080x720 I have written this code, can someone help me to verify or tell me a better way for the code below.我已经编写了这段代码,有人可以帮我验证或告诉我下面代码的更好方法。

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)

To improve the code you can:要改进代码,您可以:

  • compute the ratios before the loop计算循环前的比率
  • remove useless float conversions删除无用的浮点转换
  • remove the division (division by a division is a multiplication)删除除法(除以除法是乘法)
  • rounding of the float may not be necessary可能不需要对浮点数进行四舍五入
  • group the statements in a coherent order以连贯的顺序对语句进行分组
  • rename allBoxes to box as it represents only one box将 allBoxes 重命名为 box 因为它只代表一个盒子

Here is a possible code:这是一个可能的代码:

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)

You can further improve this code by wrapping all this in functions to improve usability, clarity and possible reuse.您可以通过将所有这些包装在函数中来进一步改进此代码,以提高可用性、清晰度和可能的重用性。

Consider a parameterized XSLT solution using Python's third party module, lxml , where you pass new width and height values from Python to dynamically apply formula to XML attributes.考虑使用 Python 的第三方模块lxml的参数化 XSLT 解决方案,您可以在其中从 Python 传递新的宽度和高度值,以将公式动态应用于 XML 属性。

XSLT (save as.xsl file) 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 (no for loop or if logic) 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)

Output Output

<?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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 裁剪图像后,如何找到新的边界框坐标? - After cropping a image, how to find new bounding box coordinates? 在 Yolov5 中计算边界框的高度和宽度 - Calculating height and width of a bounding box in Yolov5 边界框坐标中的字符串 - Strings in bounding box coordinates 张量流中边界框的坐标 - coordinates of bounding box in tensorflow 如何使用边界框坐标裁剪图像中的感兴趣区域? - How to crop regions of interest in an image using bounding box coordinates? opencv-python:如何用边界框坐标裁剪图像 - opencv-python: how to crop image with bounding box coordinates 使用边界框坐标的语法错误裁剪图像 - syntax error- cropping image using bounding box coordinates Pytorch 是否允许将给定的变换应用于图像的边界框坐标? - Does Pytorch allow to apply given transformations to bounding box coordinates of the image? 如何获取文本图像的整体边界框的坐标? - How to get coordinates of the overall bounding box of a text image? 如何找到旋转图像边界框的新坐标以修改其xml文件以进行Tensorflow数据增强? - How can I find new coordinates of boundary box of rotated image to modify its xml file for Tensorflow data augmentation?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM