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

如何用OpenCV Python准确提取矩形尺寸与坐标并分割矩形?

问题解决与脚本优化

一、cv2.boundingRect()绘制不匹配的原因及修复

核心问题分析

绘制不匹配主要源于两个错误:

  • 阈值处理颠倒:目标是黑色矩形,默认cv2.THRESH_BINARY会将黑色区域转为0(黑色)、背景转为255(白色),但cv2.findContours仅识别白色轮廓,导致提取的是背景而非目标矩形。
  • 轮廓层级错误:cv2.RETR_TREE会提取所有嵌套层级的轮廓,可能包含矩形内部杂色小轮廓,造成坐标混乱。

修复代码

# 读取灰度图
img2 = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
# 反转阈值,让黑色矩形变为白色轮廓、背景变黑
_, threshold = cv2.threshold(img2, 110, 255, cv2.THRESH_BINARY_INV)
# 仅提取最外层轮廓,避免嵌套干扰
contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

coordinates = []
for cnt in contours:
    # 过滤过小轮廓(根据实际场景调整阈值)
    if cv2.contourArea(cnt) < 50:
        continue
    x, y, w, h = cv2.boundingRect(cnt)
    coordinates.append([x, y, w, h])

# 测试绘制匹配度
test_img = cv2.imread(img)
for x, y, w, h in coordinates:
    # 绘制矩形:左上角(x,y) → 右下角(x+w, y+h)
    cv2.rectangle(test_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imwrite("test_match.png", test_img)

二、通过矩形4个角点计算宽高

分两种场景处理:

1. 轴对齐矩形(边平行于坐标轴)

直接取x、y坐标的极值计算:

# 假设corners是包含4个(x,y)元组的列表
x_coords = [p[0] for p in corners]
y_coords = [p[1] for p in corners]
width = max(x_coords) - min(x_coords)
height = max(y_coords) - min(y_coords)
# 左上角坐标:(min(x_coords), min(y_coords))

2. 旋转矩形(边不平行于坐标轴)

计算相邻角点的欧氏距离,取两组不同长度作为宽高:

import math

def calc_distance(p1, p2):
    return math.sqrt((p2[0]-p1[0])**2 + (p2[1]-p1[1])**2)

# 计算所有两两角点的距离,过滤极小误差值
distances = []
for i in range(4):
    for j in range(i+1, 4):
        d = calc_distance(corners[i], corners[j])
        if d > 1:
            distances.append(d)
# 去重排序后,短边为宽、长边为高
unique_dists = sorted(list(set([round(d, 2) for d in distances])))
width, height = unique_dists[0], unique_dists[1]

三、优化后的批量分割脚本

修复语法错误、轮廓提取问题,确保分割矩形不超出原范围:

import cv2
import random
from datetime import datetime

def split_vertical(img_path):
    # 读取原图与灰度图
    image = cv2.imread(img_path)
    img_gray = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    
    # 反转阈值提取黑色矩形轮廓
    _, threshold = cv2.threshold(img_gray, 110, 255, cv2.THRESH_BINARY_INV)
    # 仅提取最外层轮廓
    contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    coordinates = []
    for cnt in contours:
        # 过滤小轮廓
        if cv2.contourArea(cnt) < 50:
            continue
        x, y, w, h = cv2.boundingRect(cnt)
        coordinates.append([x, y, w, h])
    
    # 随机选6个矩形(轮廓不足6个则取全部)
    select_count = min(6, len(coordinates))
    numbers = random.sample(range(len(coordinates)), select_count)
    
    for j in numbers:
        timestamp = datetime.now().strftime('%Y%m%d%H%M%S%f')
        new_image = image.copy()
        x, y, width, height = coordinates[j]
        
        # 计算分割位置与宽度,确保不超出原矩形
        split_offset = random.uniform(0.2, 0.5)  # 分割点在原矩形20%-50%位置
        split_position = int(x + width * split_offset)
        max_split_width = x + width - split_position
        split_width = int(random.uniform(0.03, 0.7) * max_split_width)
        
        # 绘制白色分割矩形
        cv2.rectangle(new_image, (split_position, y), 
                      (split_position + split_width, y + height), 
                      (255, 255, 255), -1)
        
        # 保存图片
        cv2.imwrite(f"data_augmentation/split_vertical_{timestamp}.png", new_image)

# 调用示例
# split_vertical("your_image_path.png")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:45:00