001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.demos.video;
031
032import java.io.File;
033import java.io.IOException;
034import java.util.ArrayList;
035import java.util.List;
036
037import org.openimaj.image.DisplayUtilities;
038import org.openimaj.image.MBFImage;
039import org.openimaj.image.processing.transform.MBFProjectionProcessor;
040import org.openimaj.image.processing.transform.ProjectionProcessor;
041import org.openimaj.image.renderer.MBFImageRenderer;
042import org.openimaj.math.geometry.point.Point2d;
043import org.openimaj.math.geometry.point.Point2dImpl;
044import org.openimaj.math.geometry.shape.Polygon;
045import org.openimaj.math.geometry.shape.Rectangle;
046import org.openimaj.math.geometry.transforms.TransformUtilities;
047import org.openimaj.util.pair.IndependentPair;
048import org.openimaj.video.VideoDisplay;
049import org.openimaj.video.VideoDisplayListener;
050import org.openimaj.video.capture.VideoCapture;
051import org.openimaj.video.xuggle.XuggleVideo;
052
053import Jama.Matrix;
054
055public class VideoWithinVideo implements VideoDisplayListener<MBFImage> {
056        public File videoFile;
057        public XuggleVideo video;
058        public VideoCapture capture;
059        public VideoDisplay<MBFImage> display;
060        public Polygon targetArea;
061        public MBFImageRenderer renderer;
062        public List<IndependentPair<Point2d, Point2d>> pointList;
063        public Point2dImpl topLeftS = new Point2dImpl(), topLeftB = new Point2dImpl();
064        public Point2dImpl topRightS = new Point2dImpl(), topRightB = new Point2dImpl();
065        public Point2dImpl bottomLeftS = new Point2dImpl(), bottomLeftB = new Point2dImpl();
066        public Point2dImpl bottomRightS = new Point2dImpl(), bottomRightB = new Point2dImpl();
067        public Matrix captureToVideo;
068        public Rectangle videoRect;
069        private MBFImage nextCaptureFrame;
070
071        public VideoWithinVideo(String videoPath) throws IOException {
072                this.videoFile = new File(videoPath);
073                this.video = new XuggleVideo(videoFile, true);
074                this.capture = new VideoCapture(320, 240);
075                nextCaptureFrame = capture.getNextFrame().clone();
076
077                this.videoRect = new Rectangle(0, 0, video.getWidth(), video.getHeight());
078                this.captureToVideo = TransformUtilities.makeTransform(
079                                new Rectangle(0, 0, capture.getWidth(), capture.getHeight()),
080                                videoRect
081                                );
082
083                display = VideoDisplay.createVideoDisplay(video);
084                new CaptureVideoSIFT(this);
085                display.addVideoListener(this);
086
087                // targetArea = new Polygon(
088                // new Point2dImpl(100,100),
089                // new Point2dImpl(200,150),
090                // new Point2dImpl(200,230),
091                // new Point2dImpl(0,200)
092                // );
093                //
094
095                // Prepare the homography matrix
096                pointList = new ArrayList<IndependentPair<Point2d, Point2d>>();
097                pointList.add(IndependentPair.pair((Point2d) topLeftB, (Point2d) topLeftS));
098                pointList.add(IndependentPair.pair((Point2d) topRightB, (Point2d) topRightS));
099                pointList.add(IndependentPair.pair((Point2d) bottomRightB, (Point2d) bottomRightS));
100                pointList.add(IndependentPair.pair((Point2d) bottomLeftB, (Point2d) bottomLeftS));
101
102        }
103
104        @Override
105        public void afterUpdate(VideoDisplay<MBFImage> display) {
106        }
107
108        @Override
109        public void beforeUpdate(MBFImage frame) {
110                DisplayUtilities.displayName(frame, "video");
111                if (renderer == null) {
112                        this.renderer = frame.createRenderer();
113
114                }
115                // this.renderer.drawShapeFilled(targetArea, RGBColour.RED);
116                updatePolygon();
117                final ProjectionProcessor<Float[], MBFImage> proc = new MBFProjectionProcessor();
118                proc.setMatrix(captureToVideo);
119
120                proc.accumulate(nextCaptureFrame);
121                if (this.targetArea != null) {
122                        final Matrix transform = TransformUtilities.homographyMatrixNorm(pointList);
123                        proc.setMatrix(transform);
124                        proc.accumulate(frame.clone());
125                }
126                synchronized (this) {
127                        proc.performProjection(0, 0, frame);
128                }
129        }
130
131        public void updatePolygon() {
132                if (this.targetArea != null) {
133                        final Point2dImpl stl = (Point2dImpl) targetArea.points.get(0);
134                        final Point2dImpl str = (Point2dImpl) targetArea.points.get(1);
135                        final Point2dImpl sbr = (Point2dImpl) targetArea.points.get(2);
136                        final Point2dImpl sbl = (Point2dImpl) targetArea.points.get(3);
137                        this.topLeftS.x = stl.x;
138                        this.topLeftS.y = stl.y; // top left small rectangle
139                        this.topRightS.x = str.x;
140                        this.topRightS.y = str.y; // top right small rectangle
141                        this.bottomRightS.x = sbr.x;
142                        this.bottomRightS.y = sbr.y; // bottom right small rectangle
143                        this.bottomLeftS.x = sbl.x;
144                        this.bottomLeftS.y = sbl.y; // bottom right small rectangle
145                }
146
147                this.topLeftB.x = videoRect.x;
148                this.topLeftB.y = videoRect.y; // top left big rectangle
149                this.topRightB.x = videoRect.x + videoRect.width;
150                this.topRightB.y = videoRect.y; // top right big rectangle
151                this.bottomRightB.x = videoRect.x + videoRect.width;
152                this.bottomRightB.y = videoRect.y + videoRect.height; // bottom right
153                                                                                                                                // big rectangle
154                this.bottomLeftB.x = videoRect.x;
155                this.bottomLeftB.y = videoRect.y + videoRect.height; // bottom right big
156                                                                                                                                // rectangle
157        }
158
159        public static void main(String[] args) throws IOException {
160                new VideoWithinVideo("/Users/jsh2/Movies/Screen Recording.mov");
161        }
162
163        public synchronized void copyToCaptureFrame(MBFImage frameWrite) {
164                this.nextCaptureFrame.internalCopy(frameWrite);
165        }
166}