Label Studio 图像标注坐标单位详解:LS 百分比(%)与像素(px)的换算原理与实战
Label Studio 图像标注坐标单位详解LS 百分比%与像素px的换算原理与实战【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studioLabel Studio 的图像类标注矩形框、多边形、关键点、椭圆等在注解结果中x、y、width、height等几何字段统一以相对图像宽高的百分比存储而非像素绝对值。本文以官方文档 docs/source/includes/image_units.md 为核心完整讲解这一坐标体系的含义、双向换算公式、注解结果result的完整结构并结合前端编辑器源码web/libs/editor验证其底层实现帮助你正确处理导出数据、训练集构建与模型推理结果回写。读完本文你将能够理解 Label Studio 图像标注结果中每个字段的真实含义在 Python 中自由完成「百分比 ↔ 像素」双向换算读懂任何图像类标注的 JSON 结果含旋转与多图场景并在训练自己的检测模型时准确还原像素级标注框。为什么图像标注坐标要用百分比而不是像素在 docs/source/includes/image_units.md 中明确规定图像标注结果中x、y、width、height的单位是占图像整体尺寸的百分比percentages of overall image dimension。这并非随意设计而是由 result_format 所定义的通用注解格式决定的。Label Studio 的每条标注结果region在annotation.result下存储为列表项value字段承载标注动作的几何或语义信息。对于图像类标注采用归一化百分比坐标有以下实际好处与原始图像分辨率解耦同一份标注结果可以应用于不同分辨率下的同一图像预览、缩放、适配容器时无需重新换算兼容多图与画布缩放编辑器在画布上渲染时统一将内部归一化坐标换算为画布坐标见下文源码分析导出时则记录原始图像尺寸作为换算基准统一各标签类型的存储口径矩形框、多边形、椭圆、关键点等所有图像类 region 都遵循同一套百分比规则。核心换算公式LS 百分比 ↔ 像素官方文档给出了两组标准换算公式。设original_width、original_height为原始图像的像素宽高x, y, width, height为标注结果中的百分比数值百分比 → 像素LS → Pixelpixel_x x / 100.0 * original_width pixel_y y / 100.0 * original_height pixel_width width / 100.0 * original_width pixel_height height / 100.0 * original_height像素 → 百分比Pixel → LSx pixel_x / original_width * 100.0 y pixel_y / original_height * 100.0 width pixel_width / original_width * 100.0 height pixel_height / original_height * 100.0需要注意x、y表示区域左上角相对于图像左上角的百分比偏移width、height表示区域宽高占图像宽高的百分比。因此理论上它们都应在0100区间内编辑器的拖拽范围也受此约束但通过 API 写入时引擎并不会强制限制越界值需要自行校验。完整实战示例从注解结果到像素框以下完整代码来自官方文档 image_units.md包含一个标准的图像矩形框注解 Task 结构以及两个方向的转换函数与调用验证可直接复制运行task { annotations: [{ result: [ { ...: ..., original_width: 600, original_height: 403, image_rotation: 0, value: { x: 5.33, y: 23.57, width: 29.16, height: 31.26, rotation: 0, rectanglelabels: [ Airplane ] } } ] }] } # convert from LS percent units to pixels def convert_from_ls(result): if original_width not in result or original_height not in result: return None value result[value] w, h result[original_width], result[original_height] if all([key in value for key in [x, y, width, height]]): return w * value[x] / 100.0, \ h * value[y] / 100.0, \ w * value[width] / 100.0, \ h * value[height] / 100.0 # convert from pixels to LS percent units def convert_to_ls(x, y, width, height, original_width, original_height): return x / original_width * 100.0, y / original_height * 100.0, \ width / original_width * 100.0, height / original_height * 100 # convert from LS output convert_from_ls(task[annotations][0][result][0]) if output is None: raise Exception(Wrong convert) pixel_x, pixel_y, pixel_width, pixel_height output print(pixel_x, pixel_y, pixel_width, pixel_height) # convert back to LS x, y, width, height convert_to_ls(pixel_x, pixel_y, pixel_width, pixel_height, 600, 403) print(x, y, width, height)针对上述示例数据手工验算pixel_x 5.33 / 100 * 600 31.98pixel_y 23.57 / 100 * 403 ≈ 94.99pixel_width 29.16 / 100 * 600 174.96pixel_height 31.26 / 100 * 403 ≈ 125.98。反向转换后应能恢复出原始的百分比数值浮点精度导致的微小尾差属正常现象。读懂完整的结果字段original_width / original_height / image_rotation / value结合前端源码 Image.js 的createSerializedResult实现可以看到每个图像类 region 的序列化结构由「图像维度元数据 value」两部分组成const imageDimension { original_width: currentImageEntity.naturalWidth, // 原始图像像素宽 original_height: currentImageEntity.naturalHeight, // 原始图像像素高 image_rotation: currentImageEntity.rotation, // 图像整体旋转角度度 };各字段含义如下字段类型含义original_widthnumber原始图像的像素宽度是百分比换算回像素的基准original_heightnumber原始图像的像素高度同理为换算基准image_rotationnumber图像在画布上的整体旋转角度度例如 90/180/270参与坐标系变换value.xnumber区域左上角 X占原图宽度的百分比0–100value.ynumber区域左上角 Y占原图高度的百分比0–100value.widthnumber区域宽度占原图宽度的百分比value.heightnumber区域高度占原图高度的百分比value.rotationnumber区域自身的旋转角度度不随image_rotation改变value.rectanglelabelsarray该区域命中的标签列表如[Airplane]上述字段的语义注释含0-100的取值范围说明在 RectRegion.jsx 的RectRegionResultJSDoc 中也有完整定义矩形框、椭圆、多边形、关键点等区域类型均继承该坐标体系。源码级验证前端如何序列化与换算坐标为了确证百分比坐标的底层机制可以从前端编辑器的两个关键实现点验证序列化出口Image.createSerializedResultImage.js在每次区域创建/修改时将当前图像的naturalWidth、naturalHeight与旋转角写入original_width、original_height、image_rotation再把内部归一化坐标value一并落盘。相关单元测试Image.test.js直接断言了该方法的输出结构如{ original_width: 100, original_height: 80, image_rotation: 90, value }。画布坐标换算RectRegionRectRegion.jsx通过internalToCanvasX/Y与canvasToInternalX/Y在「归一化内部坐标」与「画布像素坐标」之间往返换算canvasX/canvasY/canvasWidth/canvasHeight均由此得出而serialize()同文件 L383-L393只输出归一化的x, y, width, height, rotation给后端存储。因此无论用户在画布上如何缩放、旋转持久化到数据库的始终是百分比坐标 原始图像尺寸像素计算由读取方按需完成——这正是本文开头公式的工程基础。使用中的边界情况与注意事项结合源码与格式定义实际使用中需留意以下几点图像未加载完成时的序列化createSerializedResult中有一条保护逻辑——当图像尚未加载完成且区域携带_rawResult时会直接克隆原始结果Image.js避免以错误的尺寸元数据覆盖已有标注。若你在 API 回写时省略original_width/original_height编辑器可能无法正确换算显示。多图场景使用多图像对象标签时每个 region 还会带有item_index字段以区分属于哪张子图Image.js换算像素时必须使用对应子图的原始尺寸。旋转区域value.rotation是区域自身旋转角计算包围盒像素范围时需额外做旋转校正image_rotation是整图旋转角二者不要混淆。浮点精度反向换算后百分比可能存在极小尾差比较时建议使用容差而非严格相等。延伸阅读注解结果通用结构region、id、from_name/to_name、perRegion 等result_format图像对象标签配置多图、旋转、缩放等属性image 标签文档矩形框标签配置rectangle 标签文档前端矩形区域实现与序列化源码RectRegion.jsx图像元数据注入与序列化源码Image.js测试套件中的真实图像标注样例含 bbox ground truthimage_urls_with_bboxes_gt.json掌握「百分比为存储单位、像素为计算单位」这一原则后无论你是导出标注训练目标检测模型还是把模型预测结果回写为 Label Studio 注解都能在两种坐标系间准确无误地往返切换。【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考