如何缩小表格图像内的文本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绘制到图像上后效果如下:
我想要将这些框缩小,使其紧密包裹文本,预期效果参考下图:
我尝试结合图像阈值处理使用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
相关产品推荐
相关产品推荐

