Revision: 2914
http://hugin.svn.sourceforge.net/hugin/?rev=2914&view=rev
Author: tksharpless
Date: 2008-02-29 18:58:39 -0800 (Fri, 29 Feb 2008)
Log Message:
-----------
Major extension of APSC, now renamed autopano-sift-c, adds stereographic projection and reduces memory demand.
Source is in subdir APSCpp. Some bugfixes in libsift in addition to the change from double to float for image maps, which almost doubles useful image size for generatekeys as well as autopano-sift-c.
Modified Paths:
--------------
autopano-sift-C/trunk/AutoPanoSift.h
autopano-sift-C/trunk/CMakeLists.txt
autopano-sift-C/trunk/DisplayImage.c
autopano-sift-C/trunk/ImageMap.c
autopano-sift-C/trunk/LoweDetector.c
autopano-sift-C/trunk/ScaleSpace.c
autopano-sift-C/trunk/Utils.c
Added Paths:
-----------
autopano-sift-C/trunk/APSCpp/
autopano-sift-C/trunk/APSCpp/APSCpp.c
autopano-sift-C/trunk/APSCpp/APSCpp_main.c
autopano-sift-C/trunk/APSCpp/CamLens.c
autopano-sift-C/trunk/APSCpp/HermiteSpline.c
autopano-sift-C/trunk/APSCpp/HermiteSpline.h
autopano-sift-C/trunk/APSCpp/README-autopano-sift-c.txt
autopano-sift-C/trunk/APSCpp/cmakelists.txt
autopano-sift-C/trunk/APSCpp/saInterp.c
autopano-sift-C/trunk/APSCpp/saInterp.h
autopano-sift-C/trunk/APSCpp/saRemap.c
autopano-sift-C/trunk/APSCpp/sphereAlign.h
Added: autopano-sift-C/trunk/APSCpp/APSCpp.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/APSCpp.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/APSCpp.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,448 @@
+/* APSCpp.c 15 Feb 2008 TKS
+ various routines for enhanced autopano-sift-c
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "AutoPanoSift.h"
+#include "sphereAlign.h"
+#include "saInterp.h"
+#include <math.h>
+#include <tiffio.h>
+
+
+// create empty
+pDIinfo DIinfo_new0(){
+ pDIinfo p = (pDIinfo)malloc(sizeof(DIinfo));
+ if( p ) memset( p, 0, sizeof(DIinfo) );
+ return p;
+}
+
+// delete
+void DIinfo_delete( pDIinfo p ){
+ free( p );
+}
+
+
+
+// set up remapping once basic info is read
+// Scale > 0 is the ratio of source to destination dimensions
+// returns 1 OK, 0 fail
+saRemap * DIinfo_setRm( pDIinfo p, double Scale ){
+ CamLens * pcs, * pcd;
+ saRemap * prm;
+ int destwid, desthgt;
+ if( p->width < 1 || p->height < 1 ) return 0;
+ // destination dimensions
+ destwid = (int)(0.5 + p->width / Scale);
+ desthgt = (int)(0.5 + p->height / Scale);
+ // projection descriptors
+ pcs = CamLens_new1( p->width, p->height, p->format, p->hfov, 16.0 );
+ pcd = CamLens_new1( destwid, desthgt, _stereographic, p->hfov, 0 );
+ // remapping functions
+ prm = saRemap_new( pcs, pcd );
+
+ free( pcs ); free( pcd );
+
+ return prm;
+
+}
+
+
+/*
+ Get source image info from a panotools project file.
+
+ Adapted from "optimizer script parser" in panotools\parser.c
+ Should work with panotools, ptasmblr and hugin projects.
+ Ignores everything except 'i' lines (unless there are none,
+ when it scans the file again looking for 'o' lines).
+
+ input
+ project file name
+ output
+ adds a DisplayImage struct to DIlist for each "i" or "o" line
+ with only the following fields set
+ name
+ width
+ height
+ hfov
+ format
+ yaw
+ pitch
+ roll
+ returns
+ 0 on error else number of image lines found
+
+ Notes
+ ignores all optimizable params except hfov, y, p, r;
+ handles back references ("v=n", etc) by copying the value from
+ the referenced image.
+
+ accepts all format codes verbatim (original checks them)
+*/
+#define LINE_LENGTH 512
+#define READ_VAR( fmt, ref ) \
+ sscanf( ++li, fmt, ref ); \
+ if( *li == '"' ) do ++li; while(*li != '"'); \
+ while(*li > ' ') li++;
+
+int LoadProjectImages( char* script, ArrayList * DIlist )
+{
+ DIinfo *im, *ir; // DIlist items
+
+ // Variables used by parser
+
+ char *li, line[LINE_LENGTH], *ch;
+ int lineNum = 0;
+ int k;
+ int numIm = 0;
+ int baseIdx = ArrayList_Count( DIlist ); // 1st image goes here
+
+ int keychar;
+
+// setlocale(LC_ALL, "C");
+// loop over 'i', 'o' linestart
+ for( keychar = 'i';; ){
+ FILE * fp = fopen( script, "r" );
+ if( !fp ) return 0;
+
+ // Parse script
+
+ while( (ch = fgets(line, LINE_LENGTH, fp)) )
+ {
+ lineNum++;
+
+ if( line[0] == keychar
+ && isspace( line[1] ) )
+ {
+ // create new Image descriptor
+ im = DIinfo_new0();
+ // fill it from line
+ li = &(line[1]);
+ while( *li != 0 && *li != '\n')
+ {
+ switch(*li)
+ {
+ case 'w': READ_VAR( "%d", &(im->width) )
+ break;
+ case 'h': READ_VAR( "%d", &(im->height))
+ break;
+ case 'v': if( *(li+1) == '=' ){
+ // copy referenced value
+ ++li;
+ READ_VAR( "%d", &k )
+ ir = (DIinfo *)ArrayList_GetItem( DIlist, baseIdx + k );
+ im->hfov = ir->hfov;
+ }else{
+ READ_VAR( "%lf", &(im->hfov));
+ }
+ break;
+ case 'f':
+ READ_VAR( "%d", &(im->format) );
+ break;
+ case 'y': if( *(li+1) == '=' ){
+ // copy referenced value
+ ++li;
+ READ_VAR( "%d", &k )
+ ir = (DIinfo *)ArrayList_GetItem( DIlist, baseIdx + k );
+ im->yaw = ir->yaw;
+ }else{
+ READ_VAR( "%lf", &(im->yaw));
+ }
+ break;
+ case 'p': if( *(li+1) == '=' ){
+ // copy referenced value
+ ++li;
+ READ_VAR( "%d", &k )
+ ir = (DIinfo *)ArrayList_GetItem( DIlist, baseIdx + k );
+ im->pitch = ir->pitch;
+ }else{
+ READ_VAR("%lf", &(im->pitch));
+ }
+ break;
+ case 'r': if( *(li+1) == '=' ){
+ // copy referenced value
+ ++li;
+ READ_VAR( "%d", &k )
+ ir = (DIinfo *)ArrayList_GetItem( DIlist, baseIdx + k );
+ im->roll = ir->roll;
+ }else{
+ READ_VAR("%lf", &(im->roll));
+ }
+ break;
+ case 'n': // Set filename
+ { char *p = im->name;
+ READ_VAR( "%s", p );
+ // strip quotes
+ if( *p == '"' ){
+ while( p[1] != '"' ){
+ p[0] = p[1];
+ ++p;
+ }
+ *p = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ while( *li > ' ' ){ // skip next "word"
+ if( *li == '"' ) do ++li; while( *li != '"' ); // quoted strings
+ ++li;
+ }
+ if(*li) li++; // skip one nonnull
+
+ } // EOL
+
+ // add this image to list
+ numIm++;
+ ArrayList_AddItem( DIlist, im );
+
+ } // end of line
+ } // end of file
+
+ fclose( fp );
+
+ if( numIm > 0 || keychar == 'o' ) break;
+ keychar = 'o'; // try again...
+ }
+
+
+ return numIm;
+
+}
+
+/* Dump an ImagMap to a tiff file
+ return success or failure
+*/
+int ImageMap_toTIFF( ImageMap * p, char * name )
+{
+ int i, ok;
+
+// create tiff file
+ TIFF * tp = TIFFOpen( name, "w" );
+ if( !tp ) return 0;
+
+// set tiff tags
+ TIFFSetField( tp, TIFFTAG_IMAGEWIDTH, p->yDim );
+ TIFFSetField( tp, TIFFTAG_IMAGELENGTH, p->xDim );
+ TIFFSetField( tp, TIFFTAG_PLANARCONFIG, 1 ); // packed pixels
+ TIFFSetField( tp, TIFFTAG_ROWSPERSTRIP, 1 ); // separate rows
+ TIFFSetField( tp, TIFFTAG_COMPRESSION, 1 ); // uncompressed
+ TIFFSetField( tp, TIFFTAG_SAMPLESPERPIXEL, 1 ); // monochrome
+ TIFFSetField( tp, TIFFTAG_PHOTOMETRIC, 1 ); // greyscale
+ TIFFSetField( tp, TIFFTAG_BITSPERSAMPLE, 32 );
+ TIFFSetField( tp, TIFFTAG_SAMPLEFORMAT, 3 ); // IEEE float
+
+// write the data rowwise
+ for( i = 0; i < p->xDim; i++ ){
+ if((ok = TIFFWriteScanline( tp, p->values[i], i, 0 )) != 1 ) break;
+ }
+
+// done
+ TIFFClose( tp );
+ return ok;
+
+}
+
+/* subroutine equivalent to GenerateKeys.c
+
+ for APSC++, new argumnent pdi -> DIinfo struct with the input
+ projection format and angular width into needed to set up a
+ remapping to stereographic format. If pdi is 0, behaves like
+ GenerateKeys() with these exceptions.
+
+ 1) it sets the Lowe routine's prefilter sigma to 0.5 if the image stays
+ at original size, or to 0 (no further smoothing) if it is reduced here.
+
+ 2) it always reduces image size (when maxdim < largest input dimension)
+ by a smooth interpolation rather than simple decimation.
+
+ 3) it never invokes the Lowe detector's option to expand the image 2x.
+
+
+ returns 0 for failure
+
+*/
+
+KeypointXMLList * GenerateKeyspp( char * imgname, int maxdim, DIinfo * pdi )
+{
+#ifdef _DEBUG_INTERP
+ char tmp[262];
+#endif
+ int nKeys;
+ int pW, pH;
+ double Xcen, Ycen;
+ saRemap *prm = 0;
+ ImageMap* picMap = 0;
+ LoweFeatureDetector* lf;
+ KeypointXMLList* kpp;
+
+ double Scale = 1.0;
+
+
+// reduce Lowe prefilter smoothing
+ double savesigma = LoweFeatureDetector_SetPreprocSigma( 0.5 );
+
+/* read the image */
+
+ DisplayImage* pic = DisplayImage_new(imgname);
+ // (if we get here the image was read OK, and its name printed)
+ if(!pdi) {
+ WriteLine(" width %d height %d", pic->width, pic->height );
+ } else {
+ WriteLine(" width %d height %d format %d hfov %g",
+ pic->width, pic->height, pdi->format, pdi->hfov );
+ // put actual image dimensions in the DIinfo, just in case...
+ pdi->width = pic->width; pdi->height = pic->height;
+ }
+
+ pW = pic->width;
+ pH = pic->height;
+ Xcen = 0.5 * pW;
+ Ycen = 0.5 * pH;
+
+
+// convert to monochrome float and discard input image
+ picMap = DisplayImage_ConvertToImageMap( pic );
+ DisplayImage_delete(pic);
+
+#ifdef _DEBUG_INTERP
+ strcpy(tmp, imgname);
+ strcat(tmp,"-MAP.TIF");
+ ImageMap_toTIFF( picMap, tmp );
+#endif
+
+/* reduce size if required
+ by interpolating in smoothed map
+ also convert to stereographic if pdi is valid
+*/
+ // prescale factor
+ if( maxdim > 0) Scale = max( pW, pH ) / (double) maxdim;
+ if( Scale <= 1 ) Scale = 1;
+
+ // interpolate if necessary
+ if( pdi || Scale > 1 ){
+ ImageMap * pn;
+ int x, y;
+ double X, Y;
+ int dwid = pW, dhgt = pH;
+ // reduced dimensions
+ if( Scale > 1 ){
+ dwid = (int)(0.5 + pW / Scale );
+ dhgt = (int)(0.5 + pH / Scale );
+ Scale = (double) pW / (double) dwid; // exact
+ WriteLine(" reduce size to %d x %d", dwid, dhgt );
+ }
+ // create result map
+ pn = ImageMap_new( dwid, dhgt );
+ // smooth the source
+ ImageMap_GaussianConvolution( picMap, 0.75 * Scale );
+ LoweFeatureDetector_SetPreprocSigma( 0 );
+ // set up coordinate mapping
+ if( pdi ){ // ++ mode
+ CamLens * psp, * pdp;
+ // create the projections
+ psp = CamLens_new1( pW, pH, pdi->format, pdi->hfov, 16.0 );
+ pdp = CamLens_new1( dwid, dhgt, _stereographic, pdi->hfov, 0 );
+ // create the mapping
+ prm = saRemap_new( psp, pdp );
+ saRemap_inv ( prm, 0.5 * dwid, 0.5 * dhgt, &Xcen, &Ycen );
+ WriteLine(" use stereographic projection");
+ }
+ // interpolate
+ saInterpSetup((void *)picMap->values, // void * pdata
+ 2, // format is column vectors
+ picMap->xDim, // int wid,
+ picMap->yDim, // int hgt,
+ 1, // samples per pixel
+ picMap->xDim, // pixels per row
+ 0, // char wrap, // required
+ 0, // char * pmask,
+ 0, 0, 0 // mask params
+ );
+ for( x = 0; x < pn->xDim; x++ ){
+ float * pd = pn->values[x];
+ for( y = 0; y < pn->yDim; y++ ){
+ X = (double) x; Y = (double) y;
+ if( prm ) saRemap_inv ( prm, X, Y, &X, &Y ); // ++
+ else { X *= Scale; Y *= Scale; } // legacy
+ saInterp_float( &(pd[y]), X, Y );
+ }
+ }
+ // swap
+ ImageMap_delete( picMap );
+ picMap = pn;
+ saRemap_delete( prm ); prm = 0;
+#ifdef _DEBUG_INTERP
+ strcpy(tmp, imgname);
+ strcat(tmp,"-MAP-PROJ.TIF");
+ ImageMap_toTIFF( picMap, tmp );
+ WriteLine("ImageMap dumped to %s", tmp );
+ exit(0);
+#endif
+ }
+
+
+/* find the features
+*/
+
+ lf = LoweFeatureDetector_new0();
+ nKeys = LoweFeatureDetector_DetectFeaturesDownscaled (lf, picMap, 0, Scale);
+ WriteLine(" %d keypoints found\n", nKeys );
+
+ /* build the return value
+ We need a new copy of the list held in lf because lf is about to be deleted.
+ The following code adapted from LoweFeatureDetector_GlobalNaturalKeypoints()
+ does that, and also a needed format conversion (lucky this is not C++!)
+ */
+ {
+ ArrayList * globalNaturalKeypoints = ArrayList_new0 (KeypointN_delete);
+ int i;
+
+ if( pdi ){ // build remapping function at input scale
+ CamLens * psp, * pdp;
+ psp = CamLens_new1( pW, pH, pdi->format, pdi->hfov, 16.0 );
+ pdp = CamLens_new1( pW, pH, _stereographic, pdi->hfov, 0 );
+ prm = saRemap_new( psp, pdp ); // dest=>src
+ } else prm = 0;
+
+ for(i=0; i < ArrayList_Count(lf->globalKeypoints); i++) {
+ Keypoint* kp = (Keypoint *) ArrayList_GetItem( lf->globalKeypoints, i );
+ if( prm ){ // remap coordinates to image projection
+ saRemap_inv ( prm,
+ kp->x , kp->y , // scale to image size
+ &kp->x, &kp->y // remapped coords
+ );
+ }
+ ArrayList_AddItem ( globalNaturalKeypoints, KeypointN_new( kp ));
+ }
+ // package result as a KeypointXMLList
+ kpp = KeypointXMLList_new ( imgname, pW, pH, globalNaturalKeypoints );
+ }
+
+ LoweFeatureDetector_delete(lf);
+
+ // restore the default Lowe prefilter
+ LoweFeatureDetector_SetPreprocSigma( savesigma );
+ // disable the patent warning message (for any subsequent images)
+ LoweFeatureDetector_SetPrintWarning(false);
+
+ return kpp;
+}
+
+
Added: autopano-sift-C/trunk/APSCpp/APSCpp_main.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/APSCpp_main.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/APSCpp_main.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,878 @@
+
+/* APSCpp_main.c 18 Feb2008 TKSharpless
+
+ enhanced version of APSC for Hugin 0.7 that can transform images to
+ stereographic projection for better keypoint matching.
+
+ The enhanced mode is invoked by giving it a project file in place
+ of the image files. The project file 'i' lines supply information
+ about the images' projections, as well as their file names. This
+ info is stored in DIlist. The keypoint generator (and the refine
+ keypoints step if used) converts intensity maps to stereographic
+ projection using info from DIlist. At tne final output-to-pto stage
+ the control point coordinates get projected back to image space.
+
+ The projections are "ideal" (no lens or center point corrections), but
+ the reprojection machinery could handle those if available.
+
+ * Keypoint file correlation and hugin panorama file creation utility.
+ *
+ * (C) Copyright 2004 -- Sebastian Nowozin (nowozin@...)
+ *
+ * "The University of British Columbia has applied for a patent on the SIFT
+ * algorithm in the United States. Commercial applications of this software
+ * may require a license from the University of British Columbia."
+ * For more information, see the LICENSE file supplied with the distribution.
+ *
+ * This program is free software released under the GNU General Public
+ * License, which is included in this software package (doc/LICENSE).
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include "AutoPanoSift.h"
+#include "sphereAlign.h"
+
+// APSCpp.c
+int LoadProjectImages( char* script, ArrayList * DIlist );
+KeypointXMLList * GenerateKeyspp( char * imgname, int maxdim, DIinfo * pdi );
+
+void Usage ()
+{
+ WriteLine ("APSCpp: Generate and Match Keypoints giving Hugin project file\n");
+ WriteLine (" Version %s\n", PACKAGE_VERSION);
+ WriteLine ("usage: APSCpp.exe [options] output.pto image1 image2 [..]");
+ WriteLine (" or: APSCpp.exe [options] output.pto projectfile");
+ WriteLine (" projectfile is a PT compatible script giving image");
+ WriteLine (" file names, projections and angular widths. Enables");
+ WriteLine (" reprojection to stereographic format.\n");
+
+ WriteLine ("Options");
+ WriteLine (" --ransac <on|off|1|0> Switch RANSAC filtration on or off (default: on)");
+ WriteLine (" --maxmatches <matches> Use no more than the given number of matches");
+ WriteLine (" (default: 16, use zero for unlimited)");
+
+ WriteLine (" --disable-areafilter Do not use max-area filtration, which is default.");
+ WriteLine (" See manpage for details.");
+ WriteLine (" --integer-coordinates Truncate match coordinates to integer numbers.");
+ WriteLine (" --absolute-pathnames <on|off|1|0> Use the absolute pathname of the image");
+ WriteLine (" file in the PTO output file. Disabled by default.");
+ WriteLine (" --maxdim <n> Reduce image size so that largest dimension <= n.");
+ WriteLine (" --projection <n>,<d> n = PT format code, d = hfov in degrees. These");
+ WriteLine (" apply to all images, reprojection is enabled.");
+ WriteLine ("");
+
+ WriteLine ("Alignment options");
+ WriteLine (" --align Automatically pre-align images in PTO file.");
+ WriteLine (" --bottom-is-left");
+ WriteLine (" --bottom-is-right Use in case the automatic algorithm fails.");
+ WriteLine (" --generate-horizon <c> Generate up to 'c' horizon lines.");
+ WriteLine ("");
+
+ WriteLine ("Refinement options");
+ WriteLine (" --refine Refine the found control points using the");
+ WriteLine (" original images.");
+ WriteLine (" --refine-by-middle Use the best middle point to refine (default).");
+ WriteLine (" --refine-by-mean Use the mean of the patches control points.");
+ WriteLine (" --keep-unrefinable <on|off|1|0>");
+ WriteLine (" Keep unrefinable matches (default: on).");
+
+ WriteLine ("output.pto: The output PTO panorama project file.");
+ WriteLine (" The filename can be \"-\", then stdout is used");
+ WriteLine ("image<n>: input image files (any common format: JPEG, PNG, TIFF, ..)");
+ WriteLine ("Notice: for the aligning to work, the input images shall be");
+ WriteLine (" 1. All of the same dimension and scale");
+ WriteLine (" 2. The first images must be an ordered row. See manpage.");
+ WriteLine ("");
+}
+
+
+typedef struct Resolution Resolution;
+struct Resolution
+{
+ int x, y;
+};
+
+Resolution* Resolution_new0()
+{
+ Resolution* self = (Resolution*)malloc(sizeof(Resolution));
+ return self;
+}
+
+Resolution* Resolution_new(int x, int y)
+{
+ Resolution* self = Resolution_new0();
+ self->x = x;
+ self->y = y;
+ return self;
+}
+
+void Resolution_delete(Resolution* self)
+{
+ if (self) {
+ free(self);
+ }
+}
+
+int Resolution_CompareTo (Resolution* self, int x, int y)
+{
+
+ if (self->x == x && self->y == y)
+ return (0);
+
+ return (1);
+}
+
+
+
+
+// The maximum radius to consider around a keypoint that is refined. That
+// is, at most a patch of a maximum size of twice this value in both
+// horizontal and vertical direction is extracted.
+int RefinementRadiusMaximum = 96;
+int (*refineHandler)(int index, int total);
+
+
+void RefineKeypoints (ArrayList* msList,
+ bool selectMiddlePoint, bool neverLosePoints);
+DisplayImage* ExtractPatch (DisplayImage* large,
+ int px, int py, double scale, int* radius);
+ArrayList* ExtractKeypoints (DisplayImage* pic);
+bool YesNoOption (char* optionName, char* val);
+
+// selectMiddlePoint: if true, select the middle point in the patch,
+// otherwise build the mean
+// neverLosePoints: if true, and if we cannot do the refinement, still use
+// the control point.
+void RefineKeypoints (ArrayList* msList,
+ bool selectMiddlePoint, bool neverLosePoints)
+{
+ DisplayImage* pic1 = NULL;
+ DisplayImage* pic2 = NULL;
+ char* pic1Name = NULL;
+ char* pic2Name = NULL;
+
+ /* Keep stats for the refineHandler delegate
+ */
+ int totalRefines = 0;
+ int doneRefines = 0;
+ int i;
+ for(i=0; i<ArrayList_Count(msList); i++) {
+ MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);
+ int j;
+ for(j=0; j<ArrayList_Count(ms->matches); j++) {
+ ArrayList_GetItem(ms->matches, j);
+ totalRefines += 1;
+ }
+ }
+
+
+ for(i=0; i<ArrayList_Count(msList); i++) {
+ MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);
+ WriteLine (" between \"%s\" and \"%s\"",
+ ms->file1, ms->file2);
+
+ if (pic1Name != ms->file1) {
+ pic1Name = ms->file1;
+ pic1 = DisplayImage_new (ms->file1);
+ }
+ if (pic2Name != ms->file2) {
+ pic2Name = ms->file2;
+ pic2 = DisplayImage_new (ms->file2);
+ }
+ /*WriteLine ("pair: %s, %s, %d keypoint matches",
+ ms->file1, ms->file2, ArrayList_Count(ms->Matches));*/
+
+ ArrayList* refinedMatches = ArrayList_new0 (NULL);
+
+ int j;
+ for(j=0; j<ArrayList_Count(ms->matches); j++) {
+ Match* m = (Match*) ArrayList_GetItem(ms->matches, j);
+
+ int p1x = (int) (m->kp1->x + 0.5);
+ int p1y = (int) (m->kp1->y + 0.5);
+ int p1radius;
+ DisplayImage* patch1 = ExtractPatch (pic1, p1x, p1y,
+ m->kp1->scale, &p1radius);
+
+ int p2x = (int) (m->kp2->x + 0.5);
+ int p2y = (int) (m->kp2->y + 0.5);
+ int p2radius;
+ DisplayImage* patch2 = ExtractPatch (pic2, p2x, p2y,
+ m->kp2->scale, &p2radius);
+
+ /* Call the refine handler delegate in case there is one to
+ * inform the callee of a single refining step (for progress
+ * bar displays and such).
+ */
+ doneRefines += 1;
+ if (refineHandler != NULL)
+ refineHandler (doneRefines, totalRefines);
+
+ // Skip over keypoint matches we cannot refine as part of the
+ // image lies outside.
+ if (patch1 == NULL || patch2 == NULL) {
+ if (neverLosePoints)
+ ArrayList_AddItem(refinedMatches, m);
+ DisplayImage_delete(patch1);
+ DisplayImage_delete(patch2);
+ continue;
+ }
+
+ // Otherwise, run the SIFT algorithm on both small patches.
+ ArrayList* p1kp = ExtractKeypoints (patch1);
+ ArrayList* p2kp = ExtractKeypoints (patch2);
+ /*WriteLine ("p1kp = %d, p2kp = %d", ArrayList_Count(p1kp),
+ ArrayList_Count(p2kp));*/
+
+ // Apply the matching, RANSAC enabled.
+ MultiMatch* mm = MultiMatch_new0 ();
+ mm->verbose = false;
+
+ ArrayList* matches = NULL;
+ matches = MultiMatch_TwoPatchMatch (mm, p1kp,
+ patch1->width, patch1->height, p2kp, patch2->width,
+ patch2->height, true);
+ DisplayImage_delete(patch1);
+ DisplayImage_delete(patch2);
+
+ /* In case there are less than three keypoints in the
+ * two patches, we ignore them all.
+ */
+ if (0 /*was exception ???*/ ) {
+ matches = NULL;
+ }
+
+ if (matches == NULL || ArrayList_Count(matches) != 1) {
+ if (neverLosePoints)
+ ArrayList_AddItem(refinedMatches, m);
+
+ continue;
+ }
+
+ MatchSet* pSet = (MatchSet*) ArrayList_GetItem(matches, 0);
+
+ // Now get the real new control point coordinates from the
+ // patches. We have two options and assume all points are
+ // equal quality-wise:
+ // a) Select the one that is most in the middle
+ // (selectMiddlePoint == true)
+ // b) Build the mean of all the control point matches in the
+ // patches (selectMiddlePoint == false).
+ double kp1X = 0.0;
+ double kp1Y = 0.0;
+ double kp2X = 0.0;
+ double kp2Y = 0.0;
+ double kpMidDist = Double_PositiveInfinity;
+
+ int k;
+ for(k=0; k<ArrayList_Count(pSet->matches); k++) {
+ Match* pM = (Match*) ArrayList_GetItem(pSet->matches, k);
+ if (selectMiddlePoint) {
+ double dist = sqrt (
+ pow (pM->kp1->x - p1radius, 2.0) +
+ pow (pM->kp1->y - p1radius, 2.0));
+
+ if (dist < kpMidDist) {
+ kpMidDist = dist;
+
+ kp1X = pM->kp1->x;
+ kp1Y = pM->kp1->y;
+
+ kp2X = pM->kp2->x;
+ kp2Y = pM->kp2->y;
+ }
+ } else {
+ kp1X += pM->kp1->x;
+ kp1Y += pM->kp1->y;
+
+ kp2X += pM->kp2->x;
+ kp2Y += pM->kp2->y;
+ }
+
+ /*WriteLine ("(%g, %g) matches (%g, %g)",
+ pM->kp1->x, pM->kp1->y, pM->kp2->x, pM->kp2->y);*/
+ }
+
+ if (selectMiddlePoint == false) {
+ kp1X /= (double) ArrayList_Count(pSet->matches);
+ kp1Y /= (double) ArrayList_Count(pSet->matches);
+ kp2X /= (double) ArrayList_Count(pSet->matches);
+ kp2Y /= (double) ArrayList_Count(pSet->matches);
+ }
+
+ kp1X += p1x - p1radius;
+ kp1Y += p1y - p1radius;
+
+ kp2X += p2x - p2radius;
+ kp2Y += p2y - p2radius;
+
+ Match* mn = Match_clone (m);
+
+ // Adjust the original keypoints location to be the mean of
+ // all the highly precise superresolution points.
+ mn->kp1->x = kp1X;
+ mn->kp1->y = kp1Y;
+
+ mn->kp2->x = kp2X;
+ mn->kp2->y = kp2Y;
+
+ /*WriteLine ("MASTER POINT MATCH: (%g,%g) to (%g,%g)",
+ kp1X, kp1Y, kp2X, kp2Y);*/
+
+ ArrayList_AddItem(refinedMatches, mn);
+ /*
+ DisplayImage_Save (patch1, "patch-1.jpg");
+ DisplayImage_Save (patch2, "patch-2.jpg");
+ exit (0);
+ */
+ }
+
+ ms->matches = refinedMatches;
+ }
+}
+
+/** Extract a small image patch from a larger image, centered at the given
+ * coordinates.
+ */
+DisplayImage* ExtractPatch (DisplayImage* large,
+ int px, int py, double scale, int* radius)
+{
+ *radius = (int) (9.0 * scale + 0.5);
+ if (*radius > RefinementRadiusMaximum)
+ *radius = RefinementRadiusMaximum;
+
+ /*WriteLine ("patch centered at (%d,%d), scale %g, radius = %d",
+ px, py, scale, *radius);*/
+
+ int pxe = px + *radius;
+ int pye = py + *radius;
+ px -= *radius;
+ py -= *radius;
+
+ if (px < 0 || py < 0 || pxe >= large->width || pye >= large->height) {
+ /*WriteLine (" (%d,%d)-(%d,%d) out of (0,0)-(%d,%d)",
+ px, py, pxe, pye, large->width, large->height);*/
+
+ return (NULL);
+ } else {
+ //WriteLine (" extracting patch");
+ }
+ DisplayImage* patch = DisplayImage_Carve (large, px, py, *radius*2, *radius*2);
+
+ return (patch);
+}
+
+/** Produce keypoints for a small image patch.
+ */
+ArrayList* ExtractKeypoints (DisplayImage* pic)
+{
+ ImageMap* picMap = DisplayImage_ConvertToImageMap (pic);
+
+ LoweFeatureDetector* lf = LoweFeatureDetector_new0 ();
+ LoweFeatureDetector_SetPrintWarning(false);
+ LoweFeatureDetector_SetVerbose(false);
+ LoweFeatureDetector_DetectFeatures (lf, picMap);
+
+ ArrayList* res = LoweFeatureDetector_GlobalNaturalKeypoints(lf);
+ lf->globalNaturalKeypoints = NULL; // Make sure res won't get deleted.
+ LoweFeatureDetector_delete(lf);
+ return res;
+}
+
+bool YesNoOption (char* optionName, char* val)
+{
+ if (strcmp (val, "1") == 0 || strcmp (val, "on") == 0)
+ return (true);
+ else if (strcmp (val, "0") == 0 || strcmp (val, "off") == 0)
+ return (false);
+
+ FatalError ("'%s' is no valid truth value for option '%s'. Please see manpage for help.",
+ val, optionName);
+ return false;
+}
+
+/* mods for APSCpp
+ new arg DIlist gets * the image info list (++mode) or == 0 (legacy mode)
+ if ++ mode, copies this info to the output 'i' lines
+
+*/
+void WritePTOFile (FILE* pto, MultiMatch* mm,
+ ArrayList* msList, ArrayList * DIlist,
+ BondBall* bb, int generateHorizon, bool integerCoordinates,
+ bool useAbsolutePathnames)
+{
+ DIinfo * pdi = 0;
+ char buffer[262];
+
+ fprintf(pto, "# Hugin project file generated by APSCpp\n\n");
+ fprintf(pto, "p f2 w3000 h1500 v360 n\"JPEG q90\"\n");
+ fprintf(pto, "m g1 i0\n\n");
+
+ int imageIndex = 0;
+ HashTable* imageNameTab = HashTable_new0 (NULL, NULL);
+ ArrayList* resolutions = ArrayList_new0 (Resolution_delete);
+ int i;
+ for(i=0; i<ArrayList_Count(mm->keySets); i++) {
+ KeypointXMLList* kx = (KeypointXMLList*) ArrayList_GetItem(mm->keySets, i);
+ HashTable_AddItem(imageNameTab, kx->imageFile, (void*)imageIndex);
+ ArrayList_AddItem(resolutions, Resolution_new (kx->xDim, kx->yDim));
+
+ char* imageFile = kx->imageFile;
+ // get corresponding DIlist record
+ if( DIlist ){
+ for( i = 0; i < ArrayList_Count( DIlist ); i++ ){
+ pdi = (pDIinfo)ArrayList_GetItem( DIlist, i );
+ if( !strcmp( pdi->name, imageFile ) ) break;
+ }
+ if( i >= ArrayList_Count( DIlist ) )
+ pdi = 0; // NOT FOUND!!
+ }
+
+ // If the resolution was already there, use the first image with
+ // the exact same resolution as reference for camera-related
+ // values.
+
+ int refIdx;
+ for (refIdx = 0 ; refIdx < (ArrayList_Count(resolutions) - 1) ; ++refIdx) {
+ if (Resolution_CompareTo((Resolution*) ArrayList_GetItem(resolutions, refIdx), kx->xDim, kx->yDim) == 0)
+ break;
+ }
+ if (refIdx == (ArrayList_Count(resolutions) - 1))
+ refIdx = -1;
+
+ Position* pos = bb == NULL ? NULL :
+ (Position*) HashTable_GetItem(bb->positions, imageFile);
+ /*
+ if (pos != NULL) {
+ WriteLine ("yaw %g, pitch %g, rotation %g",
+ pos->yaw, pos->pitch, pos->rotation);
+ }*/
+
+ double yaw = 0.0, pitch = 0.0, rotation = 0.0, hfov = 180.0;
+ int format = 0;
+ if (pos != NULL) {
+ yaw = pos->yaw;
+ pitch = pos->pitch;
+ rotation = pos->rotation;
+ } else if( pdi ){
+ yaw = pdi->yaw;
+ pitch = pdi->pitch;
+ rotation = pdi->roll;
+ format = pdi->format;
+ hfov = pdi->hfov;
+ }
+
+ if (imageIndex == 0 || refIdx == -1) {
+ sprintf(buffer, "i w%d h%d f%d a0 b-0.01 c0 d0 e0 p%g r%g v%g y%g u10 n\"%s\"",
+ kx->xDim, kx->yDim, format, pitch, rotation, hfov, yaw, imageFile);
+ } else {
+ sprintf(buffer, "i w%d h%d f%d a=%d b=%d c=%d d0 e0 p%g r%g v=%d y%g u10 n\"%s\"",
+ kx->xDim, kx->yDim, format, refIdx, refIdx, refIdx, pitch, rotation, refIdx, yaw, imageFile);
+ }
+ fprintf( pto, "%s\n", buffer );
+//// WriteLine("%s", buffer );
+ imageIndex += 1;
+ }
+
+ fprintf(pto, "\nv p1 r1 y1\n\n");
+
+ fprintf(pto, "# automatically generated control points\n");
+ int j;
+ for(j=0; j<ArrayList_Count(msList); j++) {
+ MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, j);
+ int k;
+ for(k=0; k<ArrayList_Count(ms->matches); k++) {
+ Match* m = (Match*) ArrayList_GetItem(ms->matches, k);
+ if (integerCoordinates == false) {
+ fprintf(pto, "c n%d N%d x%.6f y%.6f X%.6f Y%.6f t0\n",
+ (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),
+ m->kp1->x, m->kp1->y, m->kp2->x, m->kp2->y);
+ } else {
+ fprintf(pto, "c n%d N%d x%d y%d X%d Y%d t0\n",
+ (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),
+ (int) (m->kp1->x + 0.5), (int) (m->kp1->y + 0.5),
+ (int) (m->kp2->x + 0.5), (int) (m->kp2->y + 0.5));
+ }
+ }
+ }
+
+ // Generate horizon if we should
+ if (bb != NULL && generateHorizon > 0) {
+ WriteLine ("Creating horizon...");
+
+ int kMain = 2;
+ int hPoints = generateHorizon;
+ int horizonPointsMade = 0;
+
+ bool hasGood = true;
+ while (hPoints > 0 && hasGood) {
+ hasGood = false;
+ int kStep = 2 * kMain;
+
+ int p;
+ for (p = 0 ; hPoints > 0 && p < kMain ; ++p) {
+ double stepSize = ((double) ArrayList_Count(bb->firstRow)) / ((double) kStep);
+ double beginIndex = p * stepSize;
+ double endIndex = (((double) ArrayList_Count(bb->firstRow)) / (double) kMain) +
+ p * stepSize;
+
+// Round to next integer and check if their image distance
+// is larger than 1. If its not, we skip over this useless
+// horizon point.
+ int bi = (int) (beginIndex + 0.5);
+ int ei = (int) (endIndex + 0.5);
+ if ((ei - bi) <= 1)
+ continue;
+
+ hasGood = true;
+
+ bi %= ArrayList_Count(bb->firstRow);
+ ei %= ArrayList_Count(bb->firstRow);
+ fprintf(pto, "c n%s N%s x%d y%d X%d Y%d t2\n",
+ (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, bi)),
+ (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, ei)),
+ ((Resolution*) ArrayList_GetItem(resolutions,bi))->x / 2,
+ ((Resolution*) ArrayList_GetItem(resolutions,bi))->y / 2,
+ ((Resolution*) ArrayList_GetItem(resolutions,ei))->x / 2,
+ ((Resolution*) ArrayList_GetItem(resolutions,ei))->y / 2);
+
+ horizonPointsMade += 1;
+ hPoints -= 1;
+ }
+
+// Increase density for next generation lines
+ kMain *= 2;
+ }
+ WriteLine (" made %d horizon lines.\n", horizonPointsMade);
+ }
+
+ fprintf(pto, "\n# :-)\n\n");
+
+ WriteLine ("\nYou can now load the output file into hugin.");
+ if( DIlist == 0 ){
+ WriteLine ("Notice: guessed image format and field-of-view, please check and adjust.");
+ }
+
+ ArrayList_delete(resolutions);
+ HashTable_delete(imageNameTab);
+}
+
+
+int main (int argc, char* argv[])
+{
+ // list used in ++ mode only -- image info from pto file
+ ArrayList * DIlist = 0; // item = DIinfo struct.
+ char *projectfile = 0;
+ // "--projection" option sets these for all images
+ int globFmt = -1; // PT format code
+ double globFov = 0; // width in degrees
+ int Nerr = 0; // counts commandline errors
+
+ // downscale option = largest allowed image dimension
+ int maxdim = 0;
+
+ // output to stdout flag
+ bool streamout = false;
+
+ // Automatic pre-aligning of images
+ bool preAlign = false;
+ int bottomDefault = -1;
+ int generateHorizon = 0;
+
+ // Use RANSAC algorithm match filtration.
+ bool useRansac = true;
+
+ // Use area based weighting for final match selection.
+ bool useAreaFiltration = true;
+
+ // Truncate match coordinates to integer numbers.
+ bool useIntegerCoordinates = false;
+
+ // Use the absolute pathname of the image files in the output PTO
+ // file.
+ bool useAbsolutePathnames = false;
+
+ // Use "keep-best" filtration, keep the maxMatches best.
+ int maxMatches = 25; // default
+
+ // Refinement options
+ bool refine = false;
+ bool refineMiddle = true;
+ bool keepUnrefinable = true;
+
+ int optionCount = 0;
+ int optionN = 1;
+ int i;
+
+ WriteLine ("\nAPSCpp, enhanced Autopano-sift-c");
+
+ LoweFeatureDetector_SetVerbose(false); // default low chatter
+
+ if (argc+1 < 3) { // can't be legal commandline
+ Usage ();
+ exit (1);
+ }
+
+ while (optionN < argc &&
+ strlen(argv[optionN]) >= 2
+ && argv[optionN][0] == '-'
+ && argv[optionN][1] == '-')
+ {
+ char* optionStr = argv[optionN];
+
+ if (strcmp (optionStr, "--maxdim") == 0) {
+ maxdim = atoi(argv[optionN + 1]);
+ optionN += 2;
+ } else if( strcmp (optionStr, "--projection") == 0) {
+ char *p = argv[optionN + 1];
+ if(sscanf( p, "%d", &globFmt ) != 1 ){
+ WriteLine ("Parameter to projection option invalid. See the usage help.");
+ ++Nerr;
+ }
+ p = strchr(p,',');
+ if( p ) globFov = atof(p+1);
+ else {
+ WriteLine ("Parameter to projection option invalid. See the usage help.");
+ ++Nerr;
+ }
+
+ optionN += 2;
+ } else if (strcmp (optionStr, "--ransac") == 0) {
+ useRansac = YesNoOption ("--ransac", argv[optionN + 1]);
+ optionN += 2;
+ } else if (strcmp (optionStr, "--maxmatches") == 0) {
+ if (sscanf(argv[optionN + 1], "%d", &maxMatches) != 1) {
+ WriteLine ("Parameter to maxmatches option invalid. See the usage help.");
+ ++Nerr;
+ }
+ if (maxMatches < 0) {
+ WriteLine ("Maximum number of matches must be positive or zero (unlimited).");
+ ++Nerr;
+ }
+ optionN += 2;
+ } else if (strcmp (optionStr, "--disable-areafilter") == 0) {
+ useAreaFiltration = false;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--integer-coordinates") == 0) {
+ useIntegerCoordinates = true;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--absolute-pathnames") == 0) {
+ useAbsolutePathnames = YesNoOption ("--absolute-pathnames", argv[optionN + 1]);
+ optionN += 2;
+ } else if (strcmp (optionStr, "--align") == 0) {
+ preAlign = true;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--bottom-is-left") == 0) {
+ bottomDefault = 0;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--bottom-is-right") == 0) {
+ bottomDefault = 1;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--generate-horizon") == 0) {
+ if (sscanf(argv[optionN + 1], "%d", &generateHorizon) != 1) {
+ WriteLine ("Parameter to generate-horizon option invalid. See the usage help.");
+ ++Nerr;
+ }
+ if (generateHorizon < 0) {
+ WriteLine ("The number of horizon lines to generate must be positive.");
+ ++Nerr;
+ }
+
+ optionN += 2;
+ } else if (strcmp (optionStr, "--refine") == 0) {
+ refine = true;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--refine-by-middle") == 0) {
+ refineMiddle = true;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--refine-by-mean") == 0) {
+ refineMiddle = false;
+ optionN += 1;
+ } else if (strcmp (optionStr, "--keep-unrefinable") == 0) {
+ keepUnrefinable = YesNoOption ("--keep-unrefinable", argv[optionN + 1]);
+ optionN += 2;
+ } else {
+ WriteLine ("Option error. Run without arguments for help.");
+ ++Nerr;
+ }
+ }
+ optionCount = optionN;
+ // is there an output name and at least one input name?
+ if( argc - optionN < 2 ){
+ WriteLine ("Error. Output name and at least one more name required.");
+ ++Nerr;
+ }
+
+ if (bottomDefault != -1 && preAlign == false) {
+ WriteLine ("Please enable automatic alignment (\"--align\") before using the");
+ WriteLine ("--bottom-is-* options.");
+ ++Nerr;
+ }
+
+ if (generateHorizon > 0 && preAlign == false) {
+ WriteLine ("Please enable automatic alignment (\"--align\") before using the");
+ WriteLine ("--generate-horizon option. Run without arguments for help.");
+ ++Nerr;
+ }
+
+// show usage and quit if commandline errors
+ if (Nerr){
+ WriteLine ("%d commandline errors.\n", Nerr );
+ Usage();
+ exit( 1 );
+ }
+
+ // next arg is either output file name or "-" for stdout
+ // anything else beginning with '-' is an error
+ if( argv[optionCount][0] == '-' ){
+ if( strcmp( argv[optionCount], "-" ) == 0 )streamout = true;
+ else {
+ WriteLine ("Misplaced option '%s'.\n", argv[optionCount] );
+ Usage();
+ exit (1);
+ }
+ }
+ /* next arg is either a script name or the first of 2 or more image file names
+ */
+ if( argc - optionCount == 2 ){
+ projectfile = argv[optionCount + 1];
+ WriteLine("Reading project file %s", projectfile );
+ // enable ++ mode by creating DIlist
+ DIlist = ArrayList_new0( DIinfo_delete );
+ // read the proect file image info into DIlist, or die
+ if( LoadProjectImages( argv[optionCount + 1], DIlist ) ==0 ){
+ WriteLine ("Error reading project file.");
+ exit(1);
+ }
+ } else if( globFmt >= 0 && globFov > 0 ){
+ // enable ++ mode
+ DIlist = ArrayList_new0( DIinfo_delete );
+ }
+
+ if( DIlist ) WriteLine(" Stereographic projection enabled.");
+
+
+ MultiMatch* mm = MultiMatch_new0 ();
+
+/** Find keypoints **/
+
+
+ ArrayList* keylists = ArrayList_new0(NULL);
+
+ if( DIlist ){
+ // ++ mode: image info from DIlist
+ pDIinfo pd;
+ // build it first if only a global projection was given
+ if( globFmt >= 0 ){
+ for( i=0; i<argc - 1 - optionCount; i++) {
+ pd = DIinfo_new0();
+ pd->format = globFmt;
+ pd->hfov = globFov;
+ strcpy(pd->name, argv[i+optionCount+1] );
+ // note dimensions are still zero
+ ArrayList_AddItem( DIlist, pd );
+ }
+ }
+ // process the images
+ for( i = 0; i < ArrayList_Count( DIlist ); i++ ){
+ pd = (pDIinfo) ArrayList_GetItem( DIlist, i);
+ ArrayList_AddItem(keylists, GenerateKeyspp( pd->name, maxdim, pd) );
+ }
+ } else {
+ // std mode: image names only from commandline
+ for( i=0; i<argc - 1 - optionCount; i++) {
+ ArrayList_AddItem(keylists, GenerateKeyspp( argv[i+optionCount+1], maxdim, 0) );
+ }
+ }
+
+/** Find control points **/
+
+ MultiMatch_LoadKeysetsFromMemory (mm, keylists);
+ // note mm now owns keylists and will delete it when destroyed
+
+ WriteLine ("\nMatching...%s", useRansac == true ? " RANSAC enabled" : "");
+ ArrayList* msList = MultiMatch_LocateMatchSets (mm, 3, maxMatches,
+ useRansac, useAreaFiltration);
+
+ // Connected component check
+ WriteLine ("\nConnected component check...");
+ ArrayList* components = MultiMatch_ComponentCheck (mm, msList);
+ WriteLine ("Connected component identification resulted in %d component%s:",
+ ArrayList_Count(components), ArrayList_Count(components) > 1 ? "s" : "");
+
+ int compN = 1;
+ int j;
+ for(j=0; j<ArrayList_Count(components); j++) {
+ Component* comp = (Component*) ArrayList_GetItem(components, j);
+ char* compstr = Component_ToString(comp);
+ WriteLine ("component %d: %s", compN++, compstr);
+ free(compstr);
+ }
+
+ if (ArrayList_Count(components) > 1) {
+ WriteLine ("");
+ WriteLine ("Warning: There is one or more components that are not connected through control");
+ WriteLine (" points. An optimization of the resulting PTO will not be possible");
+ WriteLine (" without prior adding of control points between the components listed");
+ WriteLine (" above. Please see the manual page for autopano(1) for details.");
+ WriteLine ("");
+ } else
+ WriteLine ("");
+
+ // BondBall algorithm
+ BondBall* bb = NULL;
+ if (preAlign) {
+ bb = MultiMatch_BuildBondBall (mm, msList, bottomDefault);
+
+ if (bb == NULL) {
+ WriteLine ("WARNING: Failed to build bondball as requested. No pre-aligning of images");
+ WriteLine (" takes place.\n");
+ }
+ }
+
+ if (refine) {
+ WriteLine ("Refining keypoints");
+ RefineKeypoints (msList, refineMiddle, keepUnrefinable);
+ }
+
+ FILE* pto;
+ if ( streamout ) {
+ pto = stdout;
+ } else {
+ WriteLine ("Creating output file \"%s\"", argv[optionCount]);
+ if( DIlist ){
+ WriteLine ("with image info from \"%s\"", projectfile);
+ }
+ pto = fopen(argv[optionCount], "w");
+ }
+
+ WritePTOFile (pto, mm, msList, DIlist,
+ bb, generateHorizon, useIntegerCoordinates,
+ useAbsolutePathnames);
+
+ ArrayList_delete(components);
+ BondBall_delete(bb);
+ MultiMatch_delete(mm);
+ if ( !streamout )
+ fclose(pto);
+
+
+ return 0;
+}
+
Added: autopano-sift-C/trunk/APSCpp/CamLens.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/CamLens.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/CamLens.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,252 @@
+/* CamLens.c 20 Feb 2008 TKS
+
+ implementaton of CamLens class
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "sphereAlign.h"
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+
+/* radius <=> angle functions for lens projections
+ R is noramlized image radius
+ K is an adjustable parameter
+ A is angle in radians
+ NOTE no error checks, pass only reasonable values!
+ |A| |R|
+ rect <Pi/2 any
+ fish any <= K
+ mirr any <= 2
+ ster <Pi any
+*/
+
+static double r2a_rect( double R, double K ){
+ return atan( R );
+}
+
+static double a2r_rect( double A, double K ){
+ return tan( A );
+}
+
+static double r2a_fish( double R, double K ){
+ return K * asin( R / K );
+}
+
+static double a2r_fish( double A, double K ){
+ return K * sin( A / K );
+}
+
+static double r2a_mirr( double R, double K ){
+ return asin( 0.5 * R );
+}
+
+static double a2r_mirr( double A, double K ){
+ return sin( 0.5 * A );
+}
+
+
+static double r2a_ster( double R, double K ){
+ return 2 * atan( R );
+}
+
+static double a2r_ster( double A, double K ){
+ return tan(0.5 * A);
+}
+
+
+
+// create empty
+pCamLens CamLens_new0()
+{
+ pCamLens p = (pCamLens) malloc(sizeof(CamLens));
+ if( p ) memset(p, 0, sizeof(CamLens));
+ return p;
+}
+
+/* initialize with minimal info
+ fmt is a PT format code
+ fails if fmt is not a "camera" projection
+ hfov is the angle corresponding to wid
+ flmm should be 0 for an ideal projection, >0 for a real lens
+ other assumptions see CamLens_setProjection()
+
+*/
+pCamLens CamLens_new1( int wid, int hgt, int fmt, double hfov, double flmm )
+{
+ pCamLens p;
+ double R, x, y;
+
+ if( fmt < _rectilinear || fmt > _stereographic ) return 0;
+ p = CamLens_new0();
+ p->FLmm = flmm;
+ if( CamLens_setProjection( p, fmt )){
+
+ p->widpix = wid;
+ p->hgtpix = hgt;
+ p->FLmm = flmm;
+
+ // focal lengths in pixels
+ R = CamLens_RofA( p, DEG2RAD( 0.5 * hfov ) );
+ p->hFLpix = p->vFLpix = 0.5 * p->widpix / R;
+
+ // projection center
+ p->hCpix = 0.5 * wid;
+ p->vCpix = 0.5 * hgt;
+
+ // default crop radius circumscribes raster
+ x = y = 0;
+ p->Rcrop = CamLens_getR( p, x, y );
+
+ // reference radius inscribed in raster
+ if( p->hFLpix * p->vCpix > p->vFLpix * p->hCpix )
+ y = p->vCpix; // wid < hgt
+ else x = p->hCpix; // wid >= hgt
+ p->Rref = CamLens_getR( p, x, y );
+
+ }
+
+ if( p->widpix < 1 || p->hgtpix < 1
+ || p->hFLpix == 0 ){
+ free(p);
+ p = 0;
+ }
+
+ return p;
+}
+
+/* set projection format
+
+ fmt is an image format code defined in panorama.h
+
+ returns 0 for unsupported format
+ 1 for OK
+
+ Assumes --
+ ideal projection if FLmm == 0, else lens projection
+ equal-area fisheye lens for _equirectangular (the
+ ideal is equal-angle)
+ lens projects Y of cylindrical and equirectangular
+ and both axes of the elliptical formats
+
+*/
+int CamLens_setProjection( pCamLens p, int fmt )
+{ // null format
+ p->PT_fmt = -1;
+ p->R2A = 0;
+ p->A2R = 0;
+ p->Klens = 0;
+ p->lensAxis = (p->FLmm ? 3 : 0 ); // elliptical
+ p->Rref = p->Rcrop = 0; // no limit
+ switch( fmt ){
+ case _rectilinear:
+ p->R2A = r2a_rect;
+ p->A2R = a2r_rect;
+ p->Klens = 1.0;
+ break;
+ case _panorama:
+ p->R2A = r2a_rect;
+ p->A2R = a2r_rect;
+ p->Klens = 1.0;
+ p->lensAxis &= 2; // lens Y only
+ break;
+ case _fisheye_circ:
+ case _fisheye_ff:
+ p->R2A = r2a_fish;
+ p->A2R = a2r_fish;
+ p->Klens = 2.0;
+ p->Rref = p->Rcrop = p->Klens;
+ break;
+ case _equirectangular:
+ if( p->FLmm ){
+ p->R2A = r2a_fish;
+ p->A2R = a2r_fish;
+ p->Klens = 2.0;
+ p->Rref = p->Rcrop = p->Klens;
+ p->lensAxis = 2; // Y only
+ }
+ break;
+ case _spherical_cp:
+ case _spherical_tp:
+ if( p->FLmm ){
+ p->R2A = r2a_fish;
+ p->A2R = a2r_fish;
+ p->Klens = 500.0;
+ p->Rref = p->Rcrop = p->Klens;
+ }
+ break;
+ case _mirror:
+ p->R2A = r2a_mirr;
+ p->A2R = a2r_mirr;
+ p->Klens = 1.0;
+ break;
+ case _orthographic:
+ p->R2A = r2a_fish;
+ p->A2R = a2r_fish;
+ p->Klens = 1.0;
+ p->Rref = p->Rcrop = p->Klens;
+ break;
+ case _stereographic:
+ p->R2A = r2a_ster;
+ p->A2R = a2r_ster;
+ p->Klens = 1.0;
+ break;
+
+ default:
+ p->lensAxis = 0;
+ return 0; // unsupported format
+
+ }
+ // OK
+ p->PT_fmt = fmt;
+ return 1; // OK
+}
+
+// initialize with full info
+pCamLens CamLens_new( pCameraInfo pc, pLensInfo pl )
+{
+ return 0; /// TBD ///
+}
+
+// normalized radius to angle in radians
+double CamLens_AofR( pCamLens p, double R ){
+ if( p->R2A == 0 ) return R;
+ return (p->R2A)( R, p->Klens );
+}
+
+// angle in radians to normalized radius
+double CamLens_RofA( pCamLens p, double A ){
+ if( p->A2R == 0 ) return A;
+ return (p->A2R)( A, p->Klens );
+}
+
+// get largest valid normalized radius
+double CamLens_Rmax( pCamLens p ){
+ return p->Rcrop;
+}
+
+
+/* pixel coordinates to normalized radius */
+double CamLens_getR( CamLens *p, double x, double y )
+{
+ double dx = ( x - p->hCpix ) / p->hFLpix;
+ double dy = ( y - p->vCpix ) / p->vFLpix;
+ return sqrt( dx * dx + dy * dy );
+}
+
Added: autopano-sift-C/trunk/APSCpp/HermiteSpline.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/HermiteSpline.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/HermiteSpline.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,353 @@
+
+/* HermiteSpline.c 16 Feb 2008 TKS
+
+ Hermite Spline Interpolation Routines
+ adapted from John Burkardt's collection at
+ http://people.scs.fsu.edu/~burkardt/cpp_src/spline/spline.html
+ NOTE FORTRAN style 1-origin array indexing in some places
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <stdlib.h>
+#include <math.h>
+#include "HermiteSpline.h"
+
+/* some functions below test monotonicity by checking that
+ the differece across n >= 2 intervals is >= n * fIEPS
+ (the difference across a single interval can be 0)
+*/
+#define fIEPS 1.e-11 // tolerance for nonzero difference
+
+ /** Tabulate coefficients for Hermit Spline Interpolation **/
+
+double *spline_hermite_set ( int ndata, double tdata[], double ydata[],
+ double ypdata[] )
+
+//****************************************************************************80
+//
+// Purpose:
+//
+// SPLINE_HERMITE_SET sets up a piecewise cubic Hermite interpolant.
+//
+// Discussion:
+//
+// Once the array C is computed, then in the interval
+// (TDATA(I), TDATA(I+1)), the interpolating Hermite polynomial
+// is given by
+//
+// SVAL(TVAL) = C(1,I)
+// + ( TVAL - TDATA(I) ) * ( C(2,I)
+// + ( TVAL - TDATA(I) ) * ( C(3,I)
+// + ( TVAL - TDATA(I) ) * C(4,I) ) )
+//
+// This is algorithm CALCCF from Conte and deBoor.
+//
+// Modified:
+//
+// 11 February 2004
+//
+// Author:
+//
+// John Burkardt
+//
+// Reference:
+//
+// Samuel Conte, Carl deBoor,
+// Elementary Numerical Analysis,
+// Second Edition,
+// McGraw Hill, 1972,
+// ISBN: 07-012446-4.
+//
+// Parameters:
+//
+// Input, int NDATA, the number of data points.
+// NDATA must be at least 2.
+//
+// Input, double TDATA[NDATA], the abscissas of the data points.
+// The entries of TDATA are assumed to be strictly increasing.
+//
+// Input, double Y[NDATA], YP[NDATA], the value of the
+// function and its derivative at TDATA(1:NDATA).
+//
+// Output, double SPLINE_HERMITE_SET[4*NDATA], the coefficients of
+// the Hermite polynomial. We will refer to this array as "C".
+// C(1,1:NDATA) = Y(1:NDATA) and C(2,1:NDATA) = YP(1:NDATA).
+// C(3,1:NDATA-1) and C(4,1:NDATA-1) are the quadratic and cubic
+// coefficients.
+//
+{
+ double *c;
+ double divdif1;
+ double divdif3;
+ double dt;
+ int i;
+ int j;
+
+ // c = new double[4*ndata];
+ c = (double *)malloc(4*ndata*sizeof(double));
+
+ for ( j = 0; j < ndata; j++ )
+ {
+ c[0+j*4] = ydata[j];
+ }
+
+ for ( j = 0; j < ndata; j++ )
+ {
+ c[1+j*4] = ypdata[j];
+ }
+
+ for ( i = 1; i <= ndata-1; i++ )
+ {
+ dt = tdata[i] - tdata[i-1];
+ divdif1 = ( c[0+i*4] - c[0+(i-1)*4] ) / dt;
+ divdif3 = c[1+(i-1)*4] + c[1+i*4] - 2.0 * divdif1;
+ c[2+(i-1)*4] = ( divdif1 - c[1+(i-1)*4] - divdif3 ) / dt;
+ c[3+(i-1)*4] = divdif3 / ( dt * dt );
+ }
+
+ c[2+(ndata-1)*4] = 0.0;
+ c[3+(ndata-1)*4] = 0.0;
+
+ return c;
+}
+//****************************************************************************80
+
+
+ /** Compute a Hermite Spline Interpolation **/
+
+int spline_hermite_val ( int ndata, double tdata[], double c[], double tval,
+ double *sval, double *spval )
+
+//****************************************************************************80
+//
+// Purpose:
+//
+// SPLINE_HERMITE_VAL evaluates a piecewise cubic Hermite interpolant.
+//
+// Discussion:
+//
+// SPLINE_HERMITE_SET must be called first, to set up the
+// spline data from the raw function and derivative data.
+//
+// In the interval (TDATA(I), TDATA(I+1)), the interpolating
+// Hermite polynomial is given by
+//
+// SVAL(TVAL) = C(1,I)
+// + ( TVAL - TDATA(I) ) * ( C(2,I)
+// + ( TVAL - TDATA(I) ) * ( C(3,I)
+// + ( TVAL - TDATA(I) ) * C(4,I) ) )
+//
+// and
+//
+// SVAL'(TVAL) = C(2,I)
+// + ( TVAL - TDATA(I) ) * ( 2 * C(3,I)
+// + ( TVAL - TDATA(I) ) * 3 * C(4,I) )
+//
+// This is algorithm PCUBIC from Conte and deBoor.
+//
+// Modified:
+//
+// 24 February 2004
+//
+// Author:
+//
+// John Burkardt
+//
+// Reference:
+//
+// Samuel Conte, Carl deBoor,
+// Elementary Numerical Analysis,
+// Second Edition,
+// McGraw Hill, 1972,
+// ISBN: 07-012446-4.
+//
+// Parameters:
+//
+// Input, int NDATA, the number of data points.
+// NDATA is assumed to be at least 2.
+//
+// Input, double TDATA[NDATA], the abscissas of the data points.
+// The entries of TDATA are assumed to be strictly increasing.
+//
+// Input, double C[4*NDATA], the coefficient data computed by
+// SPLINE_HERMITE_SET.
+//
+// Input, double TVAL, the point where the interpolant is to
+// be evaluated.
+//
+// Output, double *SVAL, *SPVAL, the value of the interpolant
+// and its derivative at TVAL.
+//
+/** TKS mods Feb 2008
+ add a return value: 0 failure, 1 success
+ use interpolating interval search; fail if arg out of range
+ don't compute derivative if spval is null
+ declare local vars register
+**/
+{
+ register double dt;
+ register int left;
+
+ left = findInterval( ndata, tdata, tval );
+ if( left < 0 ) return 0;
+//
+// Evaluate the cubic polynomial.
+//
+ dt = tval - tdata[left];
+
+ *sval = c[0+(left)*4]
+ + dt * ( c[1+(left)*4]
+ + dt * ( c[2+(left)*4]
+ + dt * c[3+(left)*4] ) );
+
+ if( spval )
+ *spval = c[1+(left)*4]
+ + dt * ( 2.0 * c[2+(left)*4]
+ + dt * 3.0 * c[3+(left)*4] );
+
+ return 1;
+}
+
+/* Compute array of tangents for a tabulated function
+ to serve as derivatives for setting up a Hermite spline.
+
+ t values must be strictly monotonic (no zero differences)
+ but need not be equally spaced.
+ If y is monotonic, the tangents will be adjusted to ensure that
+ interpolated values are monotonic, too; else no adjustment.
+
+ Input:
+ ndata, tdata[ndata], ydata[ndata] as above
+ ypd[ndata] -- receives the tangents
+ Output:
+ returns 0 if tdata[] is not monotonic or ndata < 2 (fail)
+ 1 if y is monotonic (tangents set)
+ -1 if y is not monotonic (tangents set)
+
+ Method:
+ divided differences, suitable for unequally spaced data
+ (the spline 1st derivative may not be perfectly smooth)
+
+ References:
+ Wikipedia: "Cubic Hermite spline"
+ Wikipedia: "Monotone cubic interpolation"
+
+*/
+int spline_tangents_set( int ndata, double tdata[], double ydata[], double ypd[] ){
+ int i, mono;
+ double d, *del = 0;
+// check t
+ if( ndata < 2 ) return 0;
+ d = (tdata[ndata-1] - tdata[0]) / (ndata - 1); // avg t difference
+ if( fabs(d) < fIEPS ) return 0; // implausibly small!
+ if( d < 0 ){
+ for( i = 1; i < ndata; i++ ) if( tdata[i] - tdata[i-1] >= 0 ) return 0;
+ } else {
+ for( i = 1; i < ndata; i++ ) if( tdata[i] - tdata[i-1] <= 0 ) return 0;
+ }
+
+// allocate temp array or die
+ del = (double *)malloc(ndata*sizeof(double));
+ if( !del ) return 0;
+
+// compute divided y differences, test monotonicity
+ mono = 1;
+ d = 0; // previous difference
+ for( i = 1; i < ndata; i++ ){
+ register double yd = ydata[i] - ydata[i-1];
+ if( yd * d < 0 ) mono = 0; // not monotone
+ d = yd;
+ del[i] = yd / (tdata[i] - tdata[i-1]);
+ }
+ if( mono ){
+ if( fabs( ydata[ndata - 1] - ydata[0] ) < ndata * fIEPS ){
+ mono = 0;
+ }
+ }
+
+// compute tangents
+ ypd[0] = del[1];
+ ypd[ndata-1] = del[ndata-1];
+ for( i = 1; i < ndata - 1; i++ ){
+ ypd[i] = 0.5 * (del[i] + del[i+1]);
+ }
+
+// adjust for monotonicity
+ if( mono ){
+ register double a, b, c;
+ for( i = 1; i < ndata; i++ ){
+ if( fabs(del[i]) < 1.e-11 ){
+ ypd[i-1] = ypd[i] = 0;
+ } else {
+ a = ypd[i-1] / del[i];
+ b = ypd[i] / del[i];
+ c = a * a + b * b;
+ if( c > 9.0 ){ // adjust...
+ c = 3.0 / sqrt( c );
+ ypd[i-1] *= c;
+ ypd[i] *= c;
+ }
+ }
+ }
+ }
+
+ free( del );
+ return ( mono ? 1 : -1 );
+}
+
+/* Find the interval (if any) in t[n] that contains x
+ t[] must be monotonic ascending or descending
+ (isolated intervals with zero difference OK)
+ returns i if x == t[i]
+ returns index (0:n-2) of the left end of the interval, or
+ -1 if x is out of range
+ -2 if t is not monotonic
+ method: binary search intialized with secant
+*/
+
+int findInterval( int n, double t[], double x )
+{ int l, r, s;
+ double d;
+
+ if ( n < 2 ) return -2; // no data
+
+ l = 0; r = n-1;
+ d = t[r] - t[l];
+ if( fabs( d ) < fIEPS ) return -2; // insufficient slope
+ s = (int) ((x - t[0]) / d); // splitting idex
+ if( s < l || s > r ) return -1; // out of range
+
+ if( d > 0 ){
+ while ( r - l > 1 ){
+ if( x < t[s] ) r = s;
+ else l = s;
+ s = ( r + l ) / 2;
+ }
+ } else {
+ while ( r - l > 1 ){
+ if( x > t[s] ) r = s;
+ else l = s;
+ s = ( r + l ) / 2;
+ }
+ }
+
+ return l;
+}
+
Added: autopano-sift-C/trunk/APSCpp/HermiteSpline.h
===================================================================
--- autopano-sift-C/trunk/APSCpp/HermiteSpline.h (rev 0)
+++ autopano-sift-C/trunk/APSCpp/HermiteSpline.h 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,80 @@
+/* HermiteSpline.h 16 Feb 2008 TKS
+
+ Hermite Spline Interpolation Routines
+ lifted & adapted from John Burkardt's collection at
+ http://people.scs.fsu.edu/~burkardt/cpp_src/spline/spline.html
+ NOTE FORTRAN style 1-origin array indexing
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HERMITESPLINE_H
+#define _HERMITESPLINE_H
+
+/* tabulate coefficients for Hermite spline interpolation of y(t)
+ tdata[ndata], ydata[ndata] are tabulated y{t} values
+ ypdata[ndata] are its 1st derivatives at same t's (how you set
+ these determines the curviness of the spline)
+ Note t values must be monotonic but intervals can vary
+ Returns pointer to a new array c[4*ndata] of coefficients
+ Note c[] is allocated with malloc()
+*/
+double *spline_hermite_set ( int ndata, double tdata[], double ydata[], double ypdata[] );
+
+/* compute hermite spline interpolation
+ tdata[ndata] = tabulated t values; c[4*ndata] = coefficients
+ tval = interpolation point
+ sval -> returned interpolated y value
+ spval -> returned derivative at that point (0: no derivative computed)
+ returns 0: bad input or 1: sucess
+*/
+int spline_hermite_val ( int ndata, double tdata[], double c[],
+ double tval, double * sval, double * spval );
+
+/* set tangents (1st divided differences) for a tabulated function
+ whose tabulation interval need not be uniform.
+ these can serve as the derivatives for setting up a spline.
+
+ Input: ndata, tdata[ndata], ydata[ndata] as above.
+ ypdata[ndata] -- place for the result
+
+ returns 0 if tdata[] is not monotonic or ndata < 2 or the
+ range of t or y is < 1e-11, else
+ 1 if ydata[] is monotonic, else
+ -1 if ydata[] is not monotonic
+
+ If y is monotonic, the tangents are adjusted to ensure that all
+ interpolated values will be monotonic as well.
+
+*/
+int spline_tangents_set( int ndata, double tdata[], double ydata[], double ypdata[] );
+
+/* Find the interval (if any) in t[n] that contains x
+ t[] must be monotonic ascending or descending
+ returns i if x == t[i]
+ returns index (0:n-2) of the left end of the interval, or
+ -1 if x is out of range
+ -2 if t is not monotonic
+ method: linear interpolation search
+*/
+int findInterval( int n, double t[], double x );
+
+
+#endif //ndef _HERMITESPLINE_H
+
+
Added: autopano-sift-C/trunk/APSCpp/README-autopano-sift-c.txt
===================================================================
--- autopano-sift-C/trunk/APSCpp/README-autopano-sift-c.txt (rev 0)
+++ autopano-sift-C/trunk/APSCpp/README-autopano-sift-c.txt 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,51 @@
+APSCpp == enhanced autopano-sift-c 29 Feb 2008 TKSharpless
+
+New executable autopano-sift-c combines keypoint finding and matching in one
+program. It is built on the autopano-sift-c codebase, and basically delivers
+the same functionality as generatekeys + autopano, but adds a few new options.
+
+The most important are the ability to run under hugin as an alternate control
+point finder, and the option of converting to stereographic projection before
+finding keypoints.
+
+The stereographic projection can give better results on wide angle and fisheye
+images. To construct it, autopano-sift-c needs to know the projection type(s)
+and angular width(s) of the images. There are two ways to give this information.
+
+When all the images have the same format and hfov, they can be specified with
+new commandline option "--projection".
+
+Or a PanoTools-compatible project file can be given in place of the list of image
+file names at the end of the command, and autopano-sift-c will read the necessary
+data from the "i" lines (or the "o" lines if there are no "i" lines).
+
+The first method allows using the stereographic mode under hugin, by putting
+" --projection %f,%v " in hugin's command line template. The second works with
+PanoTools scripts of many kinds, including hugin, PTassembler and PTGui project
+files, but must be run from a command shell.
+
+The output is a .pto file that can be loaded into hugin. In stereographic mode
+this file has the format and hfov information.
+
+There is one other commandline difference from generatekeys: the limit on the
+larger image dimension is --maxdim, not --mindim.
+
+The APSCpp extension adds several new source files and a few improvements to the
+existing libsift code. Besides bug fixes, there is one major change: most of
+the internal image data are now stored as floats rather than doubles. This allows
+processing of significantly larger images on any given machine.
+
+The new program also uses a better method of reducing image size, which leads to
+somewhat more stable control point positions.
+
+TODO --
+
+-- find out why the kd-tree keypoint matching runs 20x slower than Jenney's, and
+fix or replace it.
+
+-- find out why enabling RANSAC seems to make the alignments worse, when the
+opposite would be expected, and fix that too.
+
+-- when a project file is input, output a full copy of it with just the conttrol
+points replaced.
+
Added: autopano-sift-C/trunk/APSCpp/cmakelists.txt
===================================================================
--- autopano-sift-C/trunk/APSCpp/cmakelists.txt (rev 0)
+++ autopano-sift-C/trunk/APSCpp/cmakelists.txt 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,7 @@
+#cmakelists.txt for subdirectory APSCpp
+#note executable is named autopano-sift-c, as Pablo prefers it
+
+add_executable(autopano-sift-c APSCpp_main.c APSCpp.c CamLens.c HermiteSpline.c saInterp.c saRemap.c )
+TARGET_LINK_LIBRARIES(autopano-sift-c ${all_libs})
+install(TARGETS autopano-sift-c DESTINATION bin)
+install(FILES README-autopano-sift-c.txt DESTINATION . )
\ No newline at end of file
Added: autopano-sift-C/trunk/APSCpp/saInterp.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/saInterp.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/saInterp.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,299 @@
+/* saInterp.c 17 Feb 2008 TKS
+
+ interpolation engine for SphereAlign,
+ specialized from Dersch's panotools code.
+
+ The setup routine is independent of pixel data type,
+ but you have to call a typed interpolator.
+
+ The interpolation kernel.is chosen at compile time,
+ default is 6x6 spline.
+
+ Optional source masks are separate byte arrays.
+
+ Source may be a contiguous array (src -> data[xdim*ydim])
+ or a vector of rows (src[y] -> data[xdim])
+ or a vector of columns (src[x] -> data[ydim])
+
+ Mask array must be contiguous,
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <math.h>
+
+/* point interpolation engines
+
+ computes one pixel of a destination image given the corresponding
+ position in the source image, handling image edges and an optional
+ mask. Can treat the source image as cylindrical in X.
+
+ The position is given in source index units relative to the lowest
+ addressed pixel of the source image.
+
+ Return 1 if position is inside [masked] source, with destination
+ pixel set to interpolated value, else 0 with destination pixel 0.
+
+*/
+
+// interpolator is SPLINE36 (can change here)
+#define ndim 6
+#define intpol( x, a, NDIM ) \
+ a[5] = ( ( - 1.0/11.0 * x + 12.0/ 209.0 ) * x + 7.0/ 209.0 ) * x; \
+ a[4] = ( ( 6.0/11.0 * x - 72.0/ 209.0 ) * x - 42.0/ 209.0 ) * x; \
+ a[3] = ( ( - 13.0/11.0 * x + 288.0/ 209.0 ) * x + 168.0/ 209.0 ) * x; \
+ a[2] = ( ( 13.0/11.0 * x - 453.0/ 209.0 ) * x - 3.0/ 209.0 ) * x + 1.0; \
+ a[1] = ( ( - 6.0/11.0 * x + 270.0/ 209.0 ) * x - 156.0/ 209.0 ) * x; \
+ a[0] = ( ( 1.0/11.0 * x - 45.0/ 209.0 ) * x + 26.0/ 209.0 ) * x;
+
+
+/** constant parameters posted by InterpSetup() **/
+static char
+ * mask = 0, // source mask array, 0 if none
+ wrap_x = 0; // source width is 360 degrees
+static void
+ * csrc = 0, // contiguous source array
+ ** vsrc = 0; // source array of row vectors
+static int
+ srcwid, // source dimensions..
+ srchgt,
+ srcspp,
+ srcppr,
+ srcvfmt;
+static int // mask...
+ smrowlen, // bytes per row
+ smitemlen, // bytes per pixel
+ smidx; // byte within pixel
+
+/** Set up constant interpolation parameters **/
+// retun 0 fail 1 success
+
+int saInterpSetup( void * psrc, // -> data or pointers
+ int vfmt, // 0 contig 1 row vectors 2 col vectors
+ int wid, // valid pixels per row
+ int hgt, // valid rows
+ int spp, // samples per pixel (>0)
+ int ppr, // actual pixels per row (>=wid)
+ char wrap, // true is X is cyclic
+ char * pmask, // -> mask array, 0 if no mask
+ int mspp, // mask samples per pixel
+ int mppr, // actual pixels per row (>= wid)
+ int midx // index of mask byte in pixel
+ )
+
+{
+ csrc = 0; vsrc = 0;
+ switch( vfmt ){
+ case 0: // contig
+ csrc = psrc;
+ break;
+ case 1:
+ case 2:
+ vsrc = (void **)psrc;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ srcvfmt = vfmt;
+
+ srcwid = wid; srchgt = hgt;
+ srcspp = spp; srcppr = ppr;
+ wrap_x = wrap;
+
+ mask = pmask;
+ smrowlen = mppr * mspp;
+ smitemlen = mspp;
+ smidx = midx;
+
+ return 1;
+}
+
+/** Compute one interpolated pixel **/
+/* started as Dersch code, now heavily modified to handle
+ vector as well as contiguous source formats.
+*/
+
+int saInterp_float( float * pdest, // -> destination pixel
+ double Xpos, double Ypos
+ )
+{
+// working vars
+ static float *row[ndim];
+ static float cdata[ndim * ndim];
+
+ int i, k, xs, ys, valid;
+ int n2 = ndim / 2;
+ double Dx, Dy;
+
+// integer parts of dest posn in src
+ int xc = (int)floor( Xpos ) ;
+ int yc = (int)floor( Ypos ) ;
+
+// fail if 0 or 2 sources
+ if(!csrc && !vsrc ) return 0;
+ if( csrc && vsrc ) return 0;
+
+// test if posn is within source image
+ valid = (xc < srcwid )
+ && (yc < srchgt )
+ && (xc >= 0) && (yc >= 0);
+
+// check source mask if used
+ if( valid && mask ){
+ valid = ( mask [ yc * smrowlen
+ + xc * smitemlen
+ + smidx ]
+ != 0 );
+ }
+// done if position is outside source
+ if( !valid ){
+ *pdest = 0;
+ return 0;
+ }
+
+ ys = yc + 1 - n2 ; // smallest y-index used for interpolation
+ xs = xc + 1 - n2 ; // smallest x-index used for interpolation
+
+ if( srcvfmt < 2 ){ // contig. or row vector format...
+ // fractions
+ Dx = Xpos - (double) xc;
+ Dy = Ypos - (double) yc;
+
+ // k = number of cols outside the row, sign idicates end
+ if( xs < 0 ) k = xs; // - at left
+ else {
+ k = xs + ndim - srcwid; // + at right
+ if( k < 0 ) k = 0; // all inside
+ }
+
+ // scan rows
+ for( i = 0; i < ndim; i++ ){
+ register float * pr;
+ register int j;
+
+ // set pr = pointer to a real row
+ j = ys + i;
+ if( j < 0 ) j = 0;
+ else if( j >= srchgt ) j = srchgt - 1;
+ // choose source pointer
+ if( csrc ) pr = (float *) csrc + srcwid * j;
+ else pr = (float *) vsrc[j];
+
+ // set row[i] = pointer to real data
+ if( k == 0 ) row[i] = pr + xs; // region is in source
+ else { // must copy region to cdata...
+ register float * pc = &cdata[i];
+ row[i] = pc;
+ if( wrap_x ){ // copy both ends of row
+ register int l = k;
+ if( l > 0 ) l -= ndim;
+ j = ndim + l;
+ for( ; l < 0; l++ ) *pc++ = pr[l+srcwid];
+ for( ; l < j; l++ ) *pc++ = pr[l];
+ } else { // copy one end of row,,,
+ register int l = k;
+ if( l < 0 ){
+ j = ndim + l;
+ for( ; l < 0; l++ ) *pc++ = *pr;
+ for( ; j > 0; j-- ) *pc++ = *pr++;
+ } else {
+ j = ndim - l;
+ pr += srcwid - j;
+ for( ; j > 0; j-- ) *pc++ = *pr++;
+ --pr;
+ for( ; l > 0; l-- ) *pc++ = *pr;
+ }
+ }
+ }
+ }
+ } else { // col vector format
+ // fractions transposed
+ Dy = Xpos - (double) xc;
+ Dx = Ypos - (double) yc;
+ // k = number of rows outside the col, sign idicates end
+ if( ys < 0 ) k = ys; // - at top
+ else {
+ k = ys + ndim - srchgt; // + at bottom
+ if( k < 0 ) k = 0; // all inside
+ }
+
+ // scan cols
+ for( i = 0; i < ndim; i++ ){
+ register float * pc;
+ register int j;
+
+ // set pc = pointer to a real col
+ j = xs + i;
+ if( j < 0 ){
+ if( !wrap_x ) j = 0;
+ else j += srcwid;
+ }
+ else if( j >= srcwid ) {
+ if( wrap_x ) j -= srcwid;
+ else j = srcwid - 1;
+ }
+ pc = (float *) vsrc[j];
+
+ // set row[i] = pointer to real data
+ if( k == 0 ) row[i] = pc + ys; // region is in source
+ else { // must copy region to cdata...
+ register float * p = &cdata[i];
+ register int l = k;
+ row[i] = p;
+ if( l < 0 ){
+ j = ndim + l;
+ for( ; l < 0; l++ ) *p++ = *pc;
+ for( ; j > 0; j-- ) *p++ = *pc++;
+ } else {
+ j = ndim - l;
+ pc += srchgt - j;
+ for( ; j > 0; j-- ) *p++ = *pc++;
+ --pc;
+ for( ; l > 0; l-- ) *p++ = *pc;
+ }
+ }
+ }
+ Dy = Xpos - (double) xc; // note transposed
+ Dx = Ypos - (double) yc;
+ }
+
+ // interpolate
+ {
+ static double yr[ndim], wx[ndim], wy[ndim];
+ register double rd;
+ register int k,i;
+
+ intpol( Dx, wx, ndim )
+
+ for( k = 0; k < ndim; k++ ){
+ yr[k] = row[k][0] * wx[0];
+ for(i=1; i<ndim; i++) yr[k] += row[k][i] * wx[i];
+ }
+
+ intpol( Dy, wy, ndim )
+
+ rd = yr[0] * wy[0];
+ for( i = 1; i < ndim; i++ ) rd += yr[i] * wy[i];
+
+ *pdest = (float)rd;
+ }
+
+ return 1;
+}
Added: autopano-sift-C/trunk/APSCpp/saInterp.h
===================================================================
--- autopano-sift-C/trunk/APSCpp/saInterp.h (rev 0)
+++ autopano-sift-C/trunk/APSCpp/saInterp.h 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,75 @@
+/* saInterp.h
+
+ interpolation engines for SphereAlign,
+ specialized from Dersch's panotools code.
+
+ Source may a contiguous array.or a vector of pointers
+ to rows. It may be treated as cylindrical in X.
+
+ The optional mask must be a contiguous array (treated as
+ a packed array of bytes). It may be stored with the
+ source if type is compatible, or can be separate. Only
+ one byte of mask is tested per pixel, and only one bit
+ of information is used: zero (out) or nonzero (in).
+
+ InterpSetup() posts constant info on the source and mask.
+ There are two source pointers, one for a contiguous source
+ and one for a vector source -- the "wrong" one must be 0.
+ Source pointers are untyped; you have to call the right
+ interpolator for the actual pixel type --
+
+ saInterp_float() -- one float value per pixel
+ saInterp_short() -- packed signed short
+ saInterp_byte() -- packed unsigned char
+
+ The interpolators set one destination pixel per call. If the given
+ position (index units) is inside the (masked) source they return 1,
+ otherwise 0 with the destination pixel set to 0.
+
+ Interpolators that can handle packed source pixels also take a sample
+ index. However the destination pointer is always absolute.
+
+ Uses only one interpolation kernel, the 6x6 spline
+ (you could change that at compile time).
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _SAINTERP_H
+#define _SAINTERP_H
+
+int saInterpSetup( void * ps, // -> source data or pointers
+ int vfmt, // 0: contig 1: row vector 2: col vector
+ int wid, // valid pixels per row
+ int hgt, // valid rows
+ int spp, // samples per pixel (>0)
+ int ppr, // actual pixels per row (>=wid)
+ char wrap, // true is X is cyclic
+ char * pmask, // -> mask array, 0 if no mask
+ int mspp, // mask samples per pixel
+ int mppr, // actual pixels per row (>= wid)
+ int midx // index of mask byte in pixel
+ );
+
+int saInterp_float( float * pdest,
+ double Xpos, double Ypos
+ );
+
+
+#endif //ndef _SAINTERP_H
+
Added: autopano-sift-C/trunk/APSCpp/saRemap.c
===================================================================
--- autopano-sift-C/trunk/APSCpp/saRemap.c (rev 0)
+++ autopano-sift-C/trunk/APSCpp/saRemap.c 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,179 @@
+/* saRemap.c 19 feb 2008 TKS
+
+ Coordinate mapping for interconverting image
+ projections that involve a lens.
+
+ Both 'source' and 'destination' projections can be
+ elliptical, with independent aspect ratios.
+
+ A CamLens struct supplies lens parameters for the
+ 'source' projection. The 'destination' projection
+ is the ideal one associated with a PT format code
+ (except that it may be elliptical).
+
+ Each image has an origin, which is the position of
+ the projection center in raster coordinates. A pair
+ of "FL's in pixels" sets the magnification and
+ aspect ratio of the destination image (imagine an
+ intermediate spherical projection).
+
+ The radial remapping function is tabulated as a
+ cubic spline. In practical cases this will be
+ monotonic, so its inverse is tabulated too. Then
+ coordinates can be remapped in either direction.
+
+ The range of tabulated source radii is 0 thru the
+ Rmax of the source CamLens; so only points inside
+ that circle can be remapped.
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include "sphereAlign.h"
+#include "HermiteSpline.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#define SARM_NPTS 50;
+
+saRemap * saRemap_new0( void ){
+ saRemap * p = (saRemap *)malloc(sizeof(saRemap));
+ if( p ){
+ p->npts = 0; // mark empty
+ p->xval = p->yval = 0; // no arrays..
+ p->Cxy = p->Cyx = 0;
+ }
+ return p;
+}
+
+void saRemap_delete( saRemap *p ){
+ if( p ){
+ if( p->npts ){
+ if(p->xval) free(p->xval); // does yval too
+ if(p->Cxy) free(p->Cxy);
+ if(p->Cyx) free(p->Cyx);
+ }
+ free( p );
+ }
+}
+
+
+saRemap * saRemap_new( CamLens * ps, CamLens * pd )
+{
+ saRemap * p = saRemap_new0();
+ if( p ){
+ p->sX0 = ps->hCpix;
+ p->sY0 = ps->vCpix;
+ p->sFx = ps->hFLpix;
+ p->sFy = ps->vFLpix;
+ p->dX0 = pd->hCpix;
+ p->dY0 = pd->vCpix;
+ p->dFx = pd->hFLpix;
+ p->dFy = pd->vFLpix;
+
+ // create the table
+ p->npts = SARM_NPTS;
+ p->xval = (double *)malloc(2 * p->npts * sizeof(double));
+ p->yval = p->xval + p->npts;
+ // tabulate source radius mapping function
+ { int i;
+ double * x = p->xval,
+ * y = p->yval,
+ * t = (double *)malloc(p->npts * sizeof(double));
+ // tabulate the radial function
+ double s = CamLens_Rmax( ps ) / (p->npts - 1);
+ for( i = 0; i < p->npts; i++ ){
+ x[i] = i * s;
+ y[i] = CamLens_RofA( pd, CamLens_AofR( ps, x[i] ) );
+ }
+
+ // set up spline table
+ // tangents for forward spline
+ i = spline_tangents_set( p->npts, x, y, t );
+ // fail if y is not monotonic
+ if( i != 1 ){
+ saRemap_delete( p );
+ return 0;
+ }
+ // coefficients for forward spline
+ p->Cxy = spline_hermite_set ( p->npts, x, y, t );
+ // tangents for inverse spline
+ i = spline_tangents_set( p->npts, y, x, t );
+ // coefficients for inverse spline
+ p->Cyx = spline_hermite_set ( p->npts, y, x, t );
+
+ free( t);
+ }
+
+ }
+ return p;
+}
+
+
+/* convert pixel coordinates
+ if fn is not defined at the given input point,
+ return 0 with output = (0,0)
+ Note "non-lens" coordinates just shift to new origin
+*/
+int saRemap_fwd ( saRemap *p,
+ double xsrc, double ysrc,
+ double *xdest, double *ydest )
+{ double dx, dy, x = 0, y = 0;
+ double r, R;
+ *xdest = *ydest = 0;
+ if( p->npts < 2 || p->Cxy == 0 ) return 0;
+ // center
+ dx = xsrc - p->sX0;
+ dy = ysrc - p->sY0;
+ // normalize
+ x = dx / p->sFx;
+ y = dy / p->sFy;
+ // convert radius
+ r = sqrt( x * x + y * y );
+ if(!spline_hermite_val ( p->npts, p->xval, p->Cxy, r, &R, 0 )) return 0;
+ // post result
+ if( r ) R /= r;
+ *xdest = x * R * p->dFx + p->dX0;
+ *ydest = y * R * p->dFy + p->dY0;
+
+ return 1;
+}
+
+int saRemap_inv ( saRemap *p,
+ double xdest, double ydest,
+ double *xsrc, double *ysrc )
+{ double dx, dy, x, y;
+ double r, R;
+ *xsrc = *ysrc = 0;
+ if( p->npts < 2 || p->Cyx == 0 ) return 0;
+
+ dx = xdest - p->dX0;
+ dy = ydest - p->dY0;
+ x = dx / p->dFx;
+ y = dy / p->dFy;
+
+ r = sqrt( x * x + y * y );
+ if(!spline_hermite_val ( p->npts, p->yval, p->Cyx, r, &R, 0 )) return 0;
+ if(r) R /= r;
+ *xsrc = x * R * p->sFx + p->sX0;
+ *ysrc = y * R * p->sFy + p->sY0;
+
+ return 1;
+}
Added: autopano-sift-C/trunk/APSCpp/sphereAlign.h
===================================================================
--- autopano-sift-C/trunk/APSCpp/sphereAlign.h (rev 0)
+++ autopano-sift-C/trunk/APSCpp/sphereAlign.h 2008-03-01 02:58:39 UTC (rev 2914)
@@ -0,0 +1,260 @@
+/* sphereAlign.h 14 Feb 2008 TKS
+
+ declarations for a spherical image alignment program built on
+ the autopano-sift-c code base.
+
+ copyright (c) 2008 TKSharpless. Use freely under GPL license terms.
+
+ N.B. include Panorama.h (or AutoPanoSift.h), if used, before this file
+
+*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _SPHEREALIGN_H
+#define _SPHEREALIGN_H
+
+////#include "pano13\panorama.h"
+#ifndef PANORAMA_H
+enum
+{ // Enumerates for Image.format
+ _rectilinear = 0,
+ _panorama = 1,
+ _fisheye_circ = 2,
+ _fisheye_ff = 3,
+ _equirectangular = 4,
+ _spherical_cp = 5,
+ _spherical_tp = 6,
+ _mirror = 7,
+ _orthographic = 8,
+ _cubic = 9,
+ _stereographic = 10,
+ _mercator = 11,
+ _trans_mercator = 12,
+ _trans_panorama = 13,
+ _sinusoidal = 14,
+ _lambert = 15,
+ _lambertazimuthal = 16,
+ _albersequalareaconic = 17,
+ _millercylindrical = 18,
+};
+#endif //ndef PANORAMA_H
+
+#ifndef Pi
+ #define Pi 3.1415926535897932384626433832795
+ #define DEG2RAD( x ) ((x) * Pi/180.0 )
+ #define RAD2DEG( x ) ((x) * 180.0 / Pi )
+#endif
+
+/* A minimal 'universal' desriptor for images in memory
+*/
+typedef struct MemImageDescr {
+ int ID; // search key
+ void * data; // -> primary array, 0 if unallocated
+ int width, height; // raster size
+ int spp, bps; // pixel size
+ // pixel type flags
+ char isSigned, // integer types only
+ isFloat, // HALF or float or double
+ isPacked, // samples of each pixel adjacent
+ alphaPos; // 0: none, else 1-origin index of alpha channel
+ // if < 0, alpha is in the image at pNext
+ // pointer to another image
+ struct MemImageDescr * pNext; // 0 if none
+} MemImageDescr, *pMemImageDescr;
+
+/* MemImageDescr methods
+*/
+pMemImageDescr MemImageDescr_new0();
+pMemImageDescr MemImageDescr_delete();
+// create with data from a PT Image
+//pMemImageDescr MemImageDescr_newImage( int ID, Image * pi );
+
+ /** database records **/
+
+typedef struct LensInfo {
+ char * name;
+ double FLmm;
+ int radialFn; // 0: ?? 1: tan(a) 2: 2sin(a/2) 3: sin(a) 4: (a)
+ double Klens; // projection function parameter
+ double c[3]; // correction polynomial coeffs (x = r^2/FL^2)
+} LensInfo, * pLensInfo;
+
+typedef struct CameraInfo {
+ char * name;
+ int PT_fmt; // codes defined in panorama.h
+ int widpix, hgtpix;
+ double widmm, hgtmm;
+} CameraInfo, * pCameraInfo;
+
+
+/* Projection data for input images
+
+ In all fields except PT_fmt, zero unambiguously means "unspecified".
+
+ Strictly speaking an image projection is given by an instance of
+ mounting a given lens on a given camera, as mechanical alignment
+ may change a little. So there should be one of these per "mount".
+
+ To accomodate panoramic cameras (and computed panoramas, anamorphic
+ lenses, cheesy cameras with nonsquare pixels, etc) there are separate
+ horizontal and vertical projection functions, both of which must be
+ specified in all cases, even if they are the same.
+
+ We distinguish projection functions of real lens from projection
+ functions generated by other means (gears, computer, ...). Real
+ lens functions are subject to empirical correction, the others are
+ assumed to be ideal. The primary means of making this distinction is
+ whether a physical focal length and sensor size are given, or not; but
+ some code just tests whether the lens parameters, hKlens and vKlens are
+ nonzero or zero.
+
+ For ideal projections, a FL in pixels must be specified -- it is the
+ scale factor that relates pixel position to angle (think of it as the
+ radius of the panosphere).
+
+ The elliptically symmetric formats, rectilinear, equal-area, spherical,
+ orthographic, stereographic and mirror-ball could in principle have been
+ projected by a lens; and actual lenses exist for all but stereographic.
+ (equal area, orthographic and spherical are ideal "fisheye" projections;
+ most real fisheye lenses approximate the equal-area.) They are easy to
+ interconvert via a one-dimensional remapping of the radius.
+
+ Assymetric formats may have a lens projection on one axis only. For
+ example, a rotating slit camera with a rectilinear lens makes quasi-
+ cylindrical images, and with a fisheye lens makes quasi-equirectangular
+ ones.
+
+ Klens parametrizes the fisheye lens projections, via the formula
+ radius/FL = Klens * sin( angle / Klens ). The nominal values are 2 for
+ the common equal-area type, 1 for orthographic and 100 for equal-angle
+ (true spherical). Someday it may parametrize rectilinear and/or mirror
+ ball lenses, too; for now set it to 1 for those lens types.
+
+ If Klens is nonzero the correction polynomial also applies, but will have
+ no effect if all 3 coefficients are zero.
+*/
+
+typedef struct CamLens {
+// camera parameters
+ int widpix, hgtpix; // raster dimensions (rqd)
+ double widmm, hgtmm; // sensor size (optional)
+ int PT_fmt; // codes defined in panorama.h, no typedef
+ int lensAxis; // 0: neither 1: X, 2: Y 3: both
+// lens parameters
+ double FLmm; // (0 for ideal projections)
+ double Klens; // parameter of the radius-to-angle fn
+ double (*R2A)( double R, double K ); // radius-to-angle
+ double (*A2R)( double A, double K ); // angle-to-radius
+ double rCorr[3]; // correction polynomial coeffs
+ double Rref; // "unit" radius scales correction poly
+// pixel <=> angle scale factors (usually computed from above)
+ double hFLpix, vFLpix; // pixels per radian,> 0 (both rq'd)
+// "mount" parameters
+ double hCpix, vCpix; // lens center coordinates
+ double Rcrop; // largest valid normalized radius
+} CamLens, * pCamLens;
+
+/* CamLens methods
+ R stands for radius normalized by focal length
+ fmt is a Panotools format code
+ flmm should be 0 for ideal projections, else > 0
+*/
+// create empty
+pCamLens CamLens_new0();
+// create with minimal info
+pCamLens CamLens_new1( int wid, int hgt, int fmt, double flpix, double flmm );
+// create with database info
+pCamLens CamLens_new( pCameraInfo pc, pLensInfo pl );
+// change projection type
+int CamLens_setProjection( pCamLens self, int fmt );
+// normalized radius <=> angle in radians
+double CamLens_AofR( pCamLens self, double R );
+double CamLens_RofA( pCamLens self, double A );
+// max legal normalized radius
+double CamLens_Rmax( pCamLens self ); // get Rcrop = largest valid R
+// get normalized radius of a point in pixel coords
+double CamLens_getR( CamLens *p, double x, double y );
+
+
+/* convert pixel coordinates between elliptically symmetric projections
+
+ Each projection is specified by a CamLens. Only points in
+ the Rmax circles of 'source' projection can be converted.
+
+ For speed, tabulates the radial remapping function.
+
+*/
+typedef struct saRemap {
+// source origin & scale
+ double sX0, sY0; // center
+ double sFx, sFy; // FLs
+// dest origin & scale
+ double dX0, dY0; // center
+ double dFx, dFy; // FLs
+ // function tables
+ int npts;
+ double *xval; // source radius
+ double *yval; // dest radius
+ double *Cxy; // spline for y(x)
+ double *Cyx; // spline for x(y) (0 if not valid)
+} saRemap;
+
+saRemap * saRemap_new0( void );
+void saRemap_delete( saRemap *p );
+
+/* set up a mapping
+ returns NULL if it can't be reaalized
+*/
+saRemap * saRemap_new( CamLens * ps, CamLens * pd );
+
+/* convert pixel coordinates
+ if the mapping is undefined at the given input point,
+ return 0 with output = (0,0)
+ else return 1
+*/
+int saRemap_fwd ( saRemap *p,
+ double xsrc, double ysrc,
+ double *xdest, double *ydest
+ );
+int saRemap_inv ( saRemap *p,
+ double xdest, double ydest,
+ double *xsrc, double *ysrc
+ );
+
+/* minimal image info for APSC++
+ source is project file 'i' lines
+ (LoadProjectImages() reads this)
+*/
+typedef struct DIinfo {
+ // 'i' line input
+ char name[262];
+ int width, height;
+ int format;
+ double hfov;
+ double yaw, pitch, roll;
+} DIinfo, * pDIinfo;
+
+// create empty
+pDIinfo DIinfo_new0();
+// delete
+void DIinfo_delete( pDIinfo self );
+// set up remapping once basic info is read
+int DIinfo_setRm( pDIinfo self );
+
+
+#endif // ndef _SPHEREALIGN_H
Modified: autopano-sift-C/trunk/AutoPanoSift.h
===================================================================
--- autopano-sift-C/trunk/AutoPanoSift.h 2008-03-01 01:45:53 UTC (rev 2913)
+++ autopano-sift-C/trunk/AutoPanoSift.h 2008-03-01 02:58:39 UTC (rev 2914)
@@ -37,6 +37,7 @@
#include "pano12/panorama.h"
#endif
#include "math.h"
+
#ifdef __cplusplus
}
#endif
@@ -73,6 +74,9 @@
int** IntMap_new(int xDim, int yDim);
void IntMap_delete(int** self);
+float** FloatMap_new(int xDim, int yDim);
+void FloatMap_delete(float** self);
+
double** DoubleMap_new(int xDim, int yDim);
void DoubleMap_delete(double** self);
@@ -261,7 +265,7 @@
struct ImageMap {
int xDim;
int yDim;
- double** values;
+ float** values;
};
typedef struct ImageMap ImageMap;
@@ -280,7 +284,7 @@
ImageMap* ImageMap_ScaleDouble(ImageMap* self);
ImageMap* ImageMap_ScaleHalf(ImageMap* self);
ImageMap* ImageMap_GaussianConvolution(ImageMap* self, double);
-void ImageMap_SetPixel(ImageMap* self, int x, int y, double val);
+void ImageMap_SetPixel(ImageMap* self, int x, int y, float val);
double ImageMap_GetPixel(ImageMap* self, int x, int y);
ImageMap* ImageMap_Add(ImageMap* f1, ImageMap* f2);
ImageMap* ImageMap_Sub(ImageMap* f1, ImageMap* f2);
@@ -540,6 +544,7 @@
void LoweFeatureDetector_SetPrintWarning(bool value);
void LoweFeatureDetector_SetVerbose(bool value);
+double LoweFeatureDetector_SetPreprocSigma( double newsigma );
LoweFeatureDetector* LoweFeatureDetector_new0();
void LoweFeatureDetector_delete(LoweFeatureDetector* );
Modified: autopano-sift-C/trunk/CMakeLists.txt
===================================================================
--- autopano-sift-C/trunk/CMakeLists.txt 2008-03-01 01:45:53 UTC (rev 2913)
+++ autopano-sift-C/trunk/CMakeLists.txt 2008-03-01 02:58:39 UTC (rev 2914)
@@ -1,200 +1,204 @@
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules )
-
-## global setup
-project(autopano-sift-C)
-
-# version
-set(V_MAJOR 2)
-set(V_MINOR 4)
-set(V_PATCH 1)
-set(PACKAGE_VERSION ${V_MAJOR}.${V_MINOR}.${V_PATCH})
-
-IF (WIN32)
- # install into place in build-dir
- SET( CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/INSTALL/FILES CACHE FILEPATH "install prefix" FORCE)
-
- ##
- ## The directory that contains the hugin source root is a good
- ## place to look for support packages, so post it in cache.
- ##
- ## Our FIND_PACKAGE calls modules will search SOURCE_BASE_DIR
- ## after the local standard places
- ##
- # extract pathname from CMAKE_SOURCE_DIR (note result must be a local var)
- STRING( REGEX REPLACE "(.*)/[^/]+$" "\\1" work "${CMAKE_SOURCE_DIR}" )
- # create the cache entry
- SET( SOURCE_BASE_DIR ${work} CACHE FILEPATH "parent dir of hugin source root" )
-
- # look in wxWidgets distribution for depending packages.
- SET(wxWidgets_LIB_DIR ${SOURCE_BASE_DIR}/wxMSW-2.8.7/lib/vc_lib)
- SET(wxWidgets_ROOT_DIR ${SOURCE_BASE_DIR}/wxMSW-2.8.7)
-ENDIF(WIN32)
-
-##
-## Graphics libraries
-##
-# wxWidgets sub-packages will be used if native ones aren't found
-
-FIND_PACKAGE(TIFF REQUIRED)
-INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
-FIND_PACKAGE(JPEG REQUIRED)
-INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
-FIND_PACKAGE(PNG REQUIRED)
-INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
-INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
-
-##
-## XML library
-##
-FIND_PACKAGE(LibXml2 REQUIRED)
-ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})
-INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
-
-##
-## Panotools
-##
-
-FIND_PACKAGE(PANO13 REQUIRED)
-INCLUDE_DIRECTORIES(${PANO13_INCLUDE_DIR})
-
-
-#BUILD SETUP
-IF(NOT CMAKE_BUILD_TYPE)
- SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
- "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
- FORCE)
-ENDIF(NOT CMAKE_BUILD_TYPE)
-
-IF(UNIX)
- ADD_DEFINITIONS(-Wall)
- ADD_DEFINITIONS(-DHAS_PANO13)
-ENDIF(UNIX)
-
-IF(APPLE)
- SET(HAVE_MALLOC 1)
-ENDIF(APPLE)
-
-# Setup MSVC
-IF (MSVC)
- # Stop MSVC8 from bitching about the C library
- ADD_DEFINITIONS(/D_CRT_SECURE_NO_DEPRECATE)
- # Stop MSVC9 from bitching about possibly invalid STL usage
- ADD_DEFINITIONS(/D_SCL_SECURE_NO_WARNINGS)
- # Stop MSVC9 from bitching about POSIX names without underscores
- ADD_DEFINITIONS(/D_CRT_NONSTDC_NO_DEPRECATE)
- # compile everything for the static C runtime
- STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
- STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
- STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL})
- STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
- STRING(REPLACE /MD /MT CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
- STRING(REPLACE /MD /MT CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
- STRING(REPLACE /MD /MT CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL})
- STRING(REPLACE /MD /MT CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO})
-
- # compile as C code as C++ code, required to enable
- # variable declarations between statements.
- ADD_DEFINITIONS(/TP)
-
- # yes we DO have pano13
- ADD_DEFINITIONS( /DHAS_PANO13 )
-
-ENDIF(MSVC)
-
-# create config.h file
-configure_file(config.h.in.cmake ${CMAKE_BINARY_DIR}/config.h)
-INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
-
-##
-## Finally, rules to build the source code!
-##
-
-SET(LIBSIFT_SOURCES LoweDetector.c RANSAC.c GaussianConvolution.c
- ScaleSpace.c KeypointXML.c MatchKeys.c KDTree.c BondBall.c
- AreaFilter.c ImageMatchModel.c Transform.c DisplayImage.c ImageMap.c
- HashTable.c ArrayList.c Random.c SimpleMatrix.c Utils.c)
-
-ADD_LIBRARY(libsift STATIC ${LIBSIFT_SOURCES})
-
-set(all_libs libsift ${JPEG_LIBRARIES} ${TIFF_LIBRARIES}
- ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${PANO13_LIBRARIES} ${LIBXML2_LIBRARIES})
-
-add_executable(generatekeys GenerateKeys.c)
-TARGET_LINK_LIBRARIES(generatekeys ${all_libs})
-
-add_executable(autopano AutoPano.c)
-TARGET_LINK_LIBRARIES(autopano ${all_libs})
-
-add_executable(autopano-sift-c APSCmain.c)
-TARGET_LINK_LIBRARIES(autopano-sift-c ${all_libs})
-
-install(TARGETS generatekeys autopano DESTINATION bin)
-install(TARGETS autopano-sift-c DESTINATION bin)
-if (WIN32)
-else (WIN32)
- install(PROGRAMS autopano-c-complete.sh DESTINATION bin)
-endif (WIN32)
-
-
-# man pages
-FILE(GLOB MAN_PAGES_1 doc/*.1)
-FILE(GLOB MAN_PAGES_7 doc/*.7)
-install(FILES ${MAN_PAGES_1} DESTINATION share/man/man1)
-install(FILES ${MAN_PAGES_7} DESTINATION share/man/man7)
-
-## Test exectuables.
-
-if (BUILD_TESTS)
- add_executable(testArray TestArray.c)
- TARGET_LINK_LIBRARIES(testArray ${all_libs})
- add_executable(testRandom TestRandom.c)
- TARGET_LINK_LIBRARIES(testRandom ${all_libs})
-#add_executable(testSimpleMatrix TestSimpleMatrix.c)
-#TARGET_LINK_LIBRARIES(testSimpleMatrix ${all_libs})
-#add_executable(testTransform TestTransform.c)
-#TARGET_LINK_LIBRARIES(testTransform ${all_libs})
-#add_executable(testRansac TestRansac.c)
-#TARGET_LINK_LIBRARIES(testRansac ${all_libs})
-#add_executable(testAreaFilter TestAreaFilter.c)
-#TARGET_LINK_LIBRARIES(testAreaFilter ${all_libs})
- add_executable(testKDTree TestKDTree.c)
- TARGET_LINK_LIBRARIES(testKDTree ${all_libs})
-endif(BUILD_TESTS)
-
-
-SET(CPACK_PACKAGE_VERSION_MAJOR "${V_MAJOR}")
-SET(CPACK_PACKAGE_VERSION_MINOR "${V_MINOR}")
-SET(CPACK_PACKAGE_VERSION_PATCH "${V_PATCH}")
-SET(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${V_MAJOR}.${V_MINOR}")
-SET(CPACK_SOURCE_PACKAGE_FILE_NAME "autopano-sift-C-${V_MAJOR}.${V_MINOR}.${V_PATCH}")
-SET(CPACK_SOURCE_GENERATOR "TGZ")
-SET(CPACK_SOURCE_IGNORE_FILES
-"/autopano$"
-"/generatekeys$"
-"/autopano-sift-c$"
-"/Makefile$"
-"/_CPack_Packages/"
-"/CMakeCache.txt$"
-"\\\\.dir/"
-"\\\\.tar\\\\.gz$"
-"\\\\.tar\\\\.Z$"
-"\\\\.svn/"
-"\\\\.cvsignore$"
-"\\\\.swp$"
-"~$"
-"\\\\.#"
-"/#"
-"/build/"
-"/CVS/"
-"/\\\\.libs/"
-"/\\\\.deps/"
-"\\\\.o$"
-"\\\\.a$"
-"\\\\.lo$"
-"\\\\.so$"
-"\\\\.so\\\\.0$"
-"\\\\.so\\\\.0\\\\.0$"
-"\\\\.la$"
-"Makefile\\\\.in$"
- )
-INCLUDE(CPack)
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules )
+
+## global setup
+project(autopano-sift-C)
+
+# version
+set(V_MAJOR 2)
+set(V_MINOR 4)
+set(V_PATCH 1)
+set(PACKAGE_VERSION ${V_MAJOR}.${V_MINOR}.${V_PATCH})
+
+IF (WIN32)
+ # install into place in build-dir
+ SET( CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/INSTALL/FILES CACHE FILEPATH "install prefix" FORCE)
+
+ ##
+ ## The directory that contains the hugin source root is a good
+ ## place to look for support packages, so post it in cache.
+ ##
+ ## Our FIND_PACKAGE calls modules will search SOURCE_BASE_DIR
+ ## after the local standard places
+ ##
+ # extract pathname from CMAKE_SOURCE_DIR (note result must be a local var)
+ STRING( REGEX REPLACE "(.*)/[^/]+$" "\\1" work "${CMAKE_SOURCE_DIR}" )
+ # create the cache entry
+ SET( SOURCE_BASE_DIR ${work} CACHE FILEPATH "parent dir of hugin source root" )
+
+ # look in wxWidgets distribution for depending packages.
+ SET(wxWidgets_LIB_DIR ${SOURCE_BASE_DIR}/wxMSW-2.8.7/lib/vc_lib)
+ SET(wxWidgets_ROOT_DIR ${SOURCE_BASE_DIR}/wxMSW-2.8.7)
+ENDIF(WIN32)
+
+##
+## Graphics libraries
+##
+# wxWidgets sub-packages will be used if native ones aren't found
+
+FIND_PACKAGE(TIFF REQUIRED)
+INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
+FIND_PACKAGE(JPEG REQUIRED)
+INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
+FIND_PACKAGE(PNG REQUIRED)
+INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
+
+##
+## XML library
+##
+FIND_PACKAGE(LibXml2 REQUIRED)
+ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})
+INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
+
+##
+## Panotools
+##
+
+FIND_PACKAGE(PANO13 REQUIRED)
+INCLUDE_DIRECTORIES(${PANO13_INCLUDE_DIR})
+
+# now there is a source code in a subdirectory
+# so put this one on the include search list
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
+
+#BUILD SETUP
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+ FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+IF(UNIX)
+ ADD_DEFINITIONS(-Wall)
+ ADD_DEFINITIONS(-DHAS_PANO13)
+ENDIF(UNIX)
+
+IF(APPLE)
+ SET(HAVE_MALLOC 1)
+ENDIF(APPLE)
+
+# Setup MSVC
+IF (MSVC)
+ # Stop MSVC8 from bitching about the C library
+ ADD_DEFINITIONS(/D_CRT_SECURE_NO_DEPRECATE)
+ # Stop MSVC9 from bitching about possibly invalid STL usage
+ ADD_DEFINITIONS(/D_SCL_SECURE_NO_WARNINGS)
+ # Stop MSVC9 from bitching about POSIX names without underscores
+ ADD_DEFINITIONS(/D_CRT_NONSTDC_NO_DEPRECATE)
+ # compile everything for the static C runtime
+ STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
+ STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
+ STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL})
+ STRING(REPLACE /MD /MT CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
+ STRING(REPLACE /MD /MT CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
+ STRING(REPLACE /MD /MT CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+ STRING(REPLACE /MD /MT CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL})
+ STRING(REPLACE /MD /MT CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO})
+
+ # compile C code as C++ code. Allows variable declarations between statements,
+ # but CAUTION breaks modules whose headers declare them with extern "C"{}
+ ADD_DEFINITIONS(/TP)
+
+ # yes we DO have pano13
+ ADD_DEFINITIONS( /DHAS_PANO13 )
+
+ENDIF(MSVC)
+
+# create config.h file
+configure_file(config.h.in.cmake ${CMAKE_BINARY_DIR}/config.h)
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
+
+##
+## Finally, rules to build the source code!
+##
+
+SET(LIBSIFT_SOURCES LoweDetector.c RANSAC.c GaussianConvolution.c
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|