Search in sources :

Example 6 with Homography2D_F64

use of georegression.struct.homography.Homography2D_F64 in project BoofCV by lessthanoptimal.

the class ExampleImageStitching method renderStitching.

/**
 * Renders and displays the stitched together images
 */
public static void renderStitching(BufferedImage imageA, BufferedImage imageB, Homography2D_F64 fromAtoB) {
    // specify size of output image
    double scale = 0.5;
    // Convert into a BoofCV color format
    Planar<GrayF32> colorA = ConvertBufferedImage.convertFromPlanar(imageA, null, true, GrayF32.class);
    Planar<GrayF32> colorB = ConvertBufferedImage.convertFromPlanar(imageB, null, true, GrayF32.class);
    // Where the output images are rendered into
    Planar<GrayF32> work = colorA.createSameShape();
    // Adjust the transform so that the whole image can appear inside of it
    Homography2D_F64 fromAToWork = new Homography2D_F64(scale, 0, colorA.width / 4, 0, scale, colorA.height / 4, 0, 0, 1);
    Homography2D_F64 fromWorkToA = fromAToWork.invert(null);
    // Used to render the results onto an image
    PixelTransformHomography_F32 model = new PixelTransformHomography_F32();
    InterpolatePixelS<GrayF32> interp = FactoryInterpolation.bilinearPixelS(GrayF32.class, BorderType.ZERO);
    ImageDistort<Planar<GrayF32>, Planar<GrayF32>> distort = DistortSupport.createDistortPL(GrayF32.class, model, interp, false);
    distort.setRenderAll(false);
    // Render first image
    model.set(fromWorkToA);
    distort.apply(colorA, work);
    // Render second image
    Homography2D_F64 fromWorkToB = fromWorkToA.concat(fromAtoB, null);
    model.set(fromWorkToB);
    distort.apply(colorB, work);
    // Convert the rendered image into a BufferedImage
    BufferedImage output = new BufferedImage(work.width, work.height, imageA.getType());
    ConvertBufferedImage.convertTo(work, output, true);
    Graphics2D g2 = output.createGraphics();
    // draw lines around the distorted image to make it easier to see
    Homography2D_F64 fromBtoWork = fromWorkToB.invert(null);
    Point2D_I32[] corners = new Point2D_I32[4];
    corners[0] = renderPoint(0, 0, fromBtoWork);
    corners[1] = renderPoint(colorB.width, 0, fromBtoWork);
    corners[2] = renderPoint(colorB.width, colorB.height, fromBtoWork);
    corners[3] = renderPoint(0, colorB.height, fromBtoWork);
    g2.setColor(Color.ORANGE);
    g2.setStroke(new BasicStroke(4));
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.drawLine(corners[0].x, corners[0].y, corners[1].x, corners[1].y);
    g2.drawLine(corners[1].x, corners[1].y, corners[2].x, corners[2].y);
    g2.drawLine(corners[2].x, corners[2].y, corners[3].x, corners[3].y);
    g2.drawLine(corners[3].x, corners[3].y, corners[0].x, corners[0].y);
    ShowImages.showWindow(output, "Stitched Images", true);
}
Also used : PixelTransformHomography_F32(boofcv.alg.distort.PixelTransformHomography_F32) Homography2D_F64(georegression.struct.homography.Homography2D_F64) BufferedImage(java.awt.image.BufferedImage) ConvertBufferedImage(boofcv.io.image.ConvertBufferedImage) GrayF32(boofcv.struct.image.GrayF32) Planar(boofcv.struct.image.Planar) Point2D_I32(georegression.struct.point.Point2D_I32)

Example 7 with Homography2D_F64

use of georegression.struct.homography.Homography2D_F64 in project BoofCV by lessthanoptimal.

the class ExampleImageStitching method stitch.

/**
 * Given two input images create and display an image where the two have been overlayed on top of each other.
 */
public static <T extends ImageGray<T>> void stitch(BufferedImage imageA, BufferedImage imageB, Class<T> imageType) {
    T inputA = ConvertBufferedImage.convertFromSingle(imageA, null, imageType);
    T inputB = ConvertBufferedImage.convertFromSingle(imageB, null, imageType);
    // Detect using the standard SURF feature descriptor and describer
    DetectDescribePoint detDesc = FactoryDetectDescribe.surfStable(new ConfigFastHessian(1, 2, 200, 1, 9, 4, 4), null, null, imageType);
    ScoreAssociation<BrightFeature> scorer = FactoryAssociation.scoreEuclidean(BrightFeature.class, true);
    AssociateDescription<BrightFeature> associate = FactoryAssociation.greedy(scorer, 2, true);
    // fit the images using a homography.  This works well for rotations and distant objects.
    ModelMatcher<Homography2D_F64, AssociatedPair> modelMatcher = FactoryMultiViewRobust.homographyRansac(null, new ConfigRansac(60, 3));
    Homography2D_F64 H = computeTransform(inputA, inputB, detDesc, associate, modelMatcher);
    renderStitching(imageA, imageB, H);
}
Also used : DetectDescribePoint(boofcv.abst.feature.detdesc.DetectDescribePoint) AssociatedPair(boofcv.struct.geo.AssociatedPair) BrightFeature(boofcv.struct.feature.BrightFeature) ConfigFastHessian(boofcv.abst.feature.detect.interest.ConfigFastHessian) ConfigRansac(boofcv.factory.geo.ConfigRansac) Homography2D_F64(georegression.struct.homography.Homography2D_F64)

Example 8 with Homography2D_F64

use of georegression.struct.homography.Homography2D_F64 in project BoofCV by lessthanoptimal.

the class ExampleVideoMosaic method main.

public static void main(String[] args) {
    // Configure the feature detector
    ConfigGeneralDetector confDetector = new ConfigGeneralDetector();
    confDetector.threshold = 1;
    confDetector.maxFeatures = 300;
    confDetector.radius = 3;
    // Use a KLT tracker
    PointTracker<GrayF32> tracker = FactoryPointTracker.klt(new int[] { 1, 2, 4, 8 }, confDetector, 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(220, 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> stitch = FactoryMotion2D.createVideoStitch(0.5, motion2DColor, ImageType.pl(3, GrayF32.class));
    // Load an image sequence
    MediaManager media = DefaultMediaManager.INSTANCE;
    String fileName = UtilIO.pathExample("mosaic/airplane01.mjpeg");
    SimpleImageSequence<Planar<GrayF32>> video = media.openVideo(fileName, ImageType.pl(3, GrayF32.class));
    Planar<GrayF32> frame = video.next();
    // shrink the input image and center it
    Homography2D_F64 shrink = new Homography2D_F64(0.5, 0, frame.width / 4, 0, 0.5, frame.height / 4, 0, 0, 1);
    shrink = shrink.invert(null);
    // The mosaic will be larger in terms of pixels but the image will be scaled down.
    // To change this into stabilization just make it the same size as the input with no shrink.
    stitch.configure(frame.width, frame.height, shrink);
    // process the first frame
    stitch.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.setPreferredSize(new Dimension(3 * frame.width, frame.height * 2));
    ShowImages.showWindow(gui, "Example Mosaic", true);
    boolean enlarged = false;
    // process the video sequence one frame at a time
    while (video.hasNext()) {
        frame = video.next();
        if (!stitch.process(frame))
            throw new RuntimeException("You should handle failures");
        // if the current image is close to the image border recenter the mosaic
        StitchingFromMotion2D.Corners corners = stitch.getImageCorners(frame.width, frame.height, null);
        if (nearBorder(corners.p0, stitch) || nearBorder(corners.p1, stitch) || nearBorder(corners.p2, stitch) || nearBorder(corners.p3, stitch)) {
            stitch.setOriginToCurrent();
            // only enlarge the image once
            if (!enlarged) {
                enlarged = true;
                // double the image size and shift it over to keep it centered
                int widthOld = stitch.getStitchedImage().width;
                int heightOld = stitch.getStitchedImage().height;
                int widthNew = widthOld * 2;
                int heightNew = heightOld * 2;
                int tranX = (widthNew - widthOld) / 2;
                int tranY = (heightNew - heightOld) / 2;
                Homography2D_F64 newToOldStitch = new Homography2D_F64(1, 0, -tranX, 0, 1, -tranY, 0, 0, 1);
                stitch.resizeStitchImage(widthNew, heightNew, newToOldStitch);
                gui.setImage(0, 1, new BufferedImage(widthNew, heightNew, BufferedImage.TYPE_INT_RGB));
            }
            corners = stitch.getImageCorners(frame.width, frame.height, null);
        }
        // display the mosaic
        ConvertBufferedImage.convertTo(frame, gui.getImage(0, 0), true);
        ConvertBufferedImage.convertTo(stitch.getStitchedImage(), gui.getImage(0, 1), true);
        // draw a red quadrilateral around the current frame in the mosaic
        Graphics2D g2 = gui.getImage(0, 1).createGraphics();
        g2.setColor(Color.RED);
        g2.drawLine((int) corners.p0.x, (int) corners.p0.y, (int) corners.p1.x, (int) corners.p1.y);
        g2.drawLine((int) corners.p1.x, (int) corners.p1.y, (int) corners.p2.x, (int) corners.p2.y);
        g2.drawLine((int) corners.p2.x, (int) corners.p2.y, (int) corners.p3.x, (int) corners.p3.y);
        g2.drawLine((int) corners.p3.x, (int) corners.p3.y, (int) corners.p0.x, (int) corners.p0.y);
        gui.repaint();
        // throttle the speed just in case it's on a fast computer
        BoofMiscOps.pause(50);
    }
}
Also used : StitchingFromMotion2D(boofcv.alg.sfm.d2.StitchingFromMotion2D) PlToGrayMotion2D(boofcv.abst.sfm.d2.PlToGrayMotion2D) ConfigGeneralDetector(boofcv.abst.feature.detect.interest.ConfigGeneralDetector) Homography2D_F64(georegression.struct.homography.Homography2D_F64) BufferedImage(java.awt.image.BufferedImage) ConvertBufferedImage(boofcv.io.image.ConvertBufferedImage) GrayF32(boofcv.struct.image.GrayF32) MediaManager(boofcv.io.MediaManager) DefaultMediaManager(boofcv.io.wrapper.DefaultMediaManager) Planar(boofcv.struct.image.Planar) ImageGridPanel(boofcv.gui.image.ImageGridPanel)

Example 9 with Homography2D_F64

use of georegression.struct.homography.Homography2D_F64 in project BoofCV by lessthanoptimal.

the class ExampleVideoStabilization method main.

public static void main(String[] args) {
    // Configure the feature detector
    ConfigGeneralDetector confDetector = new ConfigGeneralDetector();
    confDetector.threshold = 10;
    confDetector.maxFeatures = 300;
    confDetector.radius = 2;
    // Use a KLT tracker
    PointTracker<GrayF32> tracker = FactoryPointTracker.klt(new int[] { 1, 2, 4, 8 }, confDetector, 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);
    }
}
Also used : PlToGrayMotion2D(boofcv.abst.sfm.d2.PlToGrayMotion2D) ConfigGeneralDetector(boofcv.abst.feature.detect.interest.ConfigGeneralDetector) Homography2D_F64(georegression.struct.homography.Homography2D_F64) BufferedImage(java.awt.image.BufferedImage) ConvertBufferedImage(boofcv.io.image.ConvertBufferedImage) GrayF32(boofcv.struct.image.GrayF32) MediaManager(boofcv.io.MediaManager) DefaultMediaManager(boofcv.io.wrapper.DefaultMediaManager) Planar(boofcv.struct.image.Planar) ImageGridPanel(boofcv.gui.image.ImageGridPanel)

Example 10 with Homography2D_F64

use of georegression.struct.homography.Homography2D_F64 in project BoofCV by lessthanoptimal.

the class Stabilize2DPanel method drawFeatures.

@Override
protected void drawFeatures(float scale, Graphics2D g2) {
    int scaledInputWidth = (int) (scale * input.getWidth());
    drawFeatures(scale, 0, 0, allTracks, inliers, new Homography2D_F64(), g2);
    drawFeatures(scale, scaledInputWidth + outputBorder, 0, allTracks, inliers, currToWorld, g2);
}
Also used : Homography2D_F64(georegression.struct.homography.Homography2D_F64)

Aggregations

Homography2D_F64 (georegression.struct.homography.Homography2D_F64)18 Point2D_F64 (georegression.struct.point.Point2D_F64)5 GrayF32 (boofcv.struct.image.GrayF32)4 BufferedImage (java.awt.image.BufferedImage)4 ConfigGeneralDetector (boofcv.abst.feature.detect.interest.ConfigGeneralDetector)3 ImageGridPanel (boofcv.gui.image.ImageGridPanel)3 MediaManager (boofcv.io.MediaManager)3 ConvertBufferedImage (boofcv.io.image.ConvertBufferedImage)3 DefaultMediaManager (boofcv.io.wrapper.DefaultMediaManager)3 AssociatedPair (boofcv.struct.geo.AssociatedPair)3 Planar (boofcv.struct.image.Planar)3 ModelManagerHomography2D_F64 (georegression.fitting.homography.ModelManagerHomography2D_F64)3 Affine2D_F64 (georegression.struct.affine.Affine2D_F64)3 PlToGrayMotion2D (boofcv.abst.sfm.d2.PlToGrayMotion2D)2 PixelTransformAffine_F32 (boofcv.alg.distort.PixelTransformAffine_F32)2 PixelTransformHomography_F32 (boofcv.alg.distort.PixelTransformHomography_F32)2 DistanceHomographySq (boofcv.alg.geo.robust.DistanceHomographySq)2 GenerateHomographyLinear (boofcv.alg.geo.robust.GenerateHomographyLinear)2 PixelTransform2_F32 (boofcv.struct.distort.PixelTransform2_F32)2 Affine2D_F32 (georegression.struct.affine.Affine2D_F32)2