00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Raster/Raster.H"
00039 #include "SIFT/Keypoint.H"
00040 #include "SIFT/VisualObject.H"
00041 #include "SIFT/VisualObjectMatch.H"
00042 #include "Image/ImageSet.H"
00043 #include "Util/Timer.H"
00044 #include <iostream>
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 int main(const int argc, const char **argv)
00055 {
00056 MYLOGVERB = LOG_DEBUG;
00057
00058
00059 if (argc < 4)
00060 LFATAL("USAGE: app-SIFT-panorama <result.png> "
00061 "<image1.png> ... <imageN.png>");
00062
00063
00064 ImageSet< PixRGB<byte> > images;
00065
00066 const char *nam1 = argv[2];
00067 Image< PixRGB<byte> > im1 = Raster::ReadRGB(nam1);
00068 images.push_back(im1);
00069 rutz::shared_ptr<VisualObject> vo1(new VisualObject(nam1, "", im1));
00070 std::vector<SIFTaffine> affines;
00071 SIFTaffine comboaff;
00072 affines.push_back(comboaff);
00073 int minx = 0, miny = 0, maxx = im1.getWidth()-1, maxy = im1.getHeight()-1;
00074
00075 for (int i = 3; i < argc; i ++)
00076 {
00077 const char *nam2 = argv[i];
00078 Image< PixRGB<byte> > im2 = Raster::ReadRGB(nam2);
00079 images.push_back(im2);
00080 rutz::shared_ptr<VisualObject> vo2(new VisualObject(nam2, "", im2));
00081
00082
00083 Timer tim(1000000);
00084 VisualObjectMatch match(vo1, vo2, VOMA_SIMPLE);
00085 uint64 t = tim.get();
00086
00087 LINFO("Found %u matches between %s and %s in %.3fms",
00088 match.size(), nam1, nam2, float(t) * 0.001F);
00089
00090
00091 uint np = match.prune();
00092 LINFO("Pruned %u outlier matches.", np);
00093
00094
00095 SIFTaffine aff = match.getSIFTaffine();
00096 std::cerr<<aff;
00097
00098
00099 comboaff = comboaff.compose(aff);
00100 affines.push_back(comboaff);
00101
00102
00103
00104
00105 if (comboaff.isInversible() == false) LFATAL("Oooops, singular affine!");
00106 SIFTaffine iaff = comboaff.inverse();
00107 const float ww = float(im2.getWidth() - 1);
00108 const float hh = float(im2.getHeight() - 1);
00109 float xx, yy; int x, y;
00110
00111 iaff.transform(0.0F, 0.0F, xx, yy); x = int(xx+0.5F); y = int(yy+0.5F);
00112 if (x < minx) minx = x; if (x > maxx) maxx = x;
00113 if (y < miny) miny = y; if (y > maxy) maxy = y;
00114
00115 iaff.transform(ww, 0.0F, xx, yy); x = int(xx+0.5F); y = int(yy+0.5F);
00116 if (x < minx) minx = x; if (x > maxx) maxx = x;
00117 if (y < miny) miny = y; if (y > maxy) maxy = y;
00118
00119 iaff.transform(0.0F, hh, xx, yy); x = int(xx+0.5F); y = int(yy+0.5F);
00120 if (x < minx) minx = x; if (x > maxx) maxx = x;
00121 if (y < miny) miny = y; if (y > maxy) maxy = y;
00122
00123 iaff.transform(ww, hh, xx, yy); x = int(xx+0.5F); y = int(yy+0.5F);
00124 if (x < minx) minx = x; if (x > maxx) maxx = x;
00125 if (y < miny) miny = y; if (y > maxy) maxy = y;
00126
00127
00128 im1 = im2; vo1 = vo2; nam1 = nam2;
00129 }
00130
00131
00132 LINFO("x = [%d .. %d], y = [%d .. %d]", minx, maxx, miny, maxy);
00133 const int w = maxx - minx + 1, h = maxy - miny + 1;
00134 LINFO("Allocating %dx%d panorama...", w, h);
00135 if (w < 2 || h < 2) LFATAL("Oooops, panorama too small!");
00136 Image< PixRGB<byte> > pano(w, h, ZEROS);
00137 Image< PixRGB<byte> >::iterator p = pano.beginw();
00138
00139
00140
00141
00142 for (int j = 0; j < h; j ++)
00143 for (int i = 0; i < w; i ++)
00144 {
00145
00146
00147
00148 PixRGB<int> val(0); uint n = 0U;
00149
00150 for (uint k = 0; k < images.size(); k ++)
00151 {
00152
00153 float u, v;
00154 affines[k].transform(float(i + minx), float(j + miny), u, v);
00155
00156
00157 if (images[k].coordsOk(u, v))
00158 {
00159 val += PixRGB<int>(images[k].getValInterp(u, v));
00160 ++ n;
00161 }
00162 }
00163
00164 if (n > 0) *p = PixRGB<byte>(val / n);
00165
00166 ++ p;
00167 }
00168
00169
00170 Raster::WriteRGB(pano, std::string(argv[1]));
00171 LINFO("Done.");
00172
00173 return 0;
00174 }