冰壶投掷后壶体中心坐标提取技术需求(R/Python)
Alright, let's figure out how to get those accurate curling stone coordinates saved to CSV. Since you're having trouble with R, I'll cover both a refined R approach to fix your current setup and a straightforward Python solution that’s perfect for this computer vision task.
Refined R Solution Using magick and opencv
Your poor detection results are almost certainly from relying on naive RGB color picking or not filtering out tiny noise objects. Switching to the HSV color space (way more stable for color detection) and adding contour filtering will fix this.
Step 1: Install Required Packages
First, make sure you have these tools installed:
install.packages(c("magick", "opencv", "dplyr"))
Step 2: Full Implementation Code
library(magick) library(opencv) library(dplyr) # Load your curling frame image img <- image_read("curling_frame.jpg") # Convert image to a matrix compatible with OpenCV img_mat <- image_data(img, "rgba") %>% as.integer() %>% drop() %>% aperm(c(2,3,1)) # Switch to HSV color space (better for consistent color detection) hsv_img <- cv_cvtColor(img_mat, COLOR_BGR2HSV) # Define HSV ranges for red (note red has two separate ranges) and yellow lower_red1 <- c(0, 120, 70) upper_red1 <- c(10, 255, 255) lower_red2 <- c(170, 120, 70) upper_red2 <- c(180, 255, 255) lower_yellow <- c(20, 100, 100) upper_yellow <- c(30, 255, 255) # Create color masks and combine them mask_red1 <- cv_inRange(hsv_img, lower_red1, upper_red1) mask_red2 <- cv_inRange(hsv_img, lower_red2, upper_red2) mask_red <- cv_bitwise_or(mask_red1, mask_red2) mask_yellow <- cv_inRange(hsv_img, lower_yellow, upper_yellow) mask_combined <- cv_bitwise_or(mask_red, mask_yellow) # Clean up the mask to remove small noise (tiny dots/circles) kernel <- cv_getStructuringElement(MORPH_ELLIPSE, c(5,5)) mask_clean <- cv_morphologyEx(mask_combined, MORPH_OPEN, kernel) mask_clean <- cv_morphologyEx(mask_clean, MORPH_CLOSE, kernel) # Detect contours and filter out small objects (exclude top/bottom tiny circles) contours <- cv_findContours(mask_clean, mode = RETR_EXTERNAL, method = CHAIN_APPROX_SIMPLE) # Adjust min_area based on your image resolution (small circles will be way smaller than stones) min_area <- 500 valid_contours <- Filter(function(c) cv_contourArea(c) > min_area, contours) # Calculate center coordinates for each valid stone stone_centers <- lapply(valid_contours, function(c) { moments <- cv_moments(c) x <- moments$m10 / moments$m00 y <- moments$m01 / moments$m00 data.frame(x = round(x, 2), y = round(y, 2)) }) %>% bind_rows() # Save results to CSV write.csv(stone_centers, "curling_stone_coordinates.csv", row.names = FALSE)
Python Solution with OpenCV & Pandas
If you’re open to switching, Python’s OpenCV ecosystem is super mature for this kind of task. This implementation is robust and easy to tweak.
Step 1: Install Dependencies
pip install opencv-python pandas numpy
Step 2: Full Implementation Code
import cv2 import numpy as np import pandas as pd # Load your curling frame image img = cv2.imread("curling_frame.jpg") # Convert to HSV color space hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Define HSV ranges for red and yellow lower_red1 = np.array([0, 120, 70]) upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([170, 120, 70]) upper_red2 = np.array([180, 255, 255]) lower_yellow = np.array([20, 100, 100]) upper_yellow = np.array([30, 255, 255]) # Create and combine color masks mask_red1 = cv2.inRange(hsv_img, lower_red1, upper_red1) mask_red2 = cv2.inRange(hsv_img, lower_red2, upper_red2) mask_red = cv2.bitwise_or(mask_red1, mask_red2) mask_yellow = cv2.inRange(hsv_img, lower_yellow, upper_yellow) mask_combined = cv2.bitwise_or(mask_red, mask_yellow) # Clean mask to eliminate small noise kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) mask_clean = cv2.morphologyEx(mask_combined, cv2.MORPH_OPEN, kernel) mask_clean = cv2.morphologyEx(mask_clean, cv2.MORPH_CLOSE, kernel) # Detect contours and filter out tiny objects contours, _ = cv2.findContours(mask_clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) min_area = 500 # Adjust this based on your image's scale valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area] # Calculate center coordinates for each stone stone_centers = [] for cnt in valid_contours: M = cv2.moments(cnt) if M["m00"] != 0: # Avoid division by zero (edge case) cx = int(M["m10"] / M["m00"]) cy = int(M["m01"] / M["m00"]) stone_centers.append({"x": cx, "y": cy}) # Save to CSV df = pd.DataFrame(stone_centers) df.to_csv("curling_stone_coordinates.csv", index=False)
Quick Tips for Fine-Tuning
- Adjust
min_area: This is the most important parameter. Check the pixel area of the tiny top/bottom circles vs actual stones in your images, then setmin_areato a value between the two. - Tweak HSV Ranges: If color detection is off, use an HSV color picker tool to get exact ranges for your specific footage (lighting can change how colors appear).
- Coordinate System Note: In both R and OpenCV, the origin (0,0) is the top-left corner, so y-values increase as you go down the image.
内容的提问来源于stack exchange,提问作者sydg

