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

Python-OpenCV轮廓峰值检测:利用局部最大值计数遮挡人群

解决遮挡场景下的人员计数:提取轮廓局部最大值(头部点)

Got it, let's tackle this problem step by step. Since you're dealing with occluded people and already have the contours, extracting local maxima (head positions) is a really solid approach—way better than trying to count full contours when occlusion messes things up. You already know how to get the global topmost point, so expanding that to find all local peaks makes perfect sense.

核心思路

In image coordinates, the y-axis points downward, so the "topmost" point of a head will have the smallest y-value in its local neighborhood. We can scan each contour to find all points that are the lowest y-value (i.e., highest in the image) within a small window of surrounding contour points, then filter out duplicates to get distinct head positions.

具体实现步骤与代码

Here’s a practical OpenCV-based Python implementation that builds on the global topmost logic you already have:

import numpy as np
import cv2

def find_local_head_points(contour, window_size=7, distance_threshold=10):
    # Convert contour points to a clean array of (x,y) coordinates
    contour_points = contour.squeeze().astype(np.int32)
    local_peaks = []
    
    # Skip edge points to avoid index errors when checking neighbors
    for idx in range(window_size, len(contour_points) - window_size):
        current_y = contour_points[idx][1]
        # Get y-values of all points in the surrounding window
        neighbor_ys = contour_points[idx-window_size:idx+window_size+1][:, 1]
        
        # Check if current point is the topmost (smallest y) in the window
        # Add a small buffer to ignore tiny contour fluctuations
        if current_y == np.min(neighbor_ys) and current_y < np.mean(neighbor_ys) - 2:
            local_peaks.append(tuple(contour_points[idx]))
    
    # Deduplicate nearby points (same head might have multiple adjacent peaks)
    filtered_heads = []
    for peak in local_peaks:
        keep_point = True
        for existing in filtered_heads:
            # Calculate Euclidean distance between points
            if np.linalg.norm(np.array(peak) - np.array(existing)) < distance_threshold:
                keep_point = False
                break
        if keep_point:
            filtered_heads.append(peak)
    
    return filtered_heads

# --- Example usage ---
# Assume you already have your contours loaded (replace with your code)
# img = cv2.imread("your_image.jpg", 0)
# _, binary_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
# contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

all_head_positions = []
for contour in contours:
    # Skip tiny contours that are definitely not people
    if cv2.contourArea(contour) < 1000:
        continue
    # Find head points for this contour
    heads = find_local_head_points(contour)
    all_head_positions.extend(heads)

# Final count of people
person_count = len(all_head_positions)
print(f"Total people detected: {person_count}")

# Optional: Visualize the results
# color_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# for point in all_head_positions:
#     cv2.circle(color_img, point, 6, (0, 0, 255), -1)
# cv2.imshow("Detected Heads", color_img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

关键参数调整说明

  • window_size: Controls the size of the neighborhood to check for local peaks. Larger values work better for smoother contours; adjust based on your image resolution.
  • distance_threshold: Filters out duplicate points from the same head. If your image is high-res, increase this value slightly.
  • contourArea filter: Weeds out noise contours that could generate false peaks—tweak the 1000 value based on how big people are in your images.

额外优化技巧

  • Preprocess your binary image with morphological operations (like cv2.morphologyEx) to clean up noise and smooth contours before extracting them.
  • If you’re dealing with complex occlusion, you can combine this method with a vertical projection of the binary image: find peaks in the projection to cross-verify your contour-based head counts.
  • For better accuracy, you can add a check that the local peak is within a reasonable x-range relative to the contour’s width (heads shouldn’t be wider than a certain percentage of the body contour).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:11:39