Example Tracker Mean Shift

From BoofCV
Jump to navigationJump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

BoofCV provides two mean-shift trackers, histogram and pixel likelihood, this example is for the second. It is demonstrated how to create a custom pixel likelihood fuction to track a color ball. Mean-shift performs a local search that attempts to maximize the similarity of the color in its kernel to the color in its model. It is a fairly robust and fast tracker. If you are lucky, it will sometimes even reaquire a track after it has been lost.

Example Code:

Concepts:

  • Object tracking
  • Color histogram
  • Mean-shift

Example Code

/**
 * Example of how to use the low level implementation of mean-shift to track a specific color provided by the user.
 * The weights of each pixel is computed by RgbLikelihood, see below, and track regions are rectangular. This
 * tracker works very well since the ball is almost uniformly blue. If the light varried then a HSV color
 * model might be better.
 *
 * @author Peter Abeles
 */
public class ExampleTrackerMeanShiftLikelihood {
	/**
	 * Very simple implementation of PixelLikelihood. Uses linear distance to compute how close
	 * a color is to the target color.
	 */
	public static class RgbLikelihood implements PixelLikelihood<Planar<GrayU8>> {
		int targetRed, targetGreen, targetBlue;
		float radius = 35;
		Planar<GrayU8> image;

		public RgbLikelihood( int targetRed, int targetGreen, int targetBlue ) {
			this.targetRed = targetRed;
			this.targetGreen = targetGreen;
			this.targetBlue = targetBlue;
		}

		@Override public void setImage( Planar<GrayU8> image ) { this.image = image; }

		@Override public boolean isInBounds( int x, int y ) { return image.isInBounds(x, y); }

		/**
		 * This function is used to learn the target's model from the select image region. Since the
		 * model is provided in the constructor it isn't needed or used.
		 */
		@Override
		public void createModel( RectangleLength2D_I32 target ) { throw new RuntimeException("Not supported"); }

		@Override
		public float compute( int x, int y ) {
			int pixelR = image.getBand(0).get(x, y);
			int pixelG = image.getBand(1).get(x, y);
			int pixelB = image.getBand(2).get(x, y);

			// distance along each color band
			float red = Math.max(0, 1.0f - Math.abs(targetRed - pixelR)/radius);
			float green = Math.max(0, 1.0f - Math.abs(targetGreen - pixelG)/radius);
			float blue = Math.max(0, 1.0f - Math.abs(targetBlue - pixelB)/radius);

			// multiply them all together
			return red*green*blue;
		}
	}

	public static void main( String[] args ) {
		MediaManager media = DefaultMediaManager.INSTANCE;
		String fileName = UtilIO.pathExample("tracking/balls_blue_red.mjpeg");
		RectangleLength2D_I32 location = new RectangleLength2D_I32(394, 247, 475 - 394, 325 - 247);

		ImageType<Planar<GrayU8>> imageType = ImageType.pl(3, GrayU8.class);

		SimpleImageSequence<Planar<GrayU8>> video = media.openVideo(fileName, imageType);

		// Return a higher likelihood for pixels close to this RGB color
		var likelihood = new RgbLikelihood(64, 71, 69);

		TrackerMeanShiftLikelihood<Planar<GrayU8>> tracker =
				new TrackerMeanShiftLikelihood<>(likelihood, 50, 0.1f);

		// specify the target's initial location and initialize with the first frame
		Planar<GrayU8> frame = video.next();
		// Note that the tracker will not automatically invoke RgbLikelihood.createModel() in its initialize function
		tracker.initialize(frame, location);

		// For displaying the results
		var gui = new TrackerObjectQuadPanel(null);
		gui.setPreferredSize(new Dimension(frame.getWidth(), frame.getHeight()));
		gui.setImageUI(video.getGuiImage());
		gui.setTarget(location, true);
		ShowImages.showWindow(gui, "Tracking Results", true);

		// Track the object across each video frame and display the results
		while (video.hasNext()) {
			frame = video.next();

			boolean visible = tracker.process(frame);

			gui.setImageUI(video.getGuiImage());
			gui.setTarget(tracker.getLocation(), visible);
			gui.repaint();

			BoofMiscOps.pause(20);
		}
	}
}