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

如何用OpenCV生成网格及药盒单元格的内部区域掩码?

Hey there! Let's work through your two mask-generation questions—they're actually pretty similar once you shift away from Hough Transform for the pill box task, which makes sense since Hough can be finicky with real-world camera noise and imperfect lines.

1. Mask for Internal Shapes in White-Line Grid Images

For general white-line grid images, the key is to isolate the grid lines, then extract the enclosed regions. Here's a step-by-step approach:

  • Preprocess the image
    First, convert to grayscale and use adaptive thresholding to handle uneven lighting (way more reliable than fixed thresholds):

    import cv2
    import numpy as np
    
    img = cv2.imread("grid_image.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Adaptive threshold to turn white lines into white foreground, dark background
    binary = cv2.adaptiveThreshold(
        gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
    )
    
  • Clean up the grid lines
    Use morphological operations to fix broken lines and remove small noise:

    # Create a rectangular structuring element
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    # Close operation fills gaps in lines; open operation removes tiny noise
    closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2)
    opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)
    
  • Extract internal region masks
    Find contours in the cleaned grid, then filter out the outer grid frame and fill the internal cells:

    contours, hierarchy = cv2.findContours(opened, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    mask = np.zeros_like(gray)
    
    # Filter contours to keep only internal cells (adjust area ranges for your image)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        # Skip the outer frame (too large) and tiny noise (too small)
        if 800 < area < (gray.shape[0] * gray.shape[1]) // 2:
            cv2.drawContours(mask, [cnt], -1, 255, thickness=cv2.FILLED)
    

    The mask variable now holds the filled internal regions of your grid.

2. Pill Box Cell Masks (Alternative to Hough Transform)

Hough Transform struggles with real-world camera images (noise, distorted lines, uneven lighting from your Raspberry Pi cam). Let's swap to a contour-based approach that's more robust:

  • Preprocess for camera images
    Add Gaussian blur to reduce camera noise before thresholding:

    # Capture image from Pi cam (or load from file)
    # img = pi_cam.capture()
    img = cv2.imread("pill_box.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    
    # Adaptive threshold to handle shadows/lighting changes
    binary = cv2.adaptiveThreshold(
        blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 4
    )
    
  • Isolate the pill box first
    Crop out the pill box from the background to eliminate distractions:

    # Find the largest contour (should be the pill box frame)
    contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    pill_box_contour = max(contours, key=cv2.contourArea)
    
    # Create a mask for the pill box and crop the ROI
    box_mask = np.zeros_like(gray)
    cv2.drawContours(box_mask, [pill_box_contour], -1, 255, cv2.FILLED)
    pill_box_roi = cv2.bitwise_and(gray, gray, mask=box_mask)
    
  • Extract individual cell masks
    Now find contours inside the pill box ROI, filtering for cells of similar size:

    # Re-threshold the ROI for cleaner cell lines
    _, roi_binary = cv2.threshold(pill_box_roi, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    cell_contours, _ = cv2.findContours(roi_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    cell_masks = []
    # Adjust area range to match your pill cells' actual size
    for cnt in cell_contours:
        area = cv2.contourArea(cnt)
        if 600 < area < 2200:
            cell_mask = np.zeros_like(pill_box_roi)
            cv2.drawContours(cell_mask, [cnt], -1, 255, cv2.FILLED)
            cell_masks.append(cell_mask)
    
  • Check for pills in each cell
    Use the masks to compare cell content against empty background (adjust the mean threshold based on your pill/box colors):

    for idx, cell_mask in enumerate(cell_masks):
        # Extract only the cell's pixels
        cell_pixels = cv2.bitwise_and(pill_box_roi, pill_box_roi, mask=cell_mask)
        # Calculate mean brightness of the cell
        mean_brightness = cv2.mean(cell_pixels, mask=cell_mask)[0]
        
        # Empty cells will be close to the box's background brightness; pills will differ
        if mean_brightness < 140:  # Tweak this value for your setup
            print(f"Cell {idx+1} has a pill!")
        else:
            print(f"Cell {idx+1} is empty.")
    

Pro Tip for Regular Pill Boxes

If your pill box is a perfect grid (e.g., 2x7), use perspective transformation first to straighten the box into a rectangle. Then you can split the image into equal-sized cells directly (no contour hunting needed)—this is super reliable if you can detect the box's four corner points.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:03:20