Example Video Stabilization

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.

Video stabilization attempts to overlay more recent images on top of a keyframe. This makes it easier to identify objects which are moving relative to the background.

Example File: ExampleVideoStabilization.java

Concepts:

  • Image Stitching
  • Image Stabilization
  • 2D image motion

Related Examples:

Example Code

/**
 * Example of how to stabilizing a video sequence using StitchingFromMotion2D. Video stabilization is almost
 * the same as creating a video mosaic and the code in this example is a tweaked version of the mosaic example.
 * The differences are that the output size is the same as the input image size and that the origin is never changed.
 *
 * @author Peter Abeles
 */
public class ExampleVideoStabilization {
	public static void main( String[] args ) {
		// Configure the feature detector
		ConfigPointDetector configDetector = new ConfigPointDetector();
		configDetector.type = PointDetectorTypes.SHI_TOMASI;
		configDetector.general.maxFeatures = 300;
		configDetector.general.threshold = 10;
		configDetector.general.radius = 2;

		// Use a KLT tracker
		PointTracker<GrayF32> tracker = FactoryPointTracker.klt(4, configDetector, 3,
				GrayF32.class, GrayF32.class);

		// This estimates the 2D image motion
		// An Affine2D_F64 model also works quite well.
		ImageMotion2D<GrayF32, Homography2D_F64> motion2D =
				FactoryMotion2D.createMotion2D(200, 3, 2, 30, 0.6, 0.5, false, tracker, new Homography2D_F64());

		// wrap it so it output color images while estimating motion from gray
		ImageMotion2D<Planar<GrayF32>, Homography2D_F64> motion2DColor =
				new PlToGrayMotion2D<>(motion2D, GrayF32.class);

		// This fuses the images together
		StitchingFromMotion2D<Planar<GrayF32>, Homography2D_F64>
				stabilize = FactoryMotion2D.createVideoStitch(0.5, motion2DColor, ImageType.pl(3, GrayF32.class));

		// Load an image sequence
		MediaManager media = DefaultMediaManager.INSTANCE;
		String fileName = UtilIO.pathExample("shake.mjpeg");
		SimpleImageSequence<Planar<GrayF32>> video =
				media.openVideo(fileName, ImageType.pl(3, GrayF32.class));

		Planar<GrayF32> frame = video.next();

		// The output image size is the same as the input image size
		stabilize.configure(frame.width, frame.height, null);
		// process the first frame
		stabilize.process(frame);

		// Create the GUI for displaying the results + input image
		ImageGridPanel gui = new ImageGridPanel(1, 2);
		gui.setImage(0, 0, new BufferedImage(frame.width, frame.height, BufferedImage.TYPE_INT_RGB));
		gui.setImage(0, 1, new BufferedImage(frame.width, frame.height, BufferedImage.TYPE_INT_RGB));
		gui.autoSetPreferredSize();

		ShowImages.showWindow(gui, "Example Stabilization", true);

		// process the video sequence one frame at a time
		while (video.hasNext()) {
			if (!stabilize.process(video.next()))
				throw new RuntimeException("Don't forget to handle failures!");

			// display the stabilized image
			ConvertBufferedImage.convertTo(frame, gui.getImage(0, 0), true);
			ConvertBufferedImage.convertTo(stabilize.getStitchedImage(), gui.getImage(0, 1), true);

			gui.repaint();

			// throttle the speed just in case it's on a fast computer
			BoofMiscOps.pause(50);
		}
	}
}