Opencv and ball tracking

Hello Race Fans,

It’s been a while since I’ve cobbled anything together in Processing. I’ve been practicing my golf swing and got the brilliant idea to make a shot tracer using opencv. Simple, right? Identify the ball and keep adding dots to the path? To make matters real complicated I asked Google’s AI to show me code to do this. It came up with code alright, but it didn’t work. I asked it why that code didn’t work and it got a little closer to functional.

I now have code that reads a .mov file, does something with the Hue to identify the ball as a contour and then adds a path. I added sliders to adjust min and max Hue, but all it does is add a bunch of red lines(PVectors) everywhere except on the ball.

Here’s a screenshot of the gibberish it produces:

And here’s the code:

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;

import gab.opencv.*;
import processing.video.*;
import controlP5.*;
import java.awt.Rectangle;

Movie video;
OpenCV opencv;
ControlP5 cp5;

// HSV Threshold variables (linked to sliders)
int minH = 0, maxH = 179;
int minS = 0, maxS = 30; // Low saturation for white
int minV = 200, maxV = 255; // High value/brightness for white

ArrayList<PVector> path = new ArrayList<PVector>();
//Mat hsv;
//Mat mask;

void setup() {
  size(1466, 412); // Double width to show both views
  video = new Movie(this, "IMG_0339.MOV");
  video.loop();
 // hsv = new Mat();
 // mask = new Mat();
  opencv = new OpenCV(this, 733, 412);
  cp5 = new ControlP5(this);

  // Add Sliders for real-time tuning
  int y = 20;
  cp5.addSlider("minH").setPosition(20, y).setRange(0, 179);
  cp5.addSlider("maxH").setPosition(20, y+=20).setRange(0, 179);
  cp5.addSlider("minS").setPosition(20, y+=20).setRange(0, 255);
  cp5.addSlider("maxS").setPosition(20, y+=20).setRange(0, 255);
  cp5.addSlider("minV").setPosition(20, y+=20).setRange(0, 255);
  cp5.addSlider("maxV").setPosition(20, y+=20).setRange(0, 255);
}

void draw() {
  if (video.available()) {
    video.read();
    image(video,0,0);
    opencv.loadImage(video);
   // opencv.toCV(hsv);
    
    // 1. Convert to HSV and Threshold
    opencv.useColor(HSB);
   // opencv.threshold(220);
   // opencv.convert(HSB);
    opencv.setGray(opencv.getH());
   // opencv.threshold(200);
//  Scalar min = new Scalar(0, 100, 100); 
//  Scalar max = new Scalar(50, 255, 255);
  
  // Correct method: takes Scalar objects [6]
  opencv.inRange(minH, maxH);
 //   Core.inRange(hsv, min, max, mask);
   // opencv.inRange(0,255);
    
    // 2. Capture the binary mask for display
    PImage maskImage = opencv.getSnapshot();
    
    // 3. Track the ball (finding the largest white contour)
    ArrayList<Contour> contours = opencv.findContours();
    
        // 3. Find the LARGEST contour instead of just the first one
    Contour ball = null;
    double maxArea = 0;
    for (Contour c : contours) {
        if (c.area() > maxArea) {
            maxArea = c.area();
            ball = c;
        }
    }

    if (ball != null) {
      Rectangle r = ball.getBoundingBox();
      // Adjust size check based on your video resolution
      if (r.width < 100 && r.height < 100) { 
        path.add(new PVector(r.x + r.width/2, r.y + r.height/2));
      }
    }
    
 /*   if (contours.size() > 0) {
      Contour ball = contours.get(0); // Assumes ball is the most prominent object
      Rectangle r = ball.getBoundingBox();
      // Only add point if it meets a reasonable size for a golf ball
     // if (r.width < 50 && r.height < 50) { 
        if (r.width < 100 && r.height < 100) {
        path.add(new PVector(r.x + r.width/2, r.y + r.height/2));
      }
    } */
    
    // 4. Visual Output
    image(video, 0, 0, 733, 412);       // Left: Original Video
    image(maskImage, 733, 0, 733, 412); // Right: What OpenCV sees
    image(video, 0, 0, 733, 412);       // Left: Original Video
    image(maskImage, 733, 0, 733, 412); // Right: What OpenCV sees
    
    // Draw the tracer line on the original video
    drawTracer();
  }
}

void drawTracer() {
  noFill();
  stroke(255, 0, 0); // Red tracer line
  strokeWeight(3);
  beginShape();
  for (PVector p : path) {
    vertex(p.x, p.y);
  }
  endShape();
}


I don’t know why the code is not formatted properly for this forum. I’ll fix it if I can.

Anyway, any suggestions on getting this to actually track a little white ball are appreciated.