(还没推完公式先贴上matlab和c的代码 from官方文档) 因为官方的shift.m直接跑起来会出问题。我这儿改良了部分代码
% [image, descriptors, locs] = sift(imageFile) % % This function reads an image and returns its SIFT keypoints. % Input parameters: % imageFile: the file name for the image. % % Returned: % image: the image array in double format % descriptors: a K-by-128 matrix, where each row gives an invariant % descriptor for one of the K keypoints. The descriptor is a vector % of 128 values normalized to unit length. % locs: K-by-4 matrix, in which each row has the 4 values for a % keypoint location (row, column, scale, orientation). The % orientation is in the range [-PI, PI] radians. % % Credits: Thanks for initial version of this program to D. Alvaro and % J.J. Guerrero, Universidad de Zaragoza (modified by D. Lowe) function [image, descriptors, locs] = sift(imageFile) % Load image image = imread(imageFile); % If you have the Image Processing Toolbox, you can uncomment the following % lines to allow input of color images, which will be converted to grayscale. %if isrgb(image) image = rgb2gray(image); %end [rows, cols] = size(image); % Convert into PGM imagefile, readable by "keypoints" executable f = fopen('tmp.pgm', 'w'); if f == -1 error('Could not create file tmp.pgm.'); end fprintf(f, 'P5\n%d\n%d\n255\n', cols, rows); fwrite(f, image', 'uint8'); fclose(f); % Call keypoints executable if isunix command = '!./sift '; else command = '!siftWin32 '; end command = [command ' <tmp.pgm >tmp.key']; eval(command); % Open tmp.key and check its header g = fopen('tmp.key', 'r'); if g == -1 error('Could not open file tmp.key.'); end [header, count] = fscanf(g, '%d %d', [1 2]); if count ~= 2 error('Invalid keypoint file beginning.'); end num = header(1); len = header(2); if len ~= 128 error('Keypoint descriptor length invalid (should be 128).'); end % Creates the two output matrices (use known size for efficiency) locs = double(zeros(num, 4)); descriptors = double(zeros(num, 128)); % Parse tmp.key for i = 1:num [vector, count] = fscanf(g, '%f %f %f %f', [1 4]); %row col scale ori if count ~= 4 error('Invalid keypoint file format'); end locs(i, :) = vector(1, :); [descrip, count] = fscanf(g, '%d', [1 len]); if (count ~= 128) error('Invalid keypoint file value.'); end % Normalize each input vector to unit length descrip = descrip / sqrt(sum(descrip.^2)); descriptors(i, :) = descrip(1, :); end fclose(g);
% [image, descriptors, locs] = sift(imageFile) % % This function reads an image and returns its SIFT keypoints. % Input parameters: % imageFile: the file name for the image. % % Returned: % image: the image array in double format % descriptors: a K-by-128 matrix, where each row gives an invariant % descriptor for one of the K keypoints. The descriptor is a vector % of 128 values normalized to unit length. % locs: K-by-4 matrix, in which each row has the 4 values for a % keypoint location (row, column, scale, orientation). The % orientation is in the range [-PI, PI] radians. % % Credits: Thanks for initial version of this program to D. Alvaro and % J.J. Guerrero, Universidad de Zaragoza (modified by D. Lowe) function [image, descriptors, locs] = sift(imageFile) % Load image image = imread(imageFile); % If you have the Image Processing Toolbox, you can uncomment the following % lines to allow input of color images, which will be converted to grayscale. % if isrgb(image) % image = rgb2gray(image); % end [rows, cols] = size(image); % Convert into PGM imagefile, readable by "keypoints" executable f = fopen('tmp.pgm', 'w'); if f == -1 error('Could not create file tmp.pgm.'); end fprintf(f, 'P5\n%d\n%d\n255\n', cols, rows); fwrite(f, image', 'uint8'); fclose(f); % Call keypoints executable if isunix command = '!./sift '; else command = '!siftWin32 '; end command = [command ' <tmp.pgm >tmp.key']; eval(command); % Open tmp.key and check its header g = fopen('tmp.key', 'r'); if g == -1 error('Could not open file tmp.key.'); end [header, count] = fscanf(g, '%d %d', [1 2]); if count ~= 2 error('Invalid keypoint file beginning.'); end num = header(1); len = header(2); if len ~= 128 error('Keypoint descriptor length invalid (should be 128).'); end % Creates the two output matrices (use known size for efficiency) locs = double(zeros(num, 4)); descriptors = double(zeros(num, 128)); % Parse tmp.key for i = 1:num [vector, count] = fscanf(g, '%f %f %f %f', [1 4]); %row col scale ori if count ~= 4 error('Invalid keypoint file format'); end locs(i, :) = vector(1, :); [descrip, count] = fscanf(g, '%d', [1 len]); if (count ~= 128) error('Invalid keypoint file value.'); end % Normalize each input vector to unit length descrip = descrip / sqrt(sum(descrip.^2)); descriptors(i, :) = descrip(1, :); end fclose(g);
% num = match(image1, image2) % % This function reads two images, finds their SIFT features, and % displays lines connecting the matched keypoints. A match is accepted % only if its distance is less than distRatio times the distance to the % second closest match. % It returns the number of matches displayed. % % Example: match('scene.pgm','book.pgm'); function num = match(image1, image2) % Find SIFT keypoints for each image [im1, des1, loc1] = sift(image1); [im2, des2, loc2] = sift(image2); % For efficiency in Matlab, it is cheaper to compute dot products between % unit vectors rather than Euclidean distances. Note that the ratio of % angles (acos of dot products of unit vectors) is a close approximation % to the ratio of Euclidean distances for small angles. % % distRatio: Only keep matches in which the ratio of vector angles from the % nearest to second nearest neighbor is less than distRatio. distRatio = 0.6; % For each descriptor in the first image, select its match to second image. des2t = des2'; % Precompute matrix transpose for i = 1 : size(des1,1) dotprods = des1(i,:) * des2t; % Computes vector of dot products [vals,indx] = sort(acos(dotprods)); % Take inverse cosine and sort results % Check if nearest neighbor has angle less than distRatio times 2nd. if (vals(1) < distRatio * vals(2)) match(i) = indx(1); else match(i) = 0; end end % Create a new image showing the two images side by side. im3 = appendimages(im1,im2); % Show a figure with lines joining the accepted matches. figure('Position', [100 100 size(im3,2) size(im3,1)]); colormap('gray'); imagesc(im3); hold on; cols1 = size(im1,2); for i = 1: size(des1,1) if (match(i) > 0) line([loc1(i,2) loc2(match(i),2)+cols1], ... [loc1(i,1) loc2(match(i),1)], 'Color', 'c'); end end hold off; num = sum(match > 0); fprintf('Found %d matches.\n', num);
% showkeys(image, locs) % % This function displays an image with SIFT keypoints overlayed. % Input parameters: % image: the file name for the image (grayscale) % locs: matrix in which each row gives a keypoint location (row, % column, scale, orientation) function showkeys(image, locs) disp('Drawing SIFT keypoints ...'); % Draw image with keypoints figure('Position', [50 50 size(image,2) size(image,1)]); colormap('gray'); imagesc(image); hold on; imsize = size(image); for i = 1: size(locs,1) % Draw an arrow, each line transformed according to keypoint parameters. TransformLine(imsize, locs(i,:), 0.0, 0.0, 1.0, 0.0); TransformLine(imsize, locs(i,:), 0.85, 0.1, 1.0, 0.0); TransformLine(imsize, locs(i,:), 0.85, -0.1, 1.0, 0.0); end hold off; % ------ Subroutine: TransformLine ------- % Draw the given line in the image, but first translate, rotate, and % scale according to the keypoint parameters. % % Parameters: % Arrays: % imsize = [rows columns] of image % keypoint = [subpixel_row subpixel_column scale orientation] % % Scalars: % x1, y1; begining of vector % x2, y2; ending of vector function TransformLine(imsize, keypoint, x1, y1, x2, y2) % The scaling of the unit length arrow is set to approximately the radius % of the region used to compute the keypoint descriptor. len = 6 * keypoint(3); % Rotate the keypoints by 'ori' = keypoint(4) s = sin(keypoint(4)); c = cos(keypoint(4)); % Apply transform r1 = keypoint(1) - len * (c * y1 + s * x1); c1 = keypoint(2) + len * (- s * y1 + c * x1); r2 = keypoint(1) - len * (c * y2 + s * x2); c2 = keypoint(2) + len * (- s * y2 + c * x2); line([c1 c2], [r1 r2], 'Color', 'c');
/************************************************************************ Demo software: Invariant keypoint matching. Author: David Lowe defs.h: This file contains the headers for a sample program to read images and keypoints, then perform simple keypoint matching. *************************************************************************/ /* From the standard C libaray: */ #include <stdlib.h> #include <math.h> #include <assert.h> #include <stdio.h> #include <string.h> /*------------------------------ Macros ---------------------------------*/ #define ABS(x) (((x) > 0) ? (x) : (-(x))) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #define MIN(x,y) (((x) < (y)) ? (x) : (y)) /*---------------------------- Structures --------------------------------*/ /* Data structure for a float image. */ typedef struct ImageSt { int rows, cols; /* Dimensions of image. */ float **pixels; /* 2D array of image pixels. */ struct ImageSt *next; /* Pointer to next image in sequence. */ } *Image; /* Data structure for a keypoint. Lists of keypoints are linked by the "next" field. */ typedef struct KeypointSt { float row, col; /* Subpixel location of keypoint. */ float scale, ori; /* Scale and orientation (range [-PI,PI]) */ unsigned char *descrip; /* Vector of descriptor values */ struct KeypointSt *next; /* Pointer to next keypoint in list. */ } *Keypoint; /*-------------------------- Function prototypes -------------------------*/ /* These are prototypes for the external functions that are shared between files. */ /* From util.c */ void FatalError(char *fmt, ...); Image CreateImage(int rows, int cols); Image ReadPGMFile(char *filename); Image ReadPGM(FILE *fp); void WritePGM(FILE *fp, Image image); void DrawLine(Image image, int r1, int c1, int r2, int c2); Keypoint ReadKeyFile(char *filename); Keypoint ReadKeys(FILE *fp);
/************************************************************************ Demo software: Invariant keypoint matching. Author: David Lowe match.c: This file contains a sample program to read images and keypoints, then draw lines connecting matched keypoints. *************************************************************************/ #include "defs.h" /* -------------------- Local function prototypes ------------------------ */ void FindMatches(Image im1, Keypoint keys1, Image im2, Keypoint keys2); Keypoint CheckForMatch(Keypoint key, Keypoint klist); int DistSquared(Keypoint k1, Keypoint k2); Image CombineImagesVertically(Image im1, Image im2); /*----------------------------- Routines ----------------------------------*/ /* Top level routine. Read PGM images and keypoints from files given in command line arguments, then call FindMatches. */ int main (int argc, char **argv) { int arg = 0; Image im1 = NULL, im2 = NULL; Keypoint k1 = NULL, k2 = NULL; /* Parse command line arguments and read given files. The command line must specify two input images and two files of keypoints using command line arguments as follows: match -im1 i1.pgm -k1 k1.key -im2 i2.pgm -k2 k2.key > result.v */ while (++arg < argc) { if (! strcmp(argv[arg], "-im1")) im1 = ReadPGMFile(argv[++arg]); else if (! strcmp(argv[arg], "-im2")) im2 = ReadPGMFile(argv[++arg]); else if (! strcmp(argv[arg], "-k1")) k1 = ReadKeyFile(argv[++arg]); else if (! strcmp(argv[arg], "-k2")) k2 = ReadKeyFile(argv[++arg]); else FatalError("Invalid command line argument: %s", argv[arg]); } if (im1 == NULL || im2 == NULL || k1 == NULL || k2 == NULL) FatalError("Command line does not specify all images and keys."); FindMatches(im1, k1, im2, k2); exit(0); } /* Given a pair of images and their keypoints, pick the first keypoint from one image and find its closest match in the second set of keypoints. Then write the result to a file. */ void FindMatches(Image im1, Keypoint keys1, Image im2, Keypoint keys2) { Keypoint k, match; Image result; int count = 0; /* Create a new image that joins the two images vertically. */ result = CombineImagesVertically(im1, im2); /* Match the keys in list keys1 to their best matches in keys2. */ for (k= keys1; k != NULL; k = k->next) { match = CheckForMatch(k, keys2); /* Draw a line on the image from keys1 to match. Note that we must add row count of first image to row position in second so that line ends at correct location in second image. */ if (match != NULL) { count++; DrawLine(result, (int) k->row, (int) k->col, (int) (match->row + im1->rows), (int) match->col); } } /* Write result image to standard output. */ WritePGM(stdout, result); fprintf(stderr,"Found %d matches.\n", count); } /* This searches through the keypoints in klist for the two closest matches to key. If the closest is less than 0.6 times distance to second closest, then return the closest match. Otherwise, return NULL. */ Keypoint CheckForMatch(Keypoint key, Keypoint klist) { int dsq, distsq1 = 100000000, distsq2 = 100000000; Keypoint k, minkey = NULL; /* Find the two closest matches, and put their squared distances in distsq1 and distsq2. */ for (k = klist; k != NULL; k = k->next) { dsq = DistSquared(key, k); if (dsq < distsq1) { distsq2 = distsq1; distsq1 = dsq; minkey = k; } else if (dsq < distsq2) { distsq2 = dsq; } } /* Check whether closest distance is less than 0.6 of second. */ if (10 * 10 * distsq1 < 6 * 6 * distsq2) return minkey; else return NULL; } /* Return squared distance between two keypoint descriptors. */ int DistSquared(Keypoint k1, Keypoint k2) { int i, dif, distsq = 0; unsigned char *pk1, *pk2; pk1 = k1->descrip; pk2 = k2->descrip; for (i = 0; i < 128; i++) { dif = (int) *pk1++ - (int) *pk2++; distsq += dif * dif; } return distsq; } /* Return a new image that contains the two images with im1 above im2. */ Image CombineImagesVertically(Image im1, Image im2) { int rows, cols, r, c; Image result; rows = im1->rows + im2->rows; cols = MAX(im1->cols, im2->cols); result = CreateImage(rows, cols); /* Set all pixels to 0,5, so that blank regions are grey. */ for (r = 0; r < rows; r++) for (c = 0; c < cols; c++) result->pixels[r][c] = 0.5; /* Copy images into result. */ for (r = 0; r < im1->rows; r++) for (c = 0; c < im1->cols; c++) result->pixels[r][c] = im1->pixels[r][c]; for (r = 0; r < im2->rows; r++) for (c = 0; c < im2->cols; c++) result->pixels[r + im1->rows][c] = im2->pixels[r][c]; return result; }
/************************************************************************ Demo software: Invariant keypoint matching. Author: David Lowe util.c: This file contains routines for creating floating point images, reading and writing PGM files, reading keypoint files, and drawing lines on images: Image CreateImage(row,cols) - Create an image data structure. ReadPGM(filep) - Returns list of images read from the PGM format file. WritePGM(filep, image) - Writes an image to a file in PGM format. DrawLine(image, r1,c1,r2,c3) - Draws a white line on the image with the given row, column endpoints. ReadKeyFile(char *filename) - Read file of keypoints. *************************************************************************/ #include "defs.h" #include <stdarg.h> /* -------------------- Local function prototypes ------------------------ */ float **AllocMatrix(int rows, int cols); void SkipComments(FILE *fp); /*------------------------ Error reporting ----------------------------*/ /* This function prints an error message and exits. It takes a variable number of arguments that function just like those in printf. */ void FatalError(char *fmt, ...) { va_list args; va_start(args, fmt); fprintf(stderr, "Error: "); vfprintf(stderr, fmt, args); fprintf(stderr,"\n"); va_end(args); exit(1); } /*----------------- Routines for image creation ------------------------*/ /* Create a new image with uninitialized pixel values. */ Image CreateImage(int rows, int cols) { Image im; im = (Image) malloc(sizeof(struct ImageSt)); im->rows = rows; im->cols = cols; im->pixels = AllocMatrix(rows, cols); im->next = NULL; return im; } /* Allocate memory for a 2D float matrix of size [row,col]. This returns a vector of pointers to the rows of the matrix, so that routines can operate on this without knowing the dimensions. */ float **AllocMatrix(int rows, int cols) { int i; float **m, *v; m = (float **) malloc(rows * sizeof(float *)); v = (float *) malloc(rows * cols * sizeof(float)); for (i = 0; i < rows; i++) { m[i] = v; v += cols; } return (m); } /*----------------- Read and write PGM files ------------------------*/ /* This reads a PGM file from a given filename and returns the image. */ Image ReadPGMFile(char *filename) { FILE *file; /* The "b" option is for binary input, which is needed if this is compiled under Windows. It has no effect in Linux. */ file = fopen (filename, "rb"); if (! file) FatalError("Could not open file: %s", filename); return ReadPGM(file); } /* Read a PGM file from the given file pointer and return it as a float Image structure with pixels in the range [0,1]. If the file contains more than one image, then the images will be returned linked by the "next" field of the Image data structure. See "man pgm" for details on PGM file format. This handles only the usual 8-bit "raw" PGM format. Use xv or the PNM tools (such as pnmdepth) to convert from other formats. */ Image ReadPGM(FILE *fp) { int char1, char2, width, height, max, c1, c2, c3, r, c; Image image, nextimage; char1 = fgetc(fp); char2 = fgetc(fp); SkipComments(fp); c1 = fscanf(fp, "%d", &width); SkipComments(fp); c2 = fscanf(fp, "%d", &height); SkipComments(fp); c3 = fscanf(fp, "%d", &max); if (char1 != 'P' || char2 != '5' || c1 != 1 || c2 != 1 || c3 != 1 || max > 255) FatalError("Input is not a standard raw 8-bit PGM file.\n" "Use xv or pnmdepth to convert file to 8-bit PGM format.\n"); fgetc(fp); /* Discard exactly one byte after header. */ /* Create floating point image with pixels in range [0,1]. */ image = CreateImage(height, width); for (r = 0; r < height; r++) for (c = 0; c < width; c++) image->pixels[r][c] = ((float) fgetc(fp)) / 255.0; /* Check if there is another image in this file, as the latest PGM standard allows for multiple images. */ SkipComments(fp); if (getc(fp) == 'P') { ungetc('P', fp); nextimage = ReadPGM(fp); image->next = nextimage; } return image; } /* PGM files allow a comment starting with '#' to end-of-line. Skip white space including any comments. */ void SkipComments(FILE *fp) { int ch; fscanf(fp," "); /* Skip white space. */ while ((ch = fgetc(fp)) == '#') { while ((ch = fgetc(fp)) != '\n' && ch != EOF) ; fscanf(fp," "); } ungetc(ch, fp); /* Replace last character read. */ } /* Write an image to the file fp in PGM format. */ void WritePGM(FILE *fp, Image image) { int r, c, val; fprintf(fp, "P5\n%d %d\n255\n", image->cols, image->rows); for (r = 0; r < image->rows; r++) for (c = 0; c < image->cols; c++) { val = (int) (255.0 * image->pixels[r][c]); fputc(MAX(0, MIN(255, val)), fp); } } /* Draw a white line from (r1,c1) to (r2,c2) on the image. Both points must lie within the image. */ void DrawLine(Image image, int r1, int c1, int r2, int c2) { int i, dr, dc, temp; if (r1 == r2 && c1 == c2) /* Line of zero length. */ return; /* Is line more horizontal than vertical? */ if (ABS(r2 - r1) < ABS(c2 - c1)) { /* Put points in increasing order by column. */ if (c1 > c2) { temp = r1; r1 = r2; r2 = temp; temp = c1; c1 = c2; c2 = temp; } dr = r2 - r1; dc = c2 - c1; for (i = c1; i <= c2; i++) image->pixels[r1 + (i - c1) * dr / dc][i] = 1.0; } else { if (r1 > r2) { temp = r1; r1 = r2; r2 = temp; temp = c1; c1 = c2; c2 = temp; } dr = r2 - r1; dc = c2 - c1; for (i = r1; i <= r2; i++) image->pixels[i][c1 + (i - r1) * dc / dr] = 1.0; } } /*---------------------- Read keypoint file ---------------------------*/ /* This reads a keypoint file from a given filename and returns the list of keypoints. */ Keypoint ReadKeyFile(char *filename) { FILE *file; file = fopen (filename, "r"); if (! file) FatalError("Could not open file: %s", filename); return ReadKeys(file); } /* Read keypoints from the given file pointer and return the list of keypoints. The file format starts with 2 integers giving the total number of keypoints and the size of descriptor vector for each keypoint (currently assumed to be 128). Then each keypoint is specified by 4 floating point numbers giving subpixel row and column location, scale, and orientation (in radians from -PI to PI). Then the descriptor vector for each keypoint is given as a list of integers in range [0,255]. */ Keypoint ReadKeys(FILE *fp) { int i, j, num, len, val; Keypoint k, keys = NULL; if (fscanf(fp, "%d %d", &num, &len) != 2) FatalError("Invalid keypoint file beginning."); if (len != 128) FatalError("Keypoint descriptor length invalid (should be 128)."); for (i = 0; i < num; i++) { /* Allocate memory for the keypoint. */ k = (Keypoint) malloc(sizeof(struct KeypointSt)); k->next = keys; keys = k; k->descrip = malloc(len); if (fscanf(fp, "%f %f %f %f", &(k->row), &(k->col), &(k->scale), &(k->ori)) != 4) FatalError("Invalid keypoint file format."); for (j = 0; j < len; j++) { if (fscanf(fp, "%d", &val) != 1 || val < 0 || val > 255) FatalError("Invalid keypoint file value."); k->descrip[j] = (unsigned char) val; } } return keys; }
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句