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

基于3×3卷积滤波器的旋转正方形角点检测技术问询

Solution for Converting Corner Response Maps to Single-Pixel Markers

Let's break down how to turn those response maps into clean, single-pixel corner markers for each square. Here's what we need to do step by step:

Key Steps

1. Non-Maximum Suppression (NMS)

Each corner will produce a blob of high response values in its corresponding map. We only want the local maximum pixel (the peak of that blob) to be our corner marker. This eliminates all redundant pixels around the actual corner.

2. Threshold Filtering

Not every local maximum is a real corner—we need to filter out low-response noise by setting a threshold. Only pixels with response values above this threshold are kept as valid corners.

3. Mark or Extract Corners

Once we have the cleaned maps, we can either draw the corners on an image (with different colors for each corner type) or extract their coordinates for further use.

Modified Code

Here's the updated implementation that adds these steps to your existing code:

import numpy as np
import cv2 as cv

def non_max_suppression(response_map, kernel_size=3):
    # Use dilation to find local maxima across the response map
    kernel = np.ones((kernel_size, kernel_size), dtype=np.float32)
    local_max = cv.dilate(response_map, kernel)
    # Keep only pixels that equal the local maximum (suppress others)
    nms_map = np.where(response_map == local_max, response_map, 0)
    return nms_map

def corners_of_square(img: np.ndarray, threshold=10.0) -> tuple[np.ndarray, list]:
    img_cp = img.copy()
    if img_cp.ndim == 3:
        img_cp = cv.cvtColor(img_cp, cv.COLOR_BGR2GRAY).astype(np.float32)
    
    # Define the 4 corner filters (removed duplicate definitions)
    Z = np.array([ # top corner
        [ 1, 1, 1],
        [ 1, -1, -1],
        [ 1, -1, -1]
    ], dtype=np.float32)
    D = np.array([ # right corner
        [ 1, 1, 1],
        [-1, -1, 1],
        [-1, -1, 1]
    ], dtype=np.float32)
    L = np.array([ # left corner
        [ 1, -1, -1],
        [ 1, -1, -1],
        [ 1, 1, 1]
    ], dtype=np.float32)
    S = np.array([ # bottom corner
        [-1, -1, 1],
        [-1, -1, 1],
        [ 1, 1, 1]
    ], dtype=np.float32)

    # Generate response maps
    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)

    # Apply non-maximum suppression to each response map
    nms_z = non_max_suppression(rZ)
    nms_d = non_max_suppression(rD)
    nms_l = non_max_suppression(rL)
    nms_s = non_max_suppression(rS)

    # Filter out low-response pixels using the threshold
    nms_z = np.where(nms_z > threshold, 255, 0).astype(np.uint8)
    nms_d = np.where(nms_d > threshold, 255, 0).astype(np.uint8)
    nms_l = np.where(nms_l > threshold, 255, 0).astype(np.uint8)
    nms_s = np.where(nms_s > threshold, 255, 0).astype(np.uint8)

    # Create a marked image with colored corners
    marked_img = np.zeros_like(img)
    # Top corners: Red
    marked_img[nms_z == 255] = [0, 0, 255]
    # Right corners: Green
    marked_img[nms_d == 255] = [0, 255, 0]
    # Left corners: Blue
    marked_img[nms_l == 255] = [255, 0, 0]
    # Bottom corners: Yellow
    marked_img[nms_s == 255] = [0, 255, 255]

    # Collect corner coordinates with their type
    corner_coords = []
    # Convert (y, x) from argwhere to standard (x, y) coordinates
    for y, x in np.argwhere(nms_z == 255):
        corner_coords.append( (x, y, "top") )
    for y, x in np.argwhere(nms_d == 255):
        corner_coords.append( (x, y, "right") )
    for y, x in np.argwhere(nms_l == 255):
        corner_coords.append( (x, y, "left") )
    for y, x in np.argwhere(nms_s == 255):
        corner_coords.append( (x, y, "bottom") )

    return marked_img, corner_coords

if __name__ == '__main__':
    # Replace with your image path
    rotated_squares_img = cv.imread("rotirani_kvadrati.png").astype(np.float32) / 255
    # Adjust threshold based on your image's response values
    marked_corners, corner_list = corners_of_square(rotated_squares_img, threshold=8.0)

    cv.imshow("Original Squares", rotated_squares_img)
    cv.imshow("Marked Corners", marked_corners)
    print("Detected corners:", corner_list)
    cv.waitKey(0)
    cv.destroyAllWindows()

Notes

  • Threshold Adjustment: The threshold value may need tuning. Check the range of your response maps (print np.max(rZ), np.min(rZ)) to set a value that filters noise but keeps real corners.
  • Rotated Squares: If your squares are heavily rotated, these fixed-orientation filters might miss some corners. For better rotation invariance, you could add more filters covering intermediate angles, or switch to a rotation-invariant detector like Harris corner detection—but your current approach works great for axis-aligned or slightly rotated squares.
  • Cleanup: I removed the redundant redefinitions of L and S in your original code to keep things tidy.

内容的提问来源于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.27 09:52:38