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

基于3×3卷积滤波器的旋转正方形角点检测:单像素角点提取实现疑问

解决正方形角点单像素标记问题

你已经完成了最关键的一步——用方向滤波器生成了四个角点的响应图,现在只需要把这些连续的响应值转换成每个角点对应的单个像素点。核心思路是提取每个响应图中的局部最大值(因为真正的角点位置会是响应最强的点),再过滤掉噪声,最终得到精准的单像素标记。

关键步骤解析

1. 非极大值抑制(NMS)

每个响应图中,真正的角点是局部区域内响应最强的像素,我们需要用非极大值抑制把连续的响应区域压缩到单个像素:

  • 对每个通道的响应图做膨胀操作,得到每个位置的局部最大值
  • 只保留原响应图中等于局部最大值的像素,其他置0,这样就得到了仅含局部峰值的图

2. 阈值筛选

设置一个合理的响应阈值,过滤掉响应值过低的噪声点,只保留真正的角点候选。阈值可以根据你的测试图像调整。

3. (可选)角点匹配与验证

如果图像中有多个正方形,你可以进一步对候选点进行聚类,确保每个正方形的四个角点(上、右、左、下)一一对应,不过如果正方形不重叠,这一步可以简化。

修改后的完整代码

import numpy as np
import cv2 as cv
from pathlib import Path

UTILS = Path("./")  # 根据你的实际路径修改

def non_max_suppression(response_map, kernel_size=3):
    """对响应图应用非极大值抑制,保留局部最大值点"""
    kernel = np.ones((kernel_size, kernel_size), dtype=np.float32)
    # 膨胀操作提取局部最大值
    local_max = cv.dilate(response_map, kernel)
    # 仅保留等于局部最大值的像素
    nms_map = np.where(response_map == local_max, response_map, 0)
    return nms_map

def corners_of_square(img: np.ndarray, threshold=1.0) -> np.ndarray:
    img_cp = img.copy()
    if img_cp.ndim == 3:
        img_cp = cv.cvtColor(img_cp, cv.COLOR_BGR2GRAY).astype(np.float32)
    img_cp = img_cp.astype(np.float32)

    # 四个方向的角点滤波器(删除了重复定义的L和S)
    Z = np.array([  # 顶部角点 (Top)
        [ 1, 1, 1],
        [ 1, -1, -1],
        [ 1, -1, -1]
    ], dtype=np.float32)
    D = np.array([  # 右侧角点 (Right)
        [ 1, 1, 1],
        [-1, -1, 1],
        [-1, -1, 1]
    ], dtype=np.float32)
    L = np.array([  # 左侧角点 (Left)
        [ 1, -1, -1],
        [ 1, -1, -1],
        [ 1, 1, 1]
    ], dtype=np.float32)
    S = np.array([  # 底部角点 (Bottom)
        [-1, -1, 1],
        [-1, -1, 1],
        [ 1, 1, 1]
    ], dtype=np.float32)

    # 生成响应图
    rZ = cv.filter2D(img_cp, cv.CV_32F, Z)
    rD = cv.filter2D(img_cp, cv.CV_32F, D)
    rL = cv.filter2D(img_cp, cv.CV_32F, L)
    rS = cv.filter2D(img_cp, cv.CV_32F, S)

    # 对每个响应图应用非极大值抑制
    rZ_nms = non_max_suppression(rZ)
    rD_nms = non_max_suppression(rD)
    rL_nms = non_max_suppression(rL)
    rS_nms = non_max_suppression(rS)

    # 应用阈值过滤噪声
    rZ_thresholded = np.where(rZ_nms > threshold, 1, 0)
    rD_thresholded = np.where(rD_nms > threshold, 1, 0)
    rL_thresholded = np.where(rL_nms > threshold, 1, 0)
    rS_thresholded = np.where(rS_nms > threshold, 1, 0)

    # 堆叠成4通道输出(Z、D、L、S顺序),每个通道的1表示该位置是对应方向的角点
    out = np.stack([rZ_thresholded, rD_thresholded, rL_thresholded, rS_thresholded], axis=2)
    return out

def visualize_corners(original_img, corner_map):
    """可视化角点:用不同颜色标记四个方向的角点"""
    vis_img = original_img.copy()
    if vis_img.ndim == 2:
        vis_img = cv.cvtColor(vis_img, cv.COLOR_GRAY2BGR)
    
    # 获取各通道的角点坐标
    top_y, top_x = np.where(corner_map[..., 0] == 1)
    right_y, right_x = np.where(corner_map[..., 1] == 1)
    left_y, left_x = np.where(corner_map[..., 2] == 1)
    bottom_y, bottom_x = np.where(corner_map[..., 3] == 1)

    # 标记角点:顶部(红)、右侧(绿)、左侧(蓝)、底部(黄)
    for y, x in zip(top_y, top_x):
        cv.circle(vis_img, (x, y), 2, (0, 0, 255), -1)
    for y, x in zip(right_y, right_x):
        cv.circle(vis_img, (x, y), 2, (0, 255, 0), -1)
    for y, x in zip(left_y, left_x):
        cv.circle(vis_img, (x, y), 2, (255, 0, 0), -1)
    for y, x in zip(bottom_y, bottom_x):
        cv.circle(vis_img, (x, y), 2, (0, 255, 255), -1)
    
    return vis_img

if __name__ == '__main__':
    rotated_squares_img = cv.imread(str(UTILS/"rotirani_kvadrati.png")).astype(np.float32) / 255
    corners_map = corners_of_square(rotated_squares_img, threshold=1.5)  # 可调整阈值
    vis_img = visualize_corners(rotated_squares_img, corners_map)

    cv.imshow("Original Rotated Squares", rotated_squares_img)
    cv.imshow("Marked Corners", vis_img)
    cv.waitKey(0)
    cv.destroyAllWindows()

代码说明

  • 新增的non_max_suppression函数专门提取局部最大值,确保每个角点只保留一个像素点
  • visualize_corners函数用不同颜色直观标记四个方向的角点,方便你验证结果
  • 删掉了代码中重复定义的L和S滤波器,减少冗余
  • 阈值参数可以根据你的测试图像调整,确保过滤掉噪声同时保留所有真实角点

如果你的正方形是旋转的,当前的滤波器可能对大角度旋转的角点响应不够好,后续可以考虑使用旋转不变的角点检测方法(比如Harris角点检测),但基于你现有的滤波器方案,上面的修改已经可以实现单像素标记的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:40:13