You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用OpenCV Python估算图像中特定颜色/结构的占比?

Calculating Colored Structure Percentage with OpenCV (Red Eye Vessel Example)

Absolutely, there's a practical, step-by-step workflow to estimate the percentage of a specific colored structure in an image using OpenCV. Let's walk through this using your red eye vessel detection use case—since you've already tried masks and transforms, we'll refine those techniques to get better results.


Step 1: Preprocess the Image to Reduce Noise

First, smooth the image to eliminate small noise that can throw off your mask. Gaussian blur is ideal here because it preserves edges while reducing high-frequency noise:

import cv2
import numpy as np

# Load your image (OpenCV reads in BGR by default)
img = cv2.imread("red_eye_image.jpg")
# Apply Gaussian blur
blurred = cv2.GaussianBlur(img, (5, 5), 0)

Step 2: Switch to a Color Space Optimized for Color Detection

RGB isn't the best for isolating specific colors because it mixes brightness and color information. Instead, use HSV (Hue-Saturation-Value)—the hue channel directly represents color, making it easier to target red.

Red has two hue ranges in HSV: ~0-10 and ~170-180 (since hue wraps around the color wheel). Define your lower and upper bounds for red:

# Convert to HSV
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# Define red color ranges (adjust these based on your specific image!)
lower_red1 = np.array([0, 50, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 50, 50])
upper_red2 = np.array([180, 255, 255])

# Combine the two masks to capture all red areas
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = cv2.bitwise_or(mask1, mask2)

Step 3: Refine the Mask with Morphological Operations

Your initial mask might have small noise spots or tiny gaps in the vessel structures. Use morphological operations to clean this up:

  • Opening (erosion followed by dilation): Removes small white noise spots
  • Closing (dilation followed by erosion): Fills small gaps in the vessel regions
# Create a kernel for morphological operations (adjust size based on noise)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))

# Apply opening to remove noise
mask_cleaned = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
# Apply closing to fill gaps
mask_cleaned = cv2.morphologyEx(mask_cleaned, cv2.MORPH_CLOSE, kernel, iterations=1)

Step 4: Calculate the Percentage of Vessel Pixels

Now count the number of white pixels (vessels) in the mask and divide by the total number of pixels in the original image:

# Count non-zero (white) pixels in the mask
vessel_pixels = cv2.countNonZero(mask_cleaned)
# Total pixels in the image
total_pixels = img.shape[0] * img.shape[1]
# Calculate percentage
vessel_percentage = (vessel_pixels / total_pixels) * 100

print(f"Vessel percentage: {vessel_percentage:.2f}%")

Pro Tips for Better Results

  • Adjust Color Thresholds: Use cv2.imshow() to test different HSV bounds—you can even create a trackbar to tweak values in real-time for precise targeting.
  • Enhance Contrast with CLAHE: If your image has low contrast (common in medical images like red eye shots), apply CLAHE to the luminance channel before processing:
    # Convert to LAB color space
    lab = cv2.cvtColor(blurred, cv2.COLOR_BGR2LAB)
    l, a, b = cv2.split(lab)
    # Apply CLAHE to the L channel
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
    l_clahe = clahe.apply(l)
    # Merge back and convert to HSV
    lab_clahe = cv2.merge((l_clahe, a, b))
    hsv = cv2.cvtColor(lab_clahe, cv2.COLOR_LAB2HSV)
    
  • Filter Contours: If other red regions (like the red pupil) are being included, use contour detection to filter out areas that are too large or small:
    contours, _ = cv2.findContours(mask_cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # Create an empty mask to draw valid contours
    filtered_mask = np.zeros_like(mask_cleaned)
    # Only keep contours within a specific area range (adjust based on your vessel size)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if 10 < area < 500:  # Example bounds—tweak for your image
            cv2.drawContours(filtered_mask, [cnt], -1, 255, thickness=cv2.FILLED)
    # Use filtered_mask for percentage calculation instead
    

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

火山引擎 最新活动