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

如何实现sort_contours函数从右到左排序及多行文本读取?

解决方案:支持多行+右到左排序的sort_contours函数

原函数仅支持单一轴的排序逻辑,无法适配多行文本场景。要实现多行文本的右到左排序,需要先按行分组轮廓,再在每行内执行右到左排序,具体修改如下:

修改后的函数代码

import cv2
import numpy as np

def sort_contours(cnts, method="right-to-left", multi_line=True, line_threshold_ratio=0.5):
    try:
        # 获取所有轮廓的外接矩形
        boundingBoxes = [cv2.boundingRect(c) for c in cnts]
        # 先按y轴坐标排序,为行分组做准备
        cnts_boxes_sorted_y = sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][1])
        
        if not multi_line:
            # 不启用多行模式,沿用原单一维度排序逻辑
            reverse = False
            i = 0
            if method == "right-to-left" or method == "bottom-to-top":
                reverse = True
            if method == "top-to-bottom" or method == "bottom-to-top":
                i = 1
            cnts_sorted, boxes_sorted = zip(*sorted(zip(cnts, boundingBoxes),
                                                   key=lambda b: b[1][i], reverse=reverse))
            return cnts_sorted, boxes_sorted
        
        # 多行模式:先分组行,再每行内排序
        grouped_rows = []
        current_row = [cnts_boxes_sorted_y[0]]
        # 计算所有轮廓的平均高度,作为行分组的阈值依据
        avg_height = np.mean([box[3] for _, box in cnts_boxes_sorted_y])
        line_threshold = avg_height * line_threshold_ratio
        
        for cb in cnts_boxes_sorted_y[1:]:
            current_box = cb[1]
            prev_box = current_row[-1][1]
            # 通过y坐标差判断是否属于同一行
            if abs(current_box[1] - prev_box[1]) < line_threshold:
                current_row.append(cb)
            else:
                grouped_rows.append(current_row)
                current_row = [cb]
        grouped_rows.append(current_row)
        
        # 对每行内的轮廓按指定方法排序
        sorted_cnts = []
        sorted_boxes = []
        for row in grouped_rows:
            if method == "right-to-left":
                # 按x坐标降序实现右到左排序
                row_sorted = sorted(row, key=lambda b: b[1][0], reverse=True)
            elif method == "left-to-right":
                row_sorted = sorted(row, key=lambda b: b[1][0])
            elif method == "top-to-bottom":
                row_sorted = sorted(row, key=lambda b: b[1][1])
            elif method == "bottom-to-top":
                row_sorted = sorted(row, key=lambda b: b[1][1], reverse=True)
            else:
                row_sorted = row
            
            cnts_row, boxes_row = zip(*row_sorted)
            sorted_cnts.extend(cnts_row)
            sorted_boxes.extend(boxes_row)
        
        return tuple(sorted_cnts), tuple(sorted_boxes)
    
    except Exception as e:
        print(f"Error: {str(e)}")
        return cnts, boundingBoxes

关键逻辑说明

  • 行分组:通过计算轮廓外接矩形的y坐标差,结合平均高度的比例阈值,将同一行的轮廓归为一组,避免不同行的轮廓被错误排序。
  • 多行内排序:对每个行组单独执行指定的排序方法,保证每行的文本顺序符合需求。
  • 兼容原有功能:保留multi_line参数,设为False时可回到原函数的单一轴排序逻辑,不影响原有代码的其他调用场景。

调用方式

保持原有调用形式即可,多行处理默认开启:

cnts, boundingBoxes_sorted = sort_contours(cnts, method="right-to-left")
# 若需关闭多行模式,可显式指定
# cnts, boundingBoxes_sorted = sort_contours(cnts, method="right-to-left", multi_line=False)

注意事项

  • 若行分组效果不佳,可调整line_threshold_ratio参数(默认0.5):增大该值可将y坐标差更大的轮廓归为同一行,反之则分组更严格。
  • 函数仅调整轮廓的排序顺序,不会修改轮廓本身,不会影响后续预测结果。

内容的提问来源于stack exchange,提问作者jumanah mutahhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 22:20:41