图片操作说明.md 6.3 KB

通过分析图片和JSON数据,我可以明确说明坐标系的起始位置和具体规则: 2023年度报告母公司_page_001 2023年度报告母公司_page_001.json

{
	"blocks": [
		{
			"block_label": "header",
			"block_content": "广东荣德会计师事务所有限公司",
			"block_bbox": [175, 157, 594, 219]
		},
		{
			"block_label": "doc_title",
			"block_content": "审计报告",
			"block_bbox": [627, 263, 976, 325]
		},
		{
			"block_label": "footer",
			"block_content": "此码用于证明该审计报告是否由具有执业许可的会计师事务所出具...",
			"block_bbox": [527, 2235, 1411, 2297]
		}
	]
}

坐标系说明

坐标原点位置

坐标系以图片左上角为原点 (0,0)

  • X轴:从左到右递增
  • Y轴:从上到下递增

具体举例说明

1. 标题"审计报告"的坐标

{
    "block_label": "doc_title",
    "block_content": "审计报告",
    "block_bbox": [627, 263, 976, 325]
}
  • [627, 263, 976, 325] 表示:
    • 左上角:(627, 263) - 距离图片左边627像素,距离顶部263像素
    • 右下角:(976, 325) - 距离图片左边976像素,距离顶部325像素

2. 页眉公司名称的坐标

{
    "block_label": "header",
    "block_content": "广东荣德会计师事务所有限公司",
    "block_bbox": [175, 157, 594, 219]
}
  • [175, 157, 594, 219] 表示:
    • 左上角:(175, 157) - 很靠近图片顶部
    • 右下角:(594, 219)

3. 底部页脚的坐标

{
    "block_label": "footer",
    "block_content": "此码用于证明该审计报告是否由具有执业许可的会计师事务所出具...",
    "block_bbox": [527, 2235, 1411, 2297]
}
  • [527, 2235, 1411, 2297] 表示:
    • Y坐标2235、2297很大,说明位于图片底部

坐标格式规律

所有的 bbox 都采用 [x1, y1, x2, y2] 格式:

  • x1, y1:矩形框的左上角坐标
  • x2, y2:矩形框的右下角坐标

验证方法

从JSON中可以看出:

  • 页眉元素的Y坐标都在150-220范围(顶部)
  • 标题的Y坐标在260-330范围(偏上)
  • 正文内容Y坐标逐渐增大
  • 页脚元素Y坐标在2200+(底部)

这完全符合左上角为原点,Y轴向下递增的坐标系统。

Plotly坐标系

坐标系差异

1. JSON中的坐标系(图像坐标系)

  • 原点:左上角 (0,0)
  • Y轴方向:向下递增
  • 示例"block_bbox": [627, 263, 976, 325]
    • 627, 263 = 左上角坐标
    • 976, 325 = 右下角坐标

2. Plotly的坐标系(数学坐标系)

  • 原点:左下角 (0,0)
  • Y轴方向:向上递增
  • 这是标准的笛卡尔坐标系

代码中的坐标转换

fig.add_layout_image(
    dict(
        source=image,
        xref="x", yref="y",
        x=0, y=image.height,  # ← 这里是关键!
        sizex=image.width, 
        sizey=image.height,
        sizing="stretch", 
        opacity=1.0, 
        layer="below"
    )
)

y=image.height 的含义

  • 不是从左上角开始
  • 这是Plotly坐标系中的位置,表示图像的左下角位置
  • 因为Plotly原点在左下角,所以:
    • y=0 是图像底部
    • y=image.height 是图像顶部

坐标转换示例

假设图像高度为2000像素:

# JSON坐标(图像坐标系)
json_bbox = [627, 263, 976, 325]  # [x1, y1, x2, y2]

# 转换为Plotly坐标系
def convert_to_plotly_coords(bbox, image_height):
    x1, y1, x2, y2 = bbox
    # X坐标不变
    plot_x1 = x1
    plot_x2 = x2
    # Y坐标需要翻转
    plot_y1 = image_height - y2  # 原来的底部 -> Plotly的底部
    plot_y2 = image_height - y1  # 原来的顶部 -> Plotly的顶部
    return [plot_x1, plot_y1, plot_x2, plot_y2]

# 示例转换
image_height = 2000
plotly_coords = convert_to_plotly_coords([627, 263, 976, 325], image_height)
# 结果:[627, 1675, 976, 1737]

修复建议

您的代码中有坐标转换不一致的问题:

def create_resized_interactive_plot(self, image: Image.Image, selected_bbox: Optional[List[int]], zoom_level: float, all_boxes: list[tuple]) -> go.Figure:
    """创建可调整大小的交互式图片"""
    fig = go.Figure()
    
    # 添加图片 - Plotly坐标系,原点在左下角
    fig.add_layout_image(
        dict(
            source=image,
            xref="x", yref="y",
            x=0, y=image.height,  # 图片左下角在Plotly坐标系中的位置
            sizex=image.width, 
            sizey=image.height,
            sizing="stretch", 
            opacity=1.0, 
            layer="below"
        )
    )
    
    # 显示所有bbox - 需要坐标转换
    if len(all_boxes) > 0:
        for bbox in all_boxes:
            if len(bbox) >= 4:
                x1, y1, x2, y2 = bbox[:4]
                
                # 转换为Plotly坐标系(翻转Y轴)
                plot_x1 = x1
                plot_x2 = x2
                plot_y1 = image.height - y2  # JSON的y2 -> Plotly的底部
                plot_y2 = image.height - y1  # JSON的y1 -> Plotly的顶部
                
                color = "rgba(0, 100, 200, 0.2)"
                
                fig.add_shape(
                    type="rect",
                    x0=plot_x1, y0=plot_y1,
                    x1=plot_x2, y1=plot_y2,
                    line=dict(color="blue", width=1),
                    fillcolor=color,
                )

    # 高亮显示选中的bbox
    if selected_bbox and len(selected_bbox) >= 4:
        x1, y1, x2, y2 = selected_bbox[:4]
        
        # 转换为Plotly坐标系
        plot_x1 = x1
        plot_x2 = x2
        plot_y1 = image.height - y2  # 翻转Y坐标
        plot_y2 = image.height - y1  # 翻转Y坐标
        
        fig.add_shape(
            type="rect",
            x0=plot_x1, y0=plot_y1,
            x1=plot_x2, y1=plot_y2,
            line=dict(color="red", width=3),
            fillcolor="rgba(255, 0, 0, 0.3)",
        )
    
    # ...existing code...

关键点

  • y=image.height 表示图像在Plotly坐标系中的顶部位置
  • 所有bbox坐标都需要进行Y轴翻转:plotly_y = image_height - json_y
  • 这样才能确保图像和标注框正确对齐