python对修改图片尺寸后的labelimg2/rolabelimg生成的XML文件进行多级节点的读取/修改/保存

2023-05-16

已经做了四张图片的标注,很复杂,但遇到两个问题:

  1. labelimg2无法对边界处的目标进行标注,导致标注不完全;

  1. 后续的算法是基于正方形的图片进行训练的,虽然可以训练矩形,但要多一步,不如在标注前就处理好图片。

结合以上两个问题,下面分享解决思路与代码。

1. 图片遍历/读取/裁剪/填充/无损保存:

都是opencv的基础操作,不展开介绍。代码如下:

import os
import os.path
import cv2

def cv_show(name, img, pause = False):
    cv2.imshow(name, img) 
    key = cv2.waitKey(0 if pause == True else 1) & 0xFF 
    if key == 27:       # keycode 27 = Escape
        cv2.destroyAllWindows()
    else:
        cv2.destroyAllWindows()
        return 1

if __name__ == "__main__":
    path_origin = 'image_1280-800'      # 输入原文件夹地址
    path_crop = 'image'                 # 输入原文件夹地址
    files = os.listdir(path_origin)     # 读入文件夹
    num_bub = len(files)                # 统计文件夹中的文件个数

    # 检查path_crop文件夹是否存在,不存在则创建
    if not os.path.exists(path_crop):
        os.makedirs(path_crop)
    # 1. 图片遍历
    for file in files:
        # 2. 读取图像
        img = cv2.imread(path_origin + '\\' + file)
        flow_img = img.copy()
        # 显示读取到的图像
        # if cv_show(file, flow_img, True) is None:
        #     break

        #3. 切割图片
        #截取的左上坐标
        left_top = (128, 0)       
        #截取的右下坐标
        right_bottom = (1152, 800)
        # 裁剪坐标为[y0:y1, x0:x1]
        flow_img_cut = flow_img[left_top[1]:right_bottom[1],left_top[0]:right_bottom[0]]

        # 4. 常数值填充, 需要设置一个value值
        flow_img_bord = cv2.copyMakeBorder(flow_img_cut, 112, 112, 0, 0, cv2.BORDER_CONSTANT, value = (255, 255, 255))

        # 5. 无损保存
        # 0代表图片保存时的压缩程度,有0-9这个范围的10个等级,数字越大表示压缩程度越高。
        cv2.imwrite(path_crop + '\\' + file, flow_img_bord, [cv2.IMWRITE_PNG_COMPRESSION, 0])

        # 显示处理后的图像
        # if cv_show('flow_img_bord', flow_img_bord, True) is None:
        #     break

2. XML文件读取/修改/保存

图片经过裁剪填充后,由(1280*800)变为(1024*1024),但之前标注过的xml文件中的目标框会偏移,要修正偏移有两步:1、计算偏移量;2、读取/修改/保存xml文件。

2.1. 计算偏移量

偏移量的计算比较简单,opencv的坐标原点在左上角,如图所示,横坐标需要减去纵坐标需要加上,体现在2.2.代码中。

2.2. 读取/修改/保存xml文件

节点的查找有两种方法,一是逐级节点查找,二是全部节点查找。

节点结构如下:

<annotation verified="yes">
    <folder>image</folder>
    <filename>images1_0000.png</filename>
    <path>C:\Users\glanc\Desktop\flow_dataset\image\images1_0000.png</path>
    <source>
        <database>Unknown</database>
    </source>
    <size>
        <width>1024</width>
        <height>1024</height>
        <depth>1</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>single</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <robndbox>
            <cx>250.5867</cx>
            <cy>336.501</cy>
            <w>72.8736</w>
            <h>49.5941</h>
            <angle>3.041593</angle>
        </robndbox>
        <extra/>
    </object>
    <object>
        <name>single</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <robndbox>
            <cx>330.6097</cx>
            <cy>183.8053</cy>
            <w>70.3055</w>
            <h>41.3395</h>
            <angle>0.17</angle>
        </robndbox>
        <extra/>
    </object>
</annotation>

节点结构如下:

  1. <annotation verified="yes">一级节点;

  1. <folder>、<filename>、<path>、...、<object>、<object>等为二级节点;

  1. <object>下的<name>、<pose>、...、<robndbox>等为三级节点;

  1. <robndbox>下的<cx>、<cy>、<w>、<h>、<angle>五项为四级节点,其中<cx>、<cy>是需要修改的数值。

步骤都在注释里,代码如下,需要注意的一点是cx.text得到的是str,需要转换为浮点数才可以计算,计算完成后转换为字符串才可以保存

import os
import xml.etree.ElementTree as ET
 
path = 'label_1280-800'      # 输入原文件夹地址
sv_path = 'label'  # 修改后的xml文件存放路径
files = os.listdir(path)

for xmlFile in files:
    tree = ET.parse(os.path.join(path, xmlFile))
    root = tree.getroot()  # 得到根节点
    # 方法一
    # https://blog.csdn.net/weixin_39580041/article/details/113581299
    # 查找二级节点object
    nodes = root.findall('object')
    for node in nodes:
        # object节点没有属性值
        # print('节点名称:', node.tag)
        # print('节点属性:', node.attrib)

        # 继续往下找三级节点:robndbox
        robndbox = node.find('robndbox')

        # 继续往下找四级节点:cx,cy
        cx = robndbox.find('cx')
        cx_new = str(float(cx.text) - 256 / 2)
        cx.text = cx_new
        cy = robndbox.find('cy')
        cy_new = str(float(cy.text) + 224 / 2)
        cy.text = cy_new
        # print(cx, cy)
    tree.write(os.path.join(sv_path, xmlFile))

    # 方法二:直接定位节点位置
    # https://blog.csdn.net/u013996948/article/details/79157795
    # print(root.text)
    # #遍历文件所有的tag 为目标的值得标签
    # for elem in root.iter('cx'):
    #     cx_new = float(elem.text) - 256 / 2
    #     elem.text = str(cx_new)
    # for elem in root.iter('cy'):
    #     cy_new = float(elem.text) + 224 / 2
    #     elem.text = str(cy_new)
    # tree.write(os.path.join(sv_path, xmlFile))

参考文章:

https://blog.csdn.net/weixin_39580041/article/details/113581299

https://blog.csdn.net/u013996948/article/details/79157795

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python对修改图片尺寸后的labelimg2/rolabelimg生成的XML文件进行多级节点的读取/修改/保存 的相关文章

  • Java随机数-获取0到9内的随机数

    本文参考 嗨客网 Java 实战 Java随机数 描述 运用 Java 的 Random 得到随机数 题目 获取 0 到 9 内的随机数 xff08 包括 0 和 9 xff09 题目解决思路 创建一个生产随机数的对象 通过对象方法获取随机
  • Java基础练习题及详细答案

    本文参考 嗨客网 Java 实战 前言 本篇文章给大家安利一些关于 Java 基础的练习题 xff0c 每道题都附有答案链接 xff0c 答案解题的每个步骤到运行结果都十分详细 xff0c 十分适合小白拿来练习 xff0c 也十分适合准备面
  • STM32 四线驱动1602A 填坑!解决重启乱码

    最近学STM32 xff0c 用来丰富一下生活 xff0c 一个四线1602搞得一星期 xff0c 对自己的智商也是醉了 填坑开始 xff01 用的是HAL库编写的 xff0c 仅仅在ODR寄存器使用了一点寄存器操作 xff0c 其余全是H
  • 谭浩强C语言练习题及详细答案

    本文参考 嗨客网 Java 实战 前言 本篇文章分享的是 C 语言程序设计 xff08 谭浩强 C 语言第三版 xff09 课后习题及答案 xff0c 大家在学习了 C 语言程序设计后 xff0c 做几道相关的练习题 xff0c 复习一下该
  • 【自学C++】Windows安装C++语言开发环境

    Windows安装C 43 43 语言开发环境 Windows安装C 43 43 语言开发环境教程 C 43 43 的开发环境可以直接使用 C 语言 的开发环境 xff0c 同时 xff0c Windows 本身就自带 C 43 43 语言
  • 【自学Python】Python bytes转string

    Python bytes转string Python string转bytes教程 在 Python 中 xff0c bytes 类型和 字符串 的所有操作 使用和内置方法也都基本一致 因此 xff0c 我们也可以实现将 bytes 类型转
  • 【自学Python】Python查找字符串位置

    Python查找字符串位置 大纲 Python查找字符串位置教程 在开发过程中 xff0c 很多时候我们有在一个 字符串 中查找另一个字符串位置的需求 xff0c 在 Python 中 xff0c 在一个字符串中查找另一个字符串的位置我们使
  • 【自学Docker 】Docker port命令

    Docker port命令 概述 docker port命令教程 docker port 命令可以用于列出指定的 Docker容器 的端口映射 xff0c 或者将容器里的端口映射到宿主机 该命令后面的 CONTAINER 可以是容器Id x
  • 【自学Docker】Docker pull命令

    大纲 Docker pull命令 docker pull命令教程 docker pull 命令用于从镜像仓库中拉取或者更新指定镜像 docker pull 命令中的 name 即镜像名称后面可以跟上镜像标签或者镜像摘要 docker pul
  • 【自学Docker】Docker push命令

    大纲 Docker push命令 docker push命令教程 docker push 命令用于将本地的 Docker镜像 上传到 Docker镜像仓库 docker push命令使用之前需要要先登陆到镜像仓库 docker push命令
  • 【自学Linux】Linux运行级别

    Linux运行级别 Linux运行级别教程 Linux 可以支持运行级别的设置 xff0c 运行级别就是操作系统当前正在运行的功能级别 xff0c 级别是从 0 到 6 Centos7 系统之前的版本是通过 etc inittab 文件来定
  • 【自学Linux】 Linux文件目录结构

    Linux文件目录结构 Linux文件目录结构教程 在 Linux 中 xff0c 有一个很经典的说法 xff0c 叫做一切皆文件 xff0c 因此 xff0c 我们在系统学习 Linux 之前 xff0c 首先要了解 Linux 的文件目
  • 【自学Linux】Linux一切皆文件

    Linux一切皆文件 Linux一切皆文件教程 Linux 中所有内容都是以文件的形式保存和管理的 xff0c 即一切皆文件 xff0c 普通文件是文件 xff0c 目录是文件 xff0c 硬件设备 xff08 键盘 监视器 硬盘 打印机
  • 链路聚合--Eth-Trunk

    链路聚合技术是解决二层交换机多条链路产生环路的问题 xff0c 不仅避免了环路问题 xff0c 还提高了数据的传输效率 链路聚合分为两种模式 xff1a 手动模式和LACP模式 手动模式 手动模式就是人工的方式去创建Eth Trunk和成员
  • 块元素和内联元素的特点和区别

    lt css基础之块级元素和内联元素 块级元素的特点 xff1a 1 占一整行 2 是一个矩形 3 可定义宽度和高度 xff0c 内边距 xff0c 外边距等 4 其display属性默认为block 内联元素的特点 xff1a 1 并不占
  • 在vs code中使用git

    在vs code使用git 1 下载安装git 下载地址 xff1a Git Downloads 下载后安装选择默认选项即可 2 安装完成后 xff0c 设置git的环境变量 xff1a 在系统的path环境变量中添加git exe的安装目
  • Ubuntu下压缩与解压缩

    一 linux下常用的压缩格式 linux下常用的压缩扩展名有 xff1a tar tar bz2 tar gz 二 Windows下7ZIP软件的安装 因为Linux下很多文件是bz2 gz结尾的文件 xff0c 因此需要在windows
  • VIO的图优化模型

    因子图结构 VIO在纯视觉的基础上添加了IMU约束 xff0c 因子图如下 xff1a 状态变量 VIO中 xff0c 待估计的状态变量为 i 61 R
  • CMakeLists写法总结

    个人最近学习了一些关于常见的CMakeLists的一些写法格式 xff0c 分享给大家 CMAKE MINIMUM REQUIRED VERSION xxx 该项表示要求CMAKE的最低版本号 PROJECT aim1 此项表示所建立的工程
  • Qt两种传参形式(信号槽传参、界面传参)

    一 UI界面传参 在Qt中传输数据通常有两种形式 xff0c 一种是把待传输的数据先保存到UI界面的控件中 xff0c 然后子类从界面中读取数据 使用该控件作为参数传递承载 1 首先将计算出的数值传到控件中 ui span class to

随机推荐