1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.openimaj.demos.image;
31
32 import java.io.File;
33 import java.io.IOException;
34
35 import javax.swing.JFrame;
36 import javax.swing.JLabel;
37
38 import org.openimaj.demos.Demo;
39 import org.openimaj.feature.local.list.LocalFeatureList;
40 import org.openimaj.feature.local.matcher.FastBasicKeypointMatcher;
41 import org.openimaj.feature.local.matcher.consistent.ConsistentLocalFeatureMatcher2d;
42 import org.openimaj.image.DisplayUtilities;
43 import org.openimaj.image.FImage;
44 import org.openimaj.image.ImageUtilities;
45 import org.openimaj.image.MBFImage;
46 import org.openimaj.image.colour.Transforms;
47 import org.openimaj.image.feature.local.engine.DoGSIFTEngine;
48 import org.openimaj.image.feature.local.keypoints.Keypoint;
49 import org.openimaj.image.processing.resize.ResizeProcessor;
50 import org.openimaj.image.processing.transform.ProjectionProcessor;
51 import org.openimaj.math.geometry.point.Point2d;
52 import org.openimaj.math.geometry.transforms.HomographyModel;
53 import org.openimaj.math.geometry.transforms.residuals.SingleImageTransferResidual2d;
54 import org.openimaj.math.model.fit.RANSAC;
55
56
57
58
59
60
61
62
63
64 @Demo(
65 author = "Sina Samangooei",
66 description = "Demonstrates using the SIFT keypoint matching and automatic "
67 + "homography transform calculation to project 3 photos into a basic stitched "
68 + "panorama.",
69 keywords = { "image", "photo", "mosaic", "stitch", "panorama" },
70 title = "Simple Photo Mosaic",
71 icon = "/org/openimaj/demos/icons/image/mosaic-icon.png",
72 screenshot = "/org/openimaj/demos/screens/image/mosaic-screen.png",
73 vmArguments = "-Xmx1G")
74 public class SimpleMosaic
75 {
76
77
78
79
80
81
82
83 public static void main(String args[]) throws IOException
84 {
85 final JLabel l = new JLabel();
86 l.setHorizontalAlignment(JLabel.CENTER);
87 final JFrame f = new JFrame("Mosaic Progress");
88 f.getContentPane().add(l);
89 f.setSize(500, 80);
90 f.setVisible(true);
91
92 new Thread(new Runnable()
93 {
94 @Override
95 public void run()
96 {
97 try
98 {
99
100 l.setText("Setting up processors");
101 final ResizeProcessor rp = new ResizeProcessor(800, 600);
102 final DoGSIFTEngine engine = new DoGSIFTEngine();
103
104 final ConsistentLocalFeatureMatcher2d<Keypoint> matcher =
105 new ConsistentLocalFeatureMatcher2d<Keypoint>(
106 new FastBasicKeypointMatcher<Keypoint>(8));
107 final HomographyModel model = new HomographyModel();
108 final RANSAC<Point2d, Point2d, HomographyModel> modelFitting = new RANSAC<Point2d, Point2d, HomographyModel>(
109 model, new SingleImageTransferResidual2d<HomographyModel>(), 8.0, 1600,
110 new RANSAC.BestFitStoppingCondition(),
111 true);
112 matcher.setFittingModel(modelFitting);
113
114
115
116 final MBFImage imageMiddle = ImageUtilities.readMBF(SimpleMosaic.class
117 .getResource("/org/openimaj/demos/image/mosaic/trento-view-1.jpg"));
118 imageMiddle.processInplace(rp);
119 final FImage workingImageMiddle = Transforms.calculateIntensityNTSC(imageMiddle);
120 l.setText("Calculating features on middle image");
121 final LocalFeatureList<Keypoint> middleKP = engine.findFeatures(workingImageMiddle);
122 matcher.setModelFeatures(middleKP);
123
124
125 final ProjectionProcessor<Float[], MBFImage> ptp =
126 new ProjectionProcessor<Float[], MBFImage>();
127 imageMiddle.accumulateWith(ptp);
128
129
130 final MBFImage imageRight = ImageUtilities.readMBF(SimpleMosaic.class
131 .getResource("/org/openimaj/demos/image/mosaic/trento-view-0.jpg"));
132 imageRight.processInplace(rp);
133 final FImage workingImageRight = Transforms.calculateIntensityNTSC(imageRight);
134 l.setText("Calculating features on right image");
135 final LocalFeatureList<Keypoint> rightKP = engine.findFeatures(workingImageRight);
136
137
138 l.setText("Finding matches with middle image and right image");
139 matcher.findMatches(rightKP);
140 ptp.setMatrix(model.getTransform());
141 l.setText("Projecting right image");
142 imageRight.accumulateWith(ptp);
143
144
145 final MBFImage imageLeft = ImageUtilities.readMBF(SimpleMosaic.class
146 .getResource("/org/openimaj/demos/image/mosaic/trento-view-2.jpg"));
147 imageLeft.processInplace(rp);
148 final FImage workingImageLeft = Transforms.calculateIntensityNTSC(imageLeft);
149 l.setText("Calculating features on left image");
150 final LocalFeatureList<Keypoint> leftKP = engine.findFeatures(workingImageLeft);
151
152
153 l.setText("Finding matches with middle image and left image");
154 matcher.findMatches(leftKP);
155 ptp.setMatrix(model.getTransform());
156 l.setText("Projecting left image");
157 imageLeft.accumulateWith(ptp);
158
159 l.setText("Projecting final image");
160 final MBFImage projected = ptp.performBlendedProjection(
161 (-imageMiddle.getWidth()),
162 imageMiddle.getWidth() + imageMiddle.getWidth(),
163 -imageMiddle.getHeight() / 2, 3 * imageMiddle.getHeight() / 2,
164 (Float[]) null);
165
166
167 f.setVisible(false);
168 DisplayUtilities.display(projected.process(rp));
169
170
171 ImageUtilities.write(projected, "png", new File(
172 "/Users/jsh2/Desktop/mosaic.png"));
173 }
174 catch (final IOException e)
175 {
176 e.printStackTrace();
177 }
178 }
179 }).start();
180 }
181 }