通过分析图片和JSON数据,我可以明确说明坐标系的起始位置和具体规则: ![2023年度报告母公司_page_001](image/图片操作说明/2023年度报告母公司_page_001.png) [2023年度报告母公司_page_001.json](image/图片操作说明/2023年度报告母公司_page_001.json) ```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. **标题"审计报告"的坐标** ```json { "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. **页眉公司名称的坐标** ```json { "block_label": "header", "block_content": "广东荣德会计师事务所有限公司", "block_bbox": [175, 157, 594, 219] } ``` - `[175, 157, 594, 219]` 表示: - 左上角:(175, 157) - 很靠近图片顶部 - 右下角:(594, 219) #### 3. **底部页脚的坐标** ```json { "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轴方向**:向上递增 - **这是标准的笛卡尔坐标系** ## 代码中的坐标转换 ````python 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像素: ````python # 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] ```` ## 修复建议 您的代码中有坐标转换不一致的问题: ````python 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` - 这样才能确保图像和标注框正确对齐 # ocr json结果坐标旋转说明 在坐标系中,原点位于左上角,x轴向右增加,y轴向下增加(类似于屏幕坐标系)。绕原点旋转任意角度θ(θ为用户视角的逆时针角度)的旋转矩阵为: ```math \begin{bmatrix} x' \\ y' \end{bmatrix} = \begin{bmatrix} \cos \theta & \sin \theta \\ -\sin \theta & \cos \theta \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} ``` 其中: - \((x, y)\) 是旋转前的坐标, - \((x', y')\) 是旋转后的坐标, - \(\theta\) 是旋转角度(以弧度表示),用户视角的逆时针方向为正。 ### 说明: - 这个矩阵实现了从用户视角看到的逆时针旋转。例如,当θ = 90°(π/2弧度)时,点(1, 0)会旋转到(0, -1),即指向屏幕上方(y负方向)。 - 如果使用角度制,确保在计算前将角度转换为弧度(因为三角函数通常使用弧度)。 - 该矩阵适用于任何旋转角度θ。