cv2函数实践-图像处理(求点到直线距离/旋转框处理/旋转抠图/直线拟合及后处理/求直线交点/轮廓处理)

目录

快速求N个点到一条直线的距离

cv2.minAreaRect函数及旋转框后处理方法

求旋转框的长边、短边、旋转角度、关键点坐标

裁剪旋转框(最小旋正角度抠图)

cv2.fitLine函数及后处理方法

穿过图像画直线

计算两条直线交点

提取图像内部的轮廓点


快速求N个点到一条直线的距离

Python, OpenCV, Numpy

def get_distance_line_and_p_batch(line, p1_list):
    """
    求点到直线距离
    :param line: array([[vx], [vy], [x0], [y0]], dtype=float32)
    :param p1_list: 线外点
    :return:
        每个线外点到直线距离(垂直)
        每个线外点在直线垂线交点的X
        每个线外点在直线垂线交点的Y
    """
    vx, vy, x0, y0 = line
    vx = vx[0]
    vy = vy[0]
    x0 = x0[0]
    y0 = y0[0]

    B0 = [vy * x0 - vx * y0] * len(p1_list)
    B1 = [vx * p1[0] + vy * p1[1] for p1 in p1_list]

    A = np.array([[vy, -vx], [vx, vy]], dtype=np.float32)
    B = np.array([B0, B1], dtype=np.float32)
    ret, X = cv2.solve(A, B, flags=cv2.DECOMP_LU)
    x2 = X[0, :]
    y2 = X[1, :]

    x1 = np.array([p1[0] for p1 in p1_list], dtype=np.float32)
    y1 = np.array([p1[1] for p1 in p1_list], dtype=np.float32)

    return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5, x2, y2

cv2.minAreaRect函数及旋转框后处理方法

求旋转框的长边、短边、旋转角度、关键点坐标
def find_rotRect_long_side(rotRect):
    (cx, cy), (cw, ch), angle = rotRect
    cw2d, ch2d, theta = cw / 2, ch / 2, np.pi * angle / 180  # cw/2, ch/2, 旋转角(弧度制)
    cA = (cx - cw2d * np.cos(theta), cy - cw2d * np.sin(theta))
    cB = (cx + cw2d * np.cos(theta), cy + cw2d * np.sin(theta))
    cC = (cx - ch2d * np.sin(theta), cy + ch2d * np.cos(theta))
    cD = (cx + ch2d * np.sin(theta), cy - ch2d * np.cos(theta))
    # cAB = np.sqrt((cA[0] - cB[0]) ** 2 + (cA[1] - cB[1]) ** 2)  # ==cw
    # cCD = np.sqrt((cC[0] - cD[0]) ** 2 + (cC[1] - cD[1]) ** 2)  # ==ch
    point_AD = (cA[0] + ch2d * np.sin(theta), cA[1] - ch2d * np.cos(theta))  # A和D的所在直线的交点,旋转框的一个角点坐标
    point_AC = (cA[0] - ch2d * np.sin(theta), cA[1] + ch2d * np.cos(theta))
    point_BD = (cB[0] + ch2d * np.sin(theta), cB[1] - ch2d * np.cos(theta))
    point_BC = (cB[0] - ch2d * np.sin(theta), cB[1] + ch2d * np.cos(theta))
    if cw > ch:  # cAB > cCD, cw > ch
        point_start = cA
        point_end = cB
        long_length = float(cw)
        long_angle = angle
        point_upper_long_line = cD
        point_lower_long_line = cC  # cC在cD左下方
        short_length = float(ch)
    else:
        point_start = cC
        point_end = cD
        long_length = float(ch)
        long_angle = angle - 90  # 逆时针
        point_upper_long_line = cA
        point_lower_long_line = cB
        short_length = float(cw)
    # point_start/point_end: 长边方向的起始点和结束点,起始点总是在结束点的左侧
    # point_upper_long_line/point_lower_long_line: 短边方向的两个点,被长边直线隔开
    return dict(point_start=point_start, point_end=point_end, point_center=(cx, cy),
                long_length=long_length, long_angle=long_angle, short_length=short_length,
                point_upper_long_line=point_upper_long_line, point_lower_long_line=point_lower_long_line,
                point_AD=point_AD, point_AC=point_AC, point_BD=point_BD, point_BC=point_BC)
裁剪旋转框(最小旋正角度抠图)
def crop_minAreaRect_with_min_angle(rot3: Tuple, img: np.ndarray):
    (cx, cy), (cw, ch), angle = rot3  # angle属于(0,90],为x轴(矩形最低点) 顺时针 旋转的角度
    height, width = img.shape[:2]
    # min_angle = angle if angle < 45 else angle - 90  # min_angle为正,则逆时针旋转图像
    if angle < 45:
        w, h = cw, ch  # 逆时针旋转跟x轴重合
        rotate_matrix = cv2.getRotationMatrix2D(center=(cx, cy), angle=angle, scale=1)
    else:
        w, h = ch, cw  # 顺时针旋转跟x轴重合
        rotate_matrix = cv2.getRotationMatrix2D(center=(cx, cy), angle=angle - 90, scale=1)
    rotated_image = cv2.warpAffine(src=img, M=rotate_matrix, dsize=(width, height))
    x0, y0 = max(0, int(cx - w/2 + 0.5)), max(0, int(cy - h/2 + 0.5))  # 左上角xy,注意左上角可能越界
    x1, y1 = min(width, int(cx + w/2 + 0.5)), min(height, int(cy + h/2 + 0.5))  # 右下角xy
    return rotated_image[y0:y1, x0:x1]

cv2.fitLine函数及后处理方法

穿过图像画直线
def draw_line_crossImg(img: np.ndarray, line, scale_xy=1.0, color=(0,0,0)):
    """
    穿过整张图,画一条直线
    :param line: fitLine的结果,array([[vx], [vy], [x0], [y0]], dtype=float32)
    :param scale_xy: x0, y0的缩放比例
    """
    h, w = img.shape[:2]
    vx, vy, x0, y0 = line
    vx = vx[0]
    vy = vy[0]
    x0 = x0[0] * scale_xy
    y0 = y0[0] * scale_xy
    pts = []
    dxy = vx / (vy + 1e-7)
    for y1 in [0, h-1]:
        x1 = x0 + (y1 - y0) * dxy
        if 0 <= x1 < w: pts.append((x1, y1))
    if len(pts) < 2:
        dyx = vy / (vx + 1e-7)
        for x1 in [0, w-1]:
            y1 = y0 + (x1 - x0) * dyx
            if 0 <= y1 < h: pts.append((x1, y1))
    cv2.line(img, (round(pts[0][0]), round(pts[0][1])), (round(pts[1][0]), round(pts[1][1])), color)
    return pts

 

计算两条直线交点
def calc_2lines_intersection(line1_params, line2_params):
    """
    计算两直线交点,传入cv2.fitLine返回值格式的两条直线
    Args:
        line1_params:
        line2_params:
    # # 使用cv2.fitLine函数计算两条直线的参数
    # line1_params = cv2.fitLine(np.array([line1_start, line1_end]), cv2.DIST_L2, 0, 0.01, 0.01)
    # line2_params = cv2.fitLine(np.array([line2_start, line2_end]), cv2.DIST_L2, 0, 0.01, 0.01)
    Returns:
    """
    vx, vy, x0, y0 = line1_params
    a1, b1, c1 = vy[0], -vx[0], vx[0] * y0[0] - vy[0] * x0[0]

    vx, vy, x0, y0 = line2_params
    a2, b2, c2 = vy[0], -vx[0], vx[0] * y0[0] - vy[0] * x0[0]

    # 处理平行和垂直的特殊情况
    delta = a2 * b1 - a1 * b2
    if abs(delta) < 1e-10:
        # 平行情况,返回None
        return None
    # 计算交点的x和y坐标
    x_intersect = (b2 * c1 - b1 * c2) / delta
    y_intersect = (a1 * c2 - a2 * c1) / delta
    return x_intersect, y_intersect

提取图像内部的轮廓点

def extract_inside_pts_of_contour(contour, w, h, ):
    """
    contour是在wxh大小的图中的一个轮廓,目的是提取内部轮廓点(剔除图边界上的轮廓点)
    """
    cond_w = (2 < contour[:, 0, 0]) & (contour[:, 0, 0] < w - 2)
    cond_h = (2 < contour[:, 0, 1]) & (contour[:, 0, 1] < h - 2)
    # print(cond_w.shape, cond_h.shape, )  # (163,) (163,)
    return contour[cond_w & cond_h]  # 剔除边界上的轮廓点, (159, 1, 2)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值