You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缩小表格图像内的文本bounding box使其紧密贴合文本内容

问题描述

我有一张尺寸为(328, 231)的表格图像,图像上的文本bounding box存储在一个字典中。

表格图像

字典内容如下:

{"bounding_boxes": [{"class": "text", "box": [0.0, 0.0, 53.94900093453785, 18.455579291781646]}, {"class": "text", "box": [53.94900093453785, 0.0, 184.96800320412976, 51.735807141009545]}, {"class": "text", "box": [184.96800320412976, 0.0, 256.199368074407, 51.735807141009545]}, {"class": "text", "box": [256.199368074407, 0.0, 328.0, 51.735807141009545]}, {"class": "text", "box": [0.0, 18.455579291781646, 53.94900093453785, 76.14130756377666]}, {"class": "text", "box": [53.94900093453785, 51.735807141009545, 184.96800320412976, 76.14130756377666]}, {"class": "text", "box": [184.96800320412976, 51.735807141009545, 256.199368074407, 76.14130756377666]}, {"class": "text", "box": [256.199368074407, 51.735807141009545, 328.0, 76.14130756377666]}, {"class": "text", "box": [0.0, 76.14130756377666, 53.94900093453785, 105.33448988766077]}, {"class": "text", "box": [53.94900093453785, 76.14130756377666, 184.96800320412976, 115.66887643031575]}, {"class": "text", "box": [184.96800320412976, 76.14130756377666, 256.199368074407, 115.66887643031575]}, {"class": "text", "box": [256.199368074407, 76.14130756377666, 328.0, 115.66887643031575]}, {"class": "text", "box": [0.0, 105.33448988766077, 53.94900093453785, 146.28279243942194]}, {"class": "text", "box": [53.94900093453785, 115.66887643031575, 184.96800320412976, 146.28279243942194]}, {"class": "text", "box": [184.96800320412976, 115.66887643031575, 256.199368074407, 146.28279243942194]}, {"class": "text", "box": [256.199368074407, 115.66887643031575, 328.0, 146.28279243942194]}, {"class": "text", "box": [0.0, 146.28279243942194, 53.94900093453785, 175.9430656804882]}, {"class": "text", "box": [53.94900093453785, 146.28279243942194, 184.96800320412976, 201.86661158409726]}, {"class": "text", "box": [184.96800320412976, 146.28279243942194, 256.199368074407, 201.86661158409726]}, {"class": "text", "box": [256.199368074407, 146.28279243942194, 328.0, 201.86661158409726]}, {"class": "text", "box": [0.0, 175.9430656804882, 53.94900093453785, 231.0]}, {"class": "text", "box": [53.94900093453785, 201.86661158409726, 184.96800320412976, 219.67445280166658]}, {"class": "text", "box": [184.96800320412976, 201.86661158409726, 256.199368074407, 219.67445280166658]}, {"class": "text", "box": [256.199368074407, 201.86661158409726, 328.0, 219.67445280166658]}, {"class": "text", "box": [53.94900093453785, 219.67445280166658, 184.96800320412976, 231.0]}, {"class": "text", "box": [184.96800320412976, 219.67445280166658, 256.199368074407, 231.0]}, {"class": "text", "box": [256.199368074407, 219.67445280166658, 328.0, 231.0]}]}

将上述JSON数据中的bounding box绘制到图像上后效果如下:
绘制bounding box后的表格图像

我想要将这些框缩小,使其紧密包裹文本,预期效果参考下图:
预期效果示例

我尝试结合图像阈值处理使用cv2.boundingRect()实现该需求,但未成功,尝试的代码如下:

data = <<上述字典内容>>
new_boxes = list()
img = cv2.imread('sam.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8)
for item in data["bounding_boxes"]:
    xmin = int(item['box'][0])
    ymin = int(item['box'][1])
    xmax = int(item['box'][2])
    ymax = int(item['box'][3])
    crop_img = gray[ymin:ymax, xmin:xmax]
    coords = cv2.findNonZero(crop_img)
    x, y, w, h = cv2.boundingRect(coords)
    new_box = [x, y, w+x, h+y]
    new_boxes.append(new_box)

解决方案

你的代码核心问题是计算得到的裁剪图内文本坐标没有映射回原图像坐标体系,调整后的完整可运行代码如下:

import cv2
import numpy as np

# 替换为你实际的bounding box字典数据
data = {"bounding_boxes": [...]}
new_boxes = []
img = cv2.imread('sam.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 改用OTSU自动阈值二值化,适配不同明暗的文本图像
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 可选:加1像素膨胀,避免框过紧切掉文字笔画
kernel = np.ones((1, 1), np.uint8)
binary = cv2.dilate(binary, kernel, iterations=1)

for item in data["bounding_boxes"]:
    # 坐标四舍五入比直接int截断更准确
    xmin = int(round(item['box'][0]))
    ymin = int(round(item['box'][1]))
    xmax = int(round(item['box'][2]))
    ymax = int(round(item['box'][3]))
    # 坐标越界校验
    xmin, ymin = max(0, xmin), max(0, ymin)
    xmax = min(img.shape[1], xmax)
    ymax = min(img.shape[0], ymax)
    if xmax <= xmin or ymax <= ymin:
        new_boxes.append([xmin, ymin, xmax, ymax])
        continue
    crop_img = binary[ymin:ymax, xmin:xmax]
    coords = cv2.findNonZero(crop_img)
    if coords is None:
        # 裁剪区域无有效文本,保留原框
        new_boxes.append([xmin, ymin, xmax, ymax])
        continue
    x, y, w, h = cv2.boundingRect(coords)
    # 核心修正:将裁剪区相对坐标叠加原框偏移,映射回原图像坐标
    new_xmin = xmin + x
    new_ymin = ymin + y
    new_xmax = new_xmin + w
    new_ymax = new_ymin + h
    new_boxes.append([new_xmin, new_ymin, new_xmax, new_ymax])

核心修改点说明:

  • 坐标映射修正:裁剪图上计算得到的文本框坐标是相对裁剪区左上角的,需要叠加原框的xmin、ymin偏移才能得到原图像上的真实坐标
  • 阈值优化:替换固定阈值128为OTSU自动二值化,适配不同光照、对比度的图像
  • 鲁棒性优化:增加坐标越界、无文本区域的校验逻辑,避免代码运行报错
  • 效果优化:可选的1像素膨胀操作,避免最终框过紧切掉文字边缘笔画,可根据实际效果调整膨胀参数

内容的提问来源于stack exchange,提问作者Arpita Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 20:48:01