├── .idea └── vcs.xml ├── COMPUTERVISIONASSIGNMENT_EROLOZKAN.docx ├── HOWTO.txt ├── MyCodes ├── FeatureExtractor.m ├── KeyPointDetector.m ├── RESULTS │ ├── archDOGGLOH.jpg │ ├── archDOGPCASIFT.jpg │ ├── archDOGSIFT.jpg │ ├── archHARRISGLOH.jpg │ ├── archHARRISPCASIFT.jpg │ ├── archHARRISSIFT.jpg │ ├── archMSERGLOH.jpg │ ├── archMSERPCASIFT.jpg │ ├── archMSERSIFT.jpg │ ├── notredameDOGSIFT.jpg │ ├── notredameDOGSIFT_EVAL.jpg │ ├── notredameHARRISSIFT.jpg │ ├── notredameHARRISSIFT_EVAL.jpg │ ├── notredameMSERSIFT.jpg │ ├── notredameMSERSIFT_EVAL.jpg │ ├── sanmarcoDOGSIFT.jpg │ ├── sanmarcoHARRISSIFT.jpg │ ├── sanmarcoMSERSIFT.jpg │ ├── stargarder3DOGSIFT.jpg │ ├── stargarder3HARRISSIFT.jpg │ ├── stargarder3MSERSIFT.jpg │ ├── worldbuildingDOGSIFT.jpg │ ├── worldbuildingHARRISSIFT.jpg │ └── worldbuildingMSERSIFT.jpg ├── avatuationcode.m ├── calculate_feature_distance.m ├── evaluateCorrespondence.m ├── extract_GLOH_features.m ├── extract_PCASIFT_features.m ├── extract_SIFT_features.m ├── extractallcorrespondes.m ├── findLocalMaximum.m ├── get_DOG_keypoints.m ├── get_Harris_keypoints.m ├── get_MSER_keypoints.m ├── get_octant.m ├── key_points.m ├── kp_harris.m ├── kp_harrislaplace.m ├── match_images.m ├── match_points.m ├── other_tries.m ├── runner.m ├── runnerAllOfTheImages.m ├── showAllCorrespondences.m └── showCorrespondence.m ├── README.md └── data ├── arch ├── 01.png ├── 02.png └── H1to2 ├── notredame ├── 01.png ├── 02.png ├── H1to2 └── allmatches.mat ├── sanmarco ├── 01.png ├── 02.png └── H1to2 ├── stargarder3 ├── 01.png ├── 02.png └── H1to2 └── worldbuilding ├── 01.png ├── 02.png └── H1to2 /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /COMPUTERVISIONASSIGNMENT_EROLOZKAN.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/COMPUTERVISIONASSIGNMENT_EROLOZKAN.docx -------------------------------------------------------------------------------- /HOWTO.txt: -------------------------------------------------------------------------------- 1 | RUN "runner" to work with a single image. 2 | RUN "runnerAllOfTheImages" to work with all images. 3 | 4 | to evaluate matched points we need all the correspondences. SEE paper and the code. 5 | alsoEvaluate = false(1); 6 | treshold= 0.8; % changes the result significantly 7 | 8 | alsoEvaluate = true(1); 9 | treshold= 0.8; -------------------------------------------------------------------------------- /MyCodes/FeatureExtractor.m: -------------------------------------------------------------------------------- 1 | classdef FeatureExtractor 2 | enumeration 3 | SIFT,PCASIFT,GLOH 4 | end 5 | end -------------------------------------------------------------------------------- /MyCodes/KeyPointDetector.m: -------------------------------------------------------------------------------- 1 | classdef KeyPointDetector 2 | enumeration 3 | HARRIS,MSER,DOG 4 | end 5 | end -------------------------------------------------------------------------------- /MyCodes/RESULTS/archDOGGLOH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archDOGGLOH.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archDOGPCASIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archDOGPCASIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archDOGSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archDOGSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archHARRISGLOH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archHARRISGLOH.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archHARRISPCASIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archHARRISPCASIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archHARRISSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archHARRISSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archMSERGLOH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archMSERGLOH.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archMSERPCASIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archMSERPCASIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/archMSERSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/archMSERSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameDOGSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameDOGSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameDOGSIFT_EVAL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameDOGSIFT_EVAL.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameHARRISSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameHARRISSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameHARRISSIFT_EVAL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameHARRISSIFT_EVAL.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameMSERSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameMSERSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/notredameMSERSIFT_EVAL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/notredameMSERSIFT_EVAL.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/sanmarcoDOGSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/sanmarcoDOGSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/sanmarcoHARRISSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/sanmarcoHARRISSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/sanmarcoMSERSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/sanmarcoMSERSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/stargarder3DOGSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/stargarder3DOGSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/stargarder3HARRISSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/stargarder3HARRISSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/stargarder3MSERSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/stargarder3MSERSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/worldbuildingDOGSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/worldbuildingDOGSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/worldbuildingHARRISSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/worldbuildingHARRISSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/RESULTS/worldbuildingMSERSIFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/RESULTS/worldbuildingMSERSIFT.jpg -------------------------------------------------------------------------------- /MyCodes/avatuationcode.m: -------------------------------------------------------------------------------- 1 | function avatuationcode() 2 | clc; 3 | clear all; 4 | 5 | image1 = imread('../data/notredame/01.png'); 6 | image2 = imread('../data/notredame/02.png'); 7 | 8 | I1 = rgb2gray(image1); 9 | I2 = rgb2gray(image2); 10 | 11 | %points1 = detectHarrisFeatures (I1); 12 | %points2 = detectHarrisFeatures (I2); 13 | 14 | points1 = detectMSERFeatures (I1); 15 | points2 = detectMSERFeatures (I2); 16 | 17 | %points1 = detectSURFFeatures (I1); 18 | %points2 = detectSURFFeatures (I2); 19 | 20 | [features1,valid_points1] = extractFeatures(I1,points1); 21 | [features2,valid_points2] = extractFeatures(I2,points2); 22 | 23 | indexPairs = matchFeatures(features1,features2); 24 | 25 | matchedPoints1 = valid_points1(indexPairs(:,1),:); 26 | matchedPoints2 = valid_points2(indexPairs(:,2),:); 27 | 28 | figure; showMatchedFeatures(I1,I2,matchedPoints1,matchedPoints2); 29 | 30 | location1 = matchedPoints1.Location; 31 | location2 = matchedPoints2.Location; 32 | 33 | draw(image1,location1,'1' ); 34 | draw(image2,location2,'2' ); 35 | 36 | end 37 | 38 | function draw(img,pt,str) 39 | figure('Name',str); 40 | imshow(img); 41 | hold on; 42 | axis off; 43 | switch size(pt,2) 44 | case 2 45 | s = 2; 46 | for i=1:size(pt,1) 47 | rectangle('Position',[pt(i,2)-s,pt(i,1)-s,2*s,2*s],'Curvature',[0 0],'EdgeColor','b','LineWidth',2); 48 | end 49 | case 3 50 | for i=1:size(pt,1) 51 | rectangle('Position',[pt(i,2)-pt(i,3),pt(i,1)-pt(i,3),2*pt(i,3),2*pt(i,3)],'Curvature',[1,1],'EdgeColor','w','LineWidth',2); 52 | end 53 | end 54 | end -------------------------------------------------------------------------------- /MyCodes/calculate_feature_distance.m: -------------------------------------------------------------------------------- 1 | %This function gets two feaure set, then returns euclidean distance matrix 2 | %between each element of faature set 3 | 4 | %PDIST2 Pairwise distance between two sets of observations. 5 | % D = PDIST2(X,Y) returns a matrix D containing the Euclidean distances 6 | % between each pair of observations 7 | function [distanceMatrix] = calculate_feature_distance(feature1, feature2) 8 | distanceMatrix = pdist2(feature1, feature2, 'euclidean'); 9 | -------------------------------------------------------------------------------- /MyCodes/evaluateCorrespondence.m: -------------------------------------------------------------------------------- 1 | function evaluateCorrespondence(image1,image2,x1_est, y1_est, x2_est, y2_est,filePathToRead,fileNameToWrite) 2 | 3 | stringg = '../data/'; 4 | stringg= strcat(stringg,filePathToRead ); 5 | stringg = strcat(stringg, '/allmatches.mat'); 6 | 7 | %%This file hold all matches , created with matlab functions, it is 8 | %%included in folder. 9 | allCorresponcesFileCreated = stringg; 10 | load(allCorresponcesFileCreated) 11 | 12 | good_matches = zeros(length(x1_est),1); 13 | 14 | h = figure; 15 | set(h, 'Position', [100 100 800 600]) 16 | subplot(1,2,1); 17 | imshow(image1, 'Border', 'tight') 18 | subplot(1,2,2); 19 | imshow(image2, 'Border', 'tight') 20 | 21 | 22 | for i = 1:length(x1_est) 23 | 24 | fprintf('( %4.0f, %4.0f) to ( %4.0f, %4.0f)', x1_est(i), y1_est(i), x2_est(i), y2_est(i)); 25 | 26 | %for each x1_est, find nearest ground truth point in x1 27 | x_dists = x1_est(i) - x1; 28 | y_dists = y1_est(i) - y1; 29 | dists = sqrt( x_dists.^2 + y_dists.^2 ); 30 | 31 | [dists, best_matches] = sort(dists); 32 | 33 | current_offset = [x1_est(i) - x2_est(i), y1_est(i) - y2_est(i)]; 34 | most_similar_offset = [x1(best_matches(1)) - x2(best_matches(1)), y1(best_matches(1)) - y2(best_matches(1))]; 35 | 36 | %match_dist = sqrt( (x2_est(i) - x2(best_matches(1)))^2 + (y2_est(i) - y2(best_matches(1)))^2); 37 | match_dist = sqrt( sum((current_offset - most_similar_offset).^2)); 38 | 39 | %A match is bad if there ?S no ground truth point within 50 pixels or 40 | %if nearest ground truth correspondence offset isn't within 25 pixels 41 | %of the estimated correspondence offset. 42 | fprintf(' INDEX:%4.0f ERROR: %4.0f ', dists(1), match_dist); 43 | 44 | if(dists(1) > 150 || match_dist > 25) 45 | good_matches(i) = 0; 46 | edgeColor = [1 0 0]; 47 | fprintf(' TRUE\n'); 48 | else 49 | good_matches(i) = 1; 50 | edgeColor = [0 1 0]; 51 | fprintf(' FALSE\n'); 52 | end 53 | 54 | cur_color = rand(1,3); 55 | subplot(1,2,1); 56 | hold on; 57 | plot(x1_est(i),y1_est(i), 'o', 'LineWidth',2, 'MarkerEdgeColor',edgeColor,... 58 | 'MarkerFaceColor', cur_color, 'MarkerSize',10) 59 | hold off; 60 | 61 | subplot(1,2,2); 62 | hold on; 63 | plot(x2_est(i),y2_est(i), 'o', 'LineWidth',2, 'MarkerEdgeColor',edgeColor,... 64 | 'MarkerFaceColor', cur_color, 'MarkerSize',10) 65 | hold off; 66 | end 67 | 68 | fprintf('%d good matches, %d bad matches\n', sum(good_matches), length(x1_est) - sum(good_matches)) 69 | 70 | fprintf('Saving visualization to file in RESULTS (EVAL)\n') 71 | visualization_image = frame2im(getframe(h)); 72 | try 73 | visualization_image = visualization_image(81:end-80, 51:end-50,:); 74 | catch 75 | ; 76 | end 77 | imwrite(visualization_image, strcat('RESULTS/',strcat(fileNameToWrite(1:end-4),'_EVAL.jpg')), 'quality', 100) 78 | -------------------------------------------------------------------------------- /MyCodes/extract_GLOH_features.m: -------------------------------------------------------------------------------- 1 | function [calculatedFeatureList] = extract_GLOH_features(image, x, y, featureWidth) 2 | 3 | pointNumber = size(x,1); 4 | calculatedFeatureList = zeros(pointNumber, 128); %SIFT IS 128 B?T 5 | 6 | %CREATE SMALL GAUSSIOAN 7 | small_gaussian = fspecial('Gaussian', [featureWidth featureWidth], 1); 8 | %CREATE BIGGER GAUSSIAN 9 | large_gaussian = fspecial('Gaussian', [featureWidth featureWidth], featureWidth/2); 10 | 11 | %filters the image with x,y gradients of our gaussian filter. 12 | [xDerivative, yDerivative] = imgradientxy(small_gaussian); 13 | ix = imfilter(image, xDerivative); 14 | iy = imfilter(image, yDerivative); 15 | 16 | % function to be applied at each step , like functional interface in JAVA 8 17 | getOctant = @(x,y) (ceil(atan2(y,x)/(pi/4)) + 4); 18 | orients = arrayfun(getOctant, ix, iy); 19 | %returns SQRT(ABS(A).^2+ABS(B).^2) 20 | mag = hypot(ix, iy); 21 | c_size = featureWidth/4; 22 | for ii = 1:pointNumber 23 | frame_x_range = (x(ii) - 2*c_size): (x(ii) + 2*c_size-1); 24 | frame_y_range = (y(ii) - 2*c_size): (y(ii) + 2*c_size-1); 25 | %rectangle('Position', [x(ii) - 2*c_size, y(ii) - 2*c_size, feature_width, feature_width], 'EdgeColor', 'Red'); 26 | frame_mag = mag(frame_y_range, frame_x_range); 27 | frame_mag = frame_mag.*large_gaussian; 28 | frame_orients = orients(frame_y_range, frame_x_range); 29 | % Looping through each cell in the frame 30 | for xx = 0:3 31 | for yy = 0:3 32 | cell_orients = frame_orients(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 33 | cell_mag = frame_mag(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 34 | for o = 1:8 35 | f = cell_orients == o; 36 | calculatedFeatureList(ii, (xx*32 + yy*8) + o) = sum(sum(cell_mag(f))); 37 | end 38 | end 39 | end 40 | end 41 | %Normalizes feature vectors 42 | calculatedFeatureList = diag(1./sum(calculatedFeatureList,2))*calculatedFeatureList; 43 | 44 | end 45 | -------------------------------------------------------------------------------- /MyCodes/extract_PCASIFT_features.m: -------------------------------------------------------------------------------- 1 | function [calculatedFeatureList] = extract_PCASIFT_features(image, x, y, featureWidth) 2 | 3 | pointNumber = size(x,1); 4 | calculatedFeatureList = zeros(pointNumber, 128); %SIFT IS 128 B?T 5 | 6 | %CREATE SMALL GAUSSIOAN 7 | small_gaussian = fspecial('Gaussian', [featureWidth featureWidth], 1); 8 | %CREATE BIGGER GAUSSIAN 9 | large_gaussian = fspecial('Gaussian', [featureWidth featureWidth], featureWidth/2); 10 | 11 | %filters the image with x,y gradients of our gaussian filter. 12 | [xDerivative, yDerivative] = imgradientxy(small_gaussian); 13 | ix = imfilter(image, xDerivative); 14 | iy = imfilter(image, yDerivative); 15 | 16 | % function to be applied at each step , like functional interface in JAVA 8 17 | getOctant = @(x,y) (ceil(atan2(y,x)/(pi/4)) + 4); 18 | orients = arrayfun(getOctant, ix, iy); 19 | %returns SQRT(ABS(A).^2+ABS(B).^2) 20 | mag = hypot(ix, iy); 21 | c_size = featureWidth/4; 22 | for ii = 1:pointNumber 23 | frame_x_range = (x(ii) - 2*c_size): (x(ii) + 2*c_size-1); 24 | frame_y_range = (y(ii) - 2*c_size): (y(ii) + 2*c_size-1); 25 | %rectangle('Position', [x(ii) - 2*c_size, y(ii) - 2*c_size, feature_width, feature_width], 'EdgeColor', 'Red'); 26 | frame_mag = mag(frame_y_range, frame_x_range); 27 | frame_mag = frame_mag.*large_gaussian; 28 | frame_orients = orients(frame_y_range, frame_x_range); 29 | % Looping through each cell in the frame 30 | for xx = 0:3 31 | for yy = 0:3 32 | cell_orients = frame_orients(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 33 | cell_mag = frame_mag(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 34 | for o = 1:8 35 | f = cell_orients == o; 36 | calculatedFeatureList(ii, (xx*32 + yy*8) + o) = sum(sum(cell_mag(f))); 37 | end 38 | end 39 | end 40 | end 41 | %Normalizes feature vectors 42 | calculatedFeatureList = diag(1./sum(calculatedFeatureList,2))*calculatedFeatureList; 43 | 44 | end -------------------------------------------------------------------------------- /MyCodes/extract_SIFT_features.m: -------------------------------------------------------------------------------- 1 | % Returns a set of feature descriptors for a given set of key points. 2 | % 'x' and 'y' are x and y coordinates of key points. 3 | % 'feature_width', in pixels, is the local feature width. 4 | % 'features' is the array of computed features. 128 for standard SIFT) 5 | 6 | %STEPS----------------------------------------- 7 | % (1) a 4x4 grid of cells, each feature_width/4. 8 | % (2) each cell should have a histogram of the local distribution of 9 | % gradients in 8 orientations. Appending these histograms together will 10 | % give you 4x4 x 8 = 128 dimensions. 11 | % (3) Each feature should be normalized to unit length 12 | %------------------------------------------ 13 | function [calculatedFeatureList] = extract_SIFT_features(image, x, y, featureWidth) 14 | 15 | pointNumber = size(x,1); 16 | calculatedFeatureList = zeros(pointNumber, 128); %SIFT IS 128 B?T 17 | 18 | %CREATE SMALL GAUSSIOAN 19 | small_gaussian = fspecial('Gaussian', [featureWidth featureWidth], 1); 20 | %CREATE BIGGER GAUSSIAN 21 | large_gaussian = fspecial('Gaussian', [featureWidth featureWidth], featureWidth/2); 22 | 23 | %filters the image with x,y gradients of our gaussian filter. 24 | [xDerivative, yDerivative] = imgradientxy(small_gaussian); 25 | ix = imfilter(image, xDerivative); 26 | iy = imfilter(image, yDerivative); 27 | 28 | % function to be applied at each step , like functional interface in JAVA 8 29 | getOctant = @(x,y) (ceil(atan2(y,x)/(pi/4)) + 4); 30 | orients = arrayfun(getOctant, ix, iy); 31 | %returns SQRT(ABS(A).^2+ABS(B).^2) 32 | mag = hypot(ix, iy); 33 | c_size = featureWidth/4; 34 | for ii = 1:pointNumber 35 | frame_x_range = (x(ii) - 2*c_size): (x(ii) + 2*c_size-1); 36 | frame_y_range = (y(ii) - 2*c_size): (y(ii) + 2*c_size-1); 37 | %rectangle('Position', [x(ii) - 2*c_size, y(ii) - 2*c_size, feature_width, feature_width], 'EdgeColor', 'Red'); 38 | frame_mag = mag(frame_y_range, frame_x_range); 39 | frame_mag = frame_mag.*large_gaussian; 40 | frame_orients = orients(frame_y_range, frame_x_range); 41 | % Looping through each cell in the frame 42 | for xx = 0:3 43 | for yy = 0:3 44 | cell_orients = frame_orients(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 45 | cell_mag = frame_mag(xx*4+1:xx*4+4, yy*4+1:yy*4+4); 46 | for o = 1:8 47 | f = cell_orients == o; 48 | calculatedFeatureList(ii, (xx*32 + yy*8) + o) = sum(sum(cell_mag(f))); 49 | end 50 | end 51 | end 52 | end 53 | %Normalizes feature vectors 54 | calculatedFeatureList = diag(1./sum(calculatedFeatureList,2))*calculatedFeatureList; 55 | 56 | end 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /MyCodes/extractallcorrespondes.m: -------------------------------------------------------------------------------- 1 | %An interactive method to specify and then save many point correspondences 2 | %between two photographs which can later be used to evaluate matching 3 | %algorithms. 4 | function extractallcorrespondes() 5 | 6 | image1 = imread('../data/arch/01.png'); 7 | image2 = imread('../data/arch/02.png'); 8 | 9 | image1 = double(image1)/255; 10 | image2 = double(image2)/255; 11 | 12 | output_file = '../data/arch/allmatches.mat'; 13 | 14 | if(exist(output_file,'file')) 15 | load(output_file) 16 | h = show_correspondence(image1, image2, x1, y1, x2, y2) 17 | else 18 | x1 = zeros(0,1); %x locations in image 1 19 | y1 = zeros(0,1); %y locations in image 1 20 | x2 = zeros(0,1); %corresponding x locations in image 2 21 | y2 = zeros(0,1); %corresponding y locations in image 2 22 | 23 | h = figure; 24 | subplot(1,2,1); 25 | imshow(image1) 26 | 27 | subplot(1,2,2); 28 | imshow(image2) 29 | end 30 | 31 | fprintf('Click on a negative coordinate (Above or to the left of the left image) to stop\n') 32 | 33 | while(1) 34 | [x,y] = ginput(1); 35 | if(x <= 0 || y <= 0) 36 | break 37 | end 38 | subplot(1,2,1); 39 | hold on; 40 | plot(x,y,'ro'); 41 | hold off; 42 | x1 = [x1;x]; 43 | y1 = [y1;y]; 44 | 45 | [x,y] = ginput(1); 46 | if(x <= 0 || y <= 0) 47 | break 48 | end 49 | subplot(1,2,2); 50 | hold on; 51 | plot(x,y,'ro'); 52 | hold off; 53 | x2 = [x2;x]; 54 | y2 = [y2;y]; 55 | 56 | fprintf('( %5.2f, %5.2f) matches to ( %5.2f, %5.2f)\n', x1(end), y1(end), x2(end), y2(end)); 57 | fprintf('%d total points corresponded\n', length(x1)); 58 | end 59 | 60 | fprintf('saving matched points\n') 61 | save(output_file, 'x1', 'y1', 'x2', 'y2') 62 | 63 | -------------------------------------------------------------------------------- /MyCodes/findLocalMaximum.m: -------------------------------------------------------------------------------- 1 | %NOT USED 2 | function [row,col,max_local] = findLocalMaximum(val,radius) 3 | % Determine the local maximum of a given value 4 | % 5 | % Author :: Vincent Garcia 6 | % Date :: 09/02/2007 7 | % 8 | % INPUT 9 | % ===== 10 | % val : the NxM matrix containing values 11 | % radius : the radius of the neighborhood 12 | % 13 | % OUTPUT 14 | % ====== 15 | % row : the row position of the local maxima 16 | % col : the column position of the local maxima 17 | % max_local : the NxM matrix containing values of val on unique local maximum 18 | % 19 | % EXAMPLE 20 | % ======= 21 | % [l,c,m] = findLocalMaximum(img,radius); 22 | 23 | 24 | 25 | 26 | % FIND LOCAL MAXIMA BY DILATION (FAST) /!\ NON UNIQUE /!\ 27 | % mask = fspecial('disk',radius)>0; 28 | % val2 = imdilate(val,mask); 29 | % index = val==val2; 30 | % [row,col] = find(index==1); 31 | % max_local = zeros(size(val)); 32 | % max_local(index) = val(index); 33 | 34 | 35 | % FIND UNIQUE LOCAL MAXIMA USING FILTERING (FAST) 36 | mask = fspecial('disk',radius)>0; 37 | nb = sum(mask(:)); 38 | highest = ordfilt2(val, nb, mask); 39 | second_highest = ordfilt2(val, nb-1, mask); 40 | index = highest==val & highest~=second_highest; 41 | max_local = zeros(size(val)); 42 | max_local(index) = val(index); 43 | [row,col] = find(index==1); 44 | 45 | 46 | % FIND UNIQUE LOCAL MAXIMA (FAST) 47 | % val_height = size(val,1); 48 | % val_width = size(val,2); 49 | % max_local = zeros(val_height,val_width); 50 | % val_enlarge = zeros(val_height+2*radius,val_width+2*radius); 51 | % val_mask = zeros(val_height+2*radius,val_width+2*radius); 52 | % val_enlarge( (1:val_height)+radius , (1:val_width)+radius ) = val; 53 | % val_mask( (1:val_height)+radius , (1:val_width)+radius ) = 1; 54 | % mask = fspecial('disk',radius)>0; 55 | % row = zeros(val_height*val_width,1); 56 | % col = zeros(val_height*val_width,1); 57 | % index = 0; 58 | % for l = 1:val_height 59 | % for c = 1:val_width 60 | % val_ref = val(l,c); 61 | % neigh_val = val_enlarge(l:l+2*radius,c:c+2*radius); 62 | % neigh_mask = val_mask( l:l+2*radius,c:c+2*radius).*mask; 63 | % neigh_sort = sort(neigh_val(neigh_mask==1)); 64 | % if val_ref==neigh_sort(end) && val_ref>neigh_sort(end-1) 65 | % index = index+1; 66 | % row(index,1) = l; 67 | % col(index,1) = c; 68 | % max_local(l,c) = val_ref; 69 | % end 70 | % end 71 | % end 72 | % row(index+1:end,:) = []; 73 | % col(index+1:end,:) = []; 74 | 75 | 76 | end -------------------------------------------------------------------------------- /MyCodes/get_DOG_keypoints.m: -------------------------------------------------------------------------------- 1 | %creates two gausian filters that HSIZE is 25x25 and SIGMA equals to 1 for 2 | %50 for larger one, this code first uses DOG filter in the image, then it 3 | %finds edges. 4 | function [x, y, confidence, scale, orientation] = get_MSER_keypoints(image, feature_width) 5 | 6 | k = 50; 7 | sigma1 = 1; 8 | sigma2 = sigma1*k; 9 | hsize = [25,25]; 10 | h1 = fspecial('gaussian', hsize, sigma1); 11 | h2 = fspecial('gaussian', hsize, sigma2); 12 | gauss1 = imfilter(image,h1,'same'); 13 | gauss2 = imfilter(image,h2,'same'); 14 | dogImg = gauss1 - gauss2; 15 | 16 | K=0.04; 17 | gaussian = fspecial('Gaussian', [25 25], 1); 18 | [xder, yder] = imgradientxy(gaussian); 19 | ix = imfilter(dogImg, xder); 20 | iy = imfilter(dogImg, yder); 21 | ix([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 22 | ix(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 23 | iy([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 24 | iy(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 25 | 26 | biggerGaussian = fspecial('Gaussian', [25 25], 2); 27 | 28 | ixx = imfilter(ix.*ix, biggerGaussian); 29 | ixy = imfilter(ix.*iy, biggerGaussian); 30 | iyy = imfilter(iy.*iy, biggerGaussian); 31 | 32 | Mc = ixx.*iyy - ixy.*ixy - K.*(ixx+iyy).*(ixx+iyy); 33 | thresholded = Mc > 10*mean2(Mc); 34 | 35 | Mc = Mc.*thresholded; 36 | har_max = colfilt(Mc, [feature_width feature_width], 'sliding', @max); 37 | Mc = Mc.*(Mc == har_max); 38 | [y, x] = find(Mc > 0); 39 | confidence = Mc(Mc > 0); 40 | -------------------------------------------------------------------------------- /MyCodes/get_Harris_keypoints.m: -------------------------------------------------------------------------------- 1 | %HARRIS CORNER DETECTION IMPLEMNTATION 2 | %This code createes a set of key points for the input image 3 | %SEE : https://en.wikipedia.org/wiki/Corner_detection 4 | function [x, y, confidence, scale, orientation] = get_Harris_keypoints(image, feature_width) 5 | 6 | %K is a tunable sensitivity parameter, SEE wiki 7 | K=0.04; 8 | 9 | %creates a gausian filter that HSIZE is 25x25 and SIGMA equals to 1 10 | gaussian = fspecial('Gaussian', [25 25], 1); 11 | 12 | %imgradientxy finds the directional gradients of the given input data; image or matrix. 13 | %[xder, yder] are the gradient along with X and Y axises of our gaussian flter 14 | [xder, yder] = imgradientxy(gaussian); 15 | 16 | %filters the image with x,y gradients of our gaussian filter. 17 | ix = imfilter(image, xder); 18 | iy = imfilter(image, yder); 19 | 20 | %to supress the gradients near the edges 21 | ix([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 22 | ix(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 23 | iy([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 24 | iy(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 25 | 26 | %creates a gausian filter that HSIZE is 25x25 and SIGMA equals to 2, so 27 | %this gausian filter is larger than the first one. 28 | biggerGaussian = fspecial('Gaussian', [25 25], 2); 29 | 30 | %filters below values with bigger_gaussian filter 31 | ixx = imfilter(ix.*ix, biggerGaussian); 32 | ixy = imfilter(ix.*iy, biggerGaussian); 33 | iyy = imfilter(iy.*iy, biggerGaussian); 34 | 35 | %The treshold to suppress some unwanted corners. 36 | %right side is 1e-6 37 | Mc = ixx.*iyy - ixy.*ixy - K.*(ixx+iyy).*(ixx+iyy); 38 | thresholded = Mc > 10*mean2(Mc); 39 | 40 | Mc = Mc.*thresholded; 41 | %colfilt returns the max value on each sliding window. This ensures 42 | %that every interest point is at a local maximum 43 | har_max = colfilt(Mc, [feature_width feature_width], 'sliding', @max); 44 | Mc = Mc.*(Mc == har_max); 45 | %'x' and 'y' are vectors of x and y coordinates of interest points in s 46 | [y, x] = find(Mc > 0); 47 | %'confidence' is an vector indicating the strength of the key point 48 | confidence = Mc(Mc > 0); 49 | -------------------------------------------------------------------------------- /MyCodes/get_MSER_keypoints.m: -------------------------------------------------------------------------------- 1 | %MSER IMPLEMNTATION 2 | %This code createes a set of key points for the image based on MSER algoritm I created. 3 | %Firsh part is the same as get_Harris_keypoints algorithm but then this 4 | %code finds components that has similiar to each other based on their intensity 5 | %values. 6 | %SEE : https://en.wikipedia.org/wiki/Connected-component_labeling 7 | %SEE : https://en.wikipedia.org/wiki/Maximally_stable_extremal_regions 8 | %SEE : https://www.mathworks.com/help/images/ref/bwconncomp.html 9 | function [x, y, confidence, scale, orientation] = get_MSER_keypoints(image, feature_width) 10 | 11 | %K is a tunable sensitivity parameter 12 | K=0.04; 13 | 14 | %creates a gausian filter that HSIZE is 25x25 and SIGMA equals to 1 15 | gaussian = fspecial('Gaussian', [25 25], 1); 16 | 17 | %imgradientxy finds the directional gradients of the given input data; image or matrix. 18 | %[xder, yder] are the gradient along with X and Y axises of our gaussian flter 19 | [xder, yder] = imgradientxy(gaussian); 20 | 21 | %filters the image with x,y gradients of our gaussian filter. 22 | ix = imfilter(image, xder); 23 | iy = imfilter(image, yder); 24 | 25 | %to supress the gradients near the edges 26 | ix([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 27 | ix(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 28 | iy([(1:feature_width) end-feature_width+(1:feature_width)],:) = 0; 29 | iy(:, [(1:feature_width) end-feature_width+(1:feature_width)]) = 0; 30 | 31 | %creates a gausian filter that HSIZE is 25x25 and SIGMA equals to 2, so 32 | %this gausian filter is larger than the first one. 33 | biggerGaussian = fspecial('Gaussian', [25 25], 2); 34 | 35 | %filters below values with bigger_gaussian filter 36 | ixx = imfilter(ix.*ix, biggerGaussian); 37 | ixy = imfilter(ix.*iy, biggerGaussian); 38 | iyy = imfilter(iy.*iy, biggerGaussian); 39 | 40 | %The treshold to suppress some unwanted corners. 41 | %right side is 1e-6 42 | Mc = ixx.*iyy - ixy.*ixy - K.*(ixx+iyy).*(ixx+iyy); 43 | thresholded = Mc > 10*mean2(Mc); 44 | 45 | %bwconncomp finds connected components in thresholded binary image. 46 | %I take the maximum value in each component. 47 | components = bwconncomp(thresholded); 48 | width = components.ImageSize(1); 49 | x = zeros(components.NumObjects, 1); 50 | y = zeros(components.NumObjects, 1); 51 | confidence = zeros(components.NumObjects, 1); 52 | 53 | for ii=1:(components.NumObjects) 54 | pixel_ids = components.PixelIdxList{ii}; 55 | pixel_values = Mc(pixel_ids); 56 | [max_value, max_id] = max(pixel_values); 57 | %'x' and 'y' are vectors of x and y coordinates of interest points in s 58 | x(ii) = floor(pixel_ids(max_id)/ width); 59 | y(ii) = mod(pixel_ids(max_id), width); 60 | %'confidence' is an vector indicating the strength of the key point tha 61 | confidence(ii) = max_value; 62 | end 63 | -------------------------------------------------------------------------------- /MyCodes/get_octant.m: -------------------------------------------------------------------------------- 1 | %NOT USED 2 | function octant = get_octant(x,y) 3 | x_pos = x > 0; 4 | y_pos = y > 0; 5 | sum_pos = (x + y) > 0; 6 | diff_pos = (x - y) > 0; 7 | if (x_pos && y_pos && diff_pos) 8 | octant = 1; 9 | elseif (x_pos && y_pos && ~diff_pos) 10 | octant = 2; 11 | elseif (~x_pos && y_pos && sum_pos) 12 | octant = 3; 13 | elseif (~x_pos && y_pos && ~sum_pos) 14 | octant = 4; 15 | elseif (~x_pos && ~y_pos && diff_pos) 16 | octant = 5; 17 | elseif (~x_pos && ~y_pos && ~diff_pos) 18 | octant = 6; 19 | elseif (x_pos && ~y_pos && ~sum_pos) 20 | octant = 7; 21 | else 22 | octant = 8; 23 | end 24 | end -------------------------------------------------------------------------------- /MyCodes/key_points.m: -------------------------------------------------------------------------------- 1 | %NOT USED 2 | %this software computes the keypoints in SIFT algorithm and save the rsult 3 | %in extrema variable 4 | % I--> the input image should be a color(rgb) image 5 | function exterma=key_points(I) 6 | I=imread('door.jpg'); 7 | I=double(rgb2gray(I)); 8 | I=I/max(max(I)); % image should be in [0 1] 9 | [M,N,C] = size(I) ; 10 | 11 | % Lowe's choices 12 | S=3 ; 13 | omin=-1 ; % first octave -1 mmeans I should be doublsized for first octave 14 | O=floor(log2(min(M,N)))-omin-4 ; % Up to 16x16 images 15 | % we can decrease the 1.6 for some images to reach better esults 16 | sigma0=1.6*2^(1/S) ; % this sigma is for the image in real size 17 | % and 1.6 is for doublsized image in first octave 18 | sigman=0.5 ;% antialiasing filter sigma 19 | thresh = 0.006;% it was .03 in Lowe's paper ,we changed it to .006 here 20 | r = 10 ; 21 | 22 | 23 | %calculate Guassian images in different scales and octave 24 | GS = gaussianss(I,O,S,omin,-1,S+1,sigma0) ; 25 | %************************************************************* 26 | %calculate DOG images 27 | for o=1:GS.O %all the octaves 28 | [M,N,SS] = size(GS.octave{o}) ; 29 | DOG.octave{o} = zeros(M,N,SS-1) ; 30 | for s=1:SS-1 31 | DOG.octave{o}(:,:,s) = ... 32 | GS.octave{o}(:,:,s+1) - GS.octave{o}(:,:,s) ; 33 | end 34 | end 35 | %******************************************************** 36 | %******** imshow DOG images you can comment this******* 37 | % for o=1:GS.O %all the octaves 38 | % for s=1:SS-1 39 | % imshow(DOG.octave{o}(:,:,s),[]) 40 | % pause(1) 41 | % 42 | % end 43 | % end 44 | %************************************************************* 45 | 46 | %finding key points 47 | exterma=zeros(2,1); 48 | for o=1:GS.O 49 | for s=2:SS-2 50 | sig=1.6*2^(o-1)*(2^(1/S))^s; 51 | current_DOG=DOG.octave{o}(:,:,s); 52 | down_DOG=DOG.octave{o}(:,:,s-1); 53 | up_DOG=DOG.octave{o}(:,:,s+1); 54 | extr = search_exterm(up_DOG,down_DOG,current_DOG ) ;%find exremum 55 | if extr(1,1) 56 | %accurate localization to subpixel and eliminate some unsuitable 57 | %points 58 | extr=localize_eliminate(extr,up_DOG,down_DOG,current_DOG ,thresh,r); 59 | if extr(1,1) 60 | extr=2^(o-1+GS.omin) *extr; %stor key points 61 | exterma=[exterma extr]; 62 | 63 | 64 | end 65 | end 66 | 67 | end 68 | 69 | end 70 | 71 | imshow(I,[]) 72 | hold on 73 | plot(exterma(2,:),exterma(1,:),'r+','LineWidth',2) 74 | end 75 | 76 | %************************************************************************** 77 | function SS = gaussianss(I,O,S,omin,smin,smax,sigma0) 78 | %smax--> maximum scale(here it is 4) 79 | %smin--> minimum scale(here is -1...image shold be double sized) 80 | %omin--> first octave(here is -1) 81 | %1.6 as sigma0 is considered for omin=-1 82 | 83 | 84 | % Scale multiplicative step 85 | k = 2^(1/S) ; 86 | 87 | 88 | dsigma0 = sigma0 * sqrt(1 - 1/k^2) ; % Scale step factor 89 | sigman = 0.5 ; % Nominal smoothing of the image 90 | 91 | % Scale space structure 92 | SS.O = O ; 93 | SS.S = S ; 94 | SS.sigma0 = sigma0 ; 95 | SS.omin = omin ; 96 | SS.smin = smin ; 97 | SS.smax = smax ; 98 | 99 | % If mino < 0, multiply the size of the image. 100 | % (The rest of the code is consistent with this.) 101 | if omin < 0 102 | for o=1:-omin 103 | I = doubleSize(I) ; 104 | end 105 | elseif omin > 0 106 | for o=1:omin 107 | I = halveSize(I) ; 108 | end 109 | end 110 | 111 | [M,N] = size(I) ; 112 | 113 | % Index offset 114 | so = -smin+1 ; 115 | 116 | % -------------------------------------------------------------------- 117 | % First octave 118 | % -------------------------------------------------------------------- 119 | % 120 | % The first level of the first octave has scale index (o,s) = 121 | % (omin,smin) and scale coordinate 122 | % 123 | % sigma(omin,smin) = sigma0 2^omin k^smin 124 | % 125 | % The input image I is at nominal scale sigman. Thus in order to get 126 | % the first level of the pyramid we need to apply a smoothing of 127 | % 128 | % sqrt( (sigma0 2^omin k^smin)^2 - sigman^2 ). 129 | % 130 | % As we have pre-scaled the image omin octaves (up or down, 131 | % depending on the sign of omin), we need to correct this value 132 | % by dividing by 2^omin, getting 133 | %e 134 | % sqrt( (sigma0 k^smin)^2 - (sigman/2^omin)^2 ) 135 | % 136 | 137 | if(sigma0 * 2^omin * k^smin < sigman) 138 | warning('The nominal smoothing exceeds the lowest level of the scale space.') ; 139 | end 140 | 141 | SS.octave{1} = zeros(M,N,smax-smin+1) ;% we have 6 scale in each octave 142 | SS.octave{1}(:,:,1) = gauss_filter(I,sqrt((sigma0*k^smin)^2 ... 143 | - (sigman/2^omin)^2)); 144 | %HOSSEIN imsmooth(I, ... 145 | %sqrt((sigma0*k^smin)^2 - (sigman/2^omin)^2)) ;% sigman and sigma0 applyed simutnously 146 | %Not that sigma0 for first octave(double sized image state) is 147 | %1.6-->1.6*k*k^smin and smin=-1 148 | for s=smin+1:smax 149 | % Here we go from (omin,s-1) to (omin,s). The extra smoothing 150 | % standard deviation is 151 | % 152 | % (sigma0 2^omin 2^(s/S) )^2 - (simga0 2^omin 2^(s/S-1/S) )^2 153 | % 154 | % Aftred dividing by 2^omin (to take into account the fact 155 | % that the image has been pre-scaled omin octaves), the 156 | % standard deviation of the smoothing kernel is 157 | % 158 | % dsigma = sigma0 k^s sqrt(1-1/k^2) 159 | % 160 | dsigma = k^s * dsigma0 ;% smooth Image in prevous scale and just use dsigma 161 | SS.octave{1}(:,:,s +so) =gauss_filter... 162 | (squeeze(SS.octave{1}(:,:,s-1 +so)), dsigma); 163 | %HOSSEIN imsmooth(squeeze(SS.octave{1}(:,:,s-1 +so)), dsigma ) ; 164 | end 165 | 166 | 167 | % -------------------------------------------------------------------- 168 | % Other octaves 169 | % -------------------------------------------------------------------- 170 | 171 | for o=2:O 172 | % We need to initialize the first level of octave (o,smin) from 173 | % the closest possible level of the previous octave. A level (o,s) 174 | % in this octave corrsponds to the level (o-1,s+S) in the previous 175 | % octave. In particular, the level (o,smin) correspnds to 176 | % (o-1,smin+S). However (o-1,smin+S) might not be among the levels 177 | % (o-1,smin), ..., (o-1,smax) that we have previously computed. 178 | % The closest pick is 179 | % 180 | % / smin+S if smin+S <= smax % for me it is 181 | % statisfied all the time 182 | % (o-1,sbest) , sbest = | 183 | % \ smax if smin+S > smax 184 | % 185 | % The amount of extra smoothing we need to apply is then given by 186 | % 187 | % ( sigma0 2^o 2^(smin/S) )^2 - ( sigma0 2^o 2^(sbest/S - 1) )^2 188 | % 189 | % As usual, we divide by 2^o to cancel out the effect of the 190 | % downsampling and we get 191 | % 192 | % ( sigma 0 k^smin )^2 - ( sigma0 2^o k^(sbest - S) )^2 193 | % 194 | sbest = min(smin + S, smax) ; 195 | TMP = halveSize(squeeze(SS.octave{o-1}(:,:,sbest+so))) ; 196 | target_sigma = sigma0 * k^smin ; 197 | prev_sigma = sigma0 * k^(sbest - S) ; 198 | 199 | if (target_sigma > prev_sigma) 200 | TMP =gauss_filter(TMP, sqrt(target_sigma^2 - prev_sigma^2)); 201 | end 202 | 203 | 204 | [M,N] = size(TMP) ; 205 | 206 | SS.octave{o} = zeros(M,N,smax-smin+1) ; 207 | SS.octave{o}(:,:,1) = TMP ; 208 | 209 | for s=smin+1:smax 210 | % The other levels are determined as above for the first octave. 211 | dsigma = k^s * dsigma0 ; 212 | SS.octave{o}(:,:,s +so) =gauss_filter(squeeze(SS.octave{o}... 213 | (:,:,s-1 +so)), dsigma); 214 | end 215 | 216 | end 217 | end 218 | 219 | % ------------------------------------------------------------------------- 220 | % Auxiliary functions 221 | % ------------------------------------------------------------------------- 222 | function J = doubleSize(I) 223 | [M,N]=size(I) ; 224 | J = zeros(2*M,2*N) ; 225 | J(1:2:end,1:2:end) = I ; 226 | J(2:2:end-1,2:2:end-1) = ... 227 | 0.25*I(1:end-1,1:end-1) + ... 228 | 0.25*I(2:end,1:end-1) + ... 229 | 0.25*I(1:end-1,2:end) + ... 230 | 0.25*I(2:end,2:end) ; 231 | J(2:2:end-1,1:2:end) = ... 232 | 0.5*I(1:end-1,:) + ... 233 | 0.5*I(2:end,:) ; 234 | J(1:2:end,2:2:end-1) = ... 235 | 0.5*I(:,1:end-1) + ... 236 | 0.5*I(:,2:end) ; 237 | end 238 | 239 | function J = halveSize(I) 240 | J=I(1:2:end,1:2:end) ; 241 | end 242 | %************************************************************************* 243 | 244 | %************************************************************************** 245 | function im=gauss_filter(image,sigma) 246 | G = fspecial('gaussian',[5 5],sigma); 247 | im=imfilter(image,G,'same'); 248 | end 249 | %************************************************************************** 250 | 251 | %************************************************************************** 252 | function [points2]=localize_eliminate(points,up,down,curr,thr,r) 253 | points2=zeros(2,1); 254 | t=1; 255 | for i=1:size(points,2) 256 | x=points(1,i); 257 | y=points(2,i); 258 | fxx= curr(x-1,y)+curr(x+1,y)-2*curr(x,y); % double derivate in x direction 259 | fyy= curr(x,y-1)+curr(x,y+1)-2*curr(x,y); % double derivate in y direction 260 | fsigmasigma=up(x,y)+down(x,y)-2*curr(x,y); % double derivate in sigma direction 261 | 262 | 263 | fxsigma=((up(x+1,y)-down(x+1,y))-(up(x-1,y)-down(x-1,y)))/4;%derivate in x and sigma direction 264 | fysigma=((up(x,y+1)-down(x,y+1))-(up(x,y-1)-down(x,y-1)))/4;%derivate in y and sigma direction 265 | fxy= curr(x-1,y-1)+curr(x+1,y+1)-curr(x-1,y+1)-curr(x+1,y-1); %derivate inx and y direction 266 | 267 | fx=curr(x,y)-curr(x-1,y);%derivate in x direction 268 | fy=curr(x,y)-curr(x,y-1);%derivate in y direction 269 | fsigma=(up(x,y)-down(x,y))/2;%derivate in sigma direction 270 | 271 | %localization using Teilor seri 272 | A=[fsigmasigma fxsigma fysigma;fxsigma fxx fxy;fysigma fxy fyy]; 273 | X=-inv(A)*([fsigma fx fy]'); 274 | 275 | 276 | x_hat=X(2); 277 | y_hat=X(3); 278 | if abs(x_hat)<4 && abs(y_hat)<4 %ignor the ofsets > 4 279 | px=round(x+x_hat); 280 | py=round(y+y_hat); 281 | else 282 | px=x; 283 | py=y; 284 | %[px py] 285 | end 286 | 287 | 288 | 289 | D_hat=curr(px,py)+([fsigma fx fy]*X)/2; 290 | if abs(D_hat)>thr%% filter some low contrast points 291 | if (fxx+fyy)^2/(fxx*fyy-fxy^2)<(r+1)^2/r % remove edge points 292 | points2(1,t)=px;points2(2,t)=py; 293 | t=t+1; 294 | end 295 | end 296 | 297 | 298 | end 299 | 300 | end 301 | %************************************************************************** 302 | 303 | %************************************************************************** 304 | function indx=search_exterm(up,down,im) 305 | [m n]=size(im); 306 | t=1; 307 | thr=.004; 308 | indx=[0;0]; 309 | 310 | for i=2:m-1 311 | for j=2:n-1 312 | 313 | if im(i,j)> thr 314 | window(1:3,1:3)=down(i-1:i+1,j-1:j+1); 315 | window(4:6,1:3)=im(i-1:i+1,j-1:j+1); 316 | window(7:9,1:3)=up(i-1:i+1,j-1:j+1); 317 | window(5,2)=-100; 318 | if im(i,j)>max(max(window)) 319 | indx(:,t)=[i j]'; 320 | t=t+1; 321 | end 322 | end 323 | 324 | if im(i,j)<-thr 325 | window(1:3,1:3)=down(i-1:i+1,j-1:j+1); 326 | window(4:6,1:3)=im(i-1:i+1,j-1:j+1); 327 | window(7:9,1:3)=up(i-1:i+1,j-1:j+1); 328 | window(5,2)=100; 329 | if im(i,j)=t); 35 | 36 | % build interest points 37 | points = [r,c]; 38 | end -------------------------------------------------------------------------------- /MyCodes/kp_harrislaplace.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/MyCodes/kp_harrislaplace.m -------------------------------------------------------------------------------- /MyCodes/match_images.m: -------------------------------------------------------------------------------- 1 | function [abc] = match_images(filePathIndexToRead, keypointDetection, featureExtraction,alsoEvaluate,thresholdForMatch) 2 | %SET THIS VALUES BEFORE USING THE PROGRAM 3 | 4 | directory = dir( '../data/'); 5 | filePathToRead = directory(filePathIndexToRead).name; 6 | 7 | fprintf(strcat(char(filePathToRead),' folder is going to be read to match images.')); 8 | fprintf('\n') 9 | 10 | filepath1 = strcat('../data/',filePathToRead); 11 | filepath1 = strcat (filepath1, '/01.png'); 12 | image1 = imread(filepath1); 13 | 14 | filepath2 = strcat('../data/',filePathToRead); 15 | filepath2 = strcat (filepath2, '/02.png'); 16 | image2 = imread(filepath2); 17 | 18 | fileNameToWrite= strcat(strcat(strcat(filePathToRead,char(keypointDetection)),char(featureExtraction)) ,'.jpg'); 19 | 20 | scalee = 1; 21 | featureWidth = 16; %width and height of each local feature, in pixels. 22 | 23 | image1 = rgb2gray(single(image1)/255); 24 | image2 = rgb2gray(single(image2)/255); 25 | 26 | image1 = imresize(image1, scalee, 'bilinear'); 27 | image2 = imresize(image2, scalee, 'bilinear'); 28 | 29 | 30 | %% Decision 31 | if keypointDetection == KeyPointDetector.HARRIS 32 | [x1, y1] = get_Harris_keypoints(image1, featureWidth); 33 | [x2, y2] = get_Harris_keypoints(image2, featureWidth); 34 | 35 | elseif keypointDetection == KeyPointDetector.MSER 36 | [x1, y1] = get_MSER_keypoints(image1, featureWidth); 37 | [x2, y2] = get_MSER_keypoints(image2, featureWidth); 38 | 39 | elseif keypointDetection == KeyPointDetector.DOG 40 | [x1, y1] = get_DOG_keypoints(image1, featureWidth); 41 | [x2, y2] = get_DOG_keypoints(image2, featureWidth); 42 | end 43 | 44 | if featureExtraction == FeatureExtractor.SIFT 45 | [image1Features] = extract_SIFT_features(image1, x1, y1, featureWidth); 46 | [image2Features] = extract_SIFT_features(image2, x2, y2, featureWidth); 47 | elseif featureExtraction == FeatureExtractor.PCASIFT 48 | [image1Features] = extract_PCASIFT_features(image1, x1, y1, featureWidth); 49 | [image2Features] = extract_PCASIFT_features(image2, x2, y2, featureWidth); 50 | elseif featureExtraction == FeatureExtractor.GLOH 51 | [image1Features] = extract_GLOH_features(image1, x1, y1, featureWidth); 52 | [image2Features] = extract_GLOH_features(image2, x2, y2, featureWidth); 53 | end 54 | %% 55 | fprintf(strcat(char(keypointDetection),' is going to be used as key point detector')); 56 | fprintf('\n') 57 | fprintf(strcat(char(featureExtraction),' is going to be used as feature extractor')); 58 | fprintf('\n') 59 | 60 | %% Match points and features. 61 | [matches, confidences] = match_points(image1Features, image2Features,thresholdForMatch); 62 | 63 | numberOfPointToSee = size(matches,1); 64 | 65 | showCorrespondence(image1, image2, x1(matches(1:numberOfPointToSee,1)), ... 66 | y1(matches(1:numberOfPointToSee,1)), ... 67 | x2(matches(1:numberOfPointToSee,2)), ... 68 | y2(matches(1:numberOfPointToSee,2)),fileNameToWrite); 69 | %% evaluate correspondences 70 | if alsoEvaluate 71 | evaluateCorrespondence(image1,image2,x1(matches(1:numberOfPointToSee,1))/scalee, ... 72 | y1(matches(1:numberOfPointToSee,1))/scalee, ... 73 | x2(matches(1:numberOfPointToSee,2))/scalee, ... 74 | y2(matches(1:numberOfPointToSee,2))/scalee,filePathToRead,fileNameToWrite); 75 | end -------------------------------------------------------------------------------- /MyCodes/match_points.m: -------------------------------------------------------------------------------- 1 | function [matches, confidences] = match_points(features1, features2,threshold) 2 | 3 | distanceMatrix = calculate_feature_distance(features1, features2); 4 | 5 | [sortedDistanceMatrix, indices] = sort(distanceMatrix, 2); 6 | inverseConfidences = (sortedDistanceMatrix(:,1)./sortedDistanceMatrix(:,2)); 7 | confidences = 1./inverseConfidences(inverseConfidences < threshold); 8 | 9 | matches = zeros(size(confidences,1), 2); 10 | matches(:,1) = find(inverseConfidences < threshold); 11 | matches(:,2) = indices(inverseConfidences < threshold, 1); 12 | 13 | % Sort the matches. the highest confident values are at the top of the 14 | % list. 15 | [confidences, ind] = sort(confidences, 'descend'); 16 | matches = matches(ind,:); -------------------------------------------------------------------------------- /MyCodes/other_tries.m: -------------------------------------------------------------------------------- 1 | function test() 2 | % The test function gives an example of keypoint extraction using the 3 | % methods : 4 | % - Harris 5 | % - SUSAN 6 | % - LoG (Laplacian of Gaussian) 7 | % - Harris-Laplace 8 | % - Gilles 9 | % 10 | % Example 11 | % ======= 12 | % test(); 13 | 14 | % Harris 15 | img = imread('../data/notredame/01.png'); 16 | pt = kp_harris(img); 17 | draw(img,pt,'Harris'); 18 | 19 | 20 | 21 | % Harris-Laplace 22 | 23 | pt = kp_harrislaplace(rgb2gray(img)); 24 | draw(img,pt,'Harris Laplace'); 25 | 26 | 27 | 28 | end 29 | 30 | function draw(img,pt,str) 31 | figure('Name',str); 32 | imshow(img); 33 | hold on; 34 | axis off; 35 | switch size(pt,2) 36 | case 2 37 | s = 2; 38 | for i=1:size(pt,1) 39 | rectangle('Position',[pt(i,2)-s,pt(i,1)-s,2*s,2*s],'Curvature',[0 0],'EdgeColor','b','LineWidth',2); 40 | end 41 | case 3 42 | for i=1:size(pt,1) 43 | rectangle('Position',[pt(i,2)-pt(i,3),pt(i,1)-pt(i,3),2*pt(i,3),2*pt(i,3)],'Curvature',[1,1],'EdgeColor','w','LineWidth',2); 44 | end 45 | end 46 | end -------------------------------------------------------------------------------- /MyCodes/runner.m: -------------------------------------------------------------------------------- 1 | %% 2 | close all 3 | clear all 4 | %% THE FILE TO READ!!!!!!!! ...th folder in the directory. (IN DATA FOLDER) 5 | % . is first one (dont chooise this) 6 | % .. is the second one (dont chooise this) 7 | % start from 3! 8 | %% 9 | close all 10 | clear all 11 | %% THE FILE TO READ!!!!!!!! ...th folder in the directory. (IN DATA FOLDER) 12 | % . is first one (dont chooise this) 13 | % .. is the second one (dont chooise this) 14 | % start from 3! 15 | filePathIndexToRead = 4;%2TH FOLDER IN DATA DIRECTORY, 3 is the first one, 4 is second one! and it goes on... 16 | alsoEvaluate = true(1); %boolean : wheter evaluation step is going be happen or not. 17 | treshold= 0.8; 18 | 19 | keypointDetection = KeyPointDetector.MSER;%HARRIS,MSER,DOG 20 | featureExtraction = FeatureExtractor.SIFT;%SIFT,PCASIFT,GLOH 21 | match_images(filePathIndexToRead,keypointDetection,featureExtraction,alsoEvaluate,treshold); 22 | 23 | 24 | %OUTPUT WiLL BE SAVED TO RESULTS DIRECTORY -------------------------------------------------------------------------------- /MyCodes/runnerAllOfTheImages.m: -------------------------------------------------------------------------------- 1 | %% 2 | close all 3 | clear all 4 | %% THE FILE TO READ!!!!!!!! ...th folder in the directory. (IN DATA FOLDER) 5 | % . is first one (dont chooise this) 6 | % .. is the second one (dont chooise this) 7 | % start from 3! 8 | alsoEvaluate = false(1); %boolean : wheter evaluation step is going be happen or not 9 | treshold= 0.8;%play with treshold for better results 10 | for i = 3:7%DIRECTORY INDICES, run runner to work with a single image. 11 | %%SIFT 12 | %%SET ENUM VALUES 13 | keypointDetection = KeyPointDetector.HARRIS;%HARRIS 14 | featureExtraction = FeatureExtractor.SIFT;%SIFT 15 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 16 | 17 | keypointDetection = KeyPointDetector.MSER;%MSER, 18 | featureExtraction = FeatureExtractor.SIFT;%SIFT 19 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 20 | 21 | keypointDetection = KeyPointDetector.DOG;%DOG 22 | featureExtraction = FeatureExtractor.SIFT;%SIFT 23 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 24 | %%PCA SIFT 25 | keypointDetection = KeyPointDetector.HARRIS;%HARRIS 26 | featureExtraction = FeatureExtractor.PCASIFT;%PCASIFT 27 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 28 | 29 | keypointDetection = KeyPointDetector.MSER;%MSER 30 | featureExtraction = FeatureExtractor.PCASIFT;%PCASIFT 31 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 32 | 33 | keypointDetection = KeyPointDetector.DOG;%,DOG 34 | featureExtraction = FeatureExtractor.PCASIFT;%PCASIFT 35 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 36 | 37 | %%GLOH 38 | keypointDetection = KeyPointDetector.HARRIS;%HARRIS 39 | featureExtraction = FeatureExtractor.GLOH;%GLOH 40 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 41 | 42 | keypointDetection = KeyPointDetector.MSER;%MSER 43 | featureExtraction = FeatureExtractor.GLOH;%GLOH 44 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 45 | 46 | keypointDetection = KeyPointDetector.DOG;%DOG 47 | featureExtraction = FeatureExtractor.GLOH;%GLOH 48 | match_images(i,keypointDetection,featureExtraction,alsoEvaluate,treshold); 49 | end 50 | %OUTPUT WiLL BE SAVED TO RESULTS DIRECTORY -------------------------------------------------------------------------------- /MyCodes/showAllCorrespondences.m: -------------------------------------------------------------------------------- 1 | function showAllCorrespondences() 2 | 3 | image1 = imread('../data/notredame/01.png'); 4 | image2 = imread('../data/notredame/02.png'); 5 | 6 | allMatches = '../data/notredame/allmatches.mat'; 7 | 8 | load(allMatches) 9 | 10 | showCorrespondence(image1, image2, x1, y1, x2, y2,'allMatches') -------------------------------------------------------------------------------- /MyCodes/showCorrespondence.m: -------------------------------------------------------------------------------- 1 | function [ h ] = showConnection(image1, image2, X1, Y1, X2, Y2,fileNameToWrite) 2 | 3 | 4 | h = figure; 5 | set(h, 'Position', [100 100 800 600]) 6 | subplot(1,2,1); 7 | imshow(image1, 'Border', 'tight') 8 | subplot(1,2,2); 9 | imshow(image2, 'Border', 'tight') 10 | 11 | for i = 1:size(X1,1) 12 | title(strcat(fileNameToWrite,'_02')) 13 | cur_color = rand(3,1); 14 | subplot(1,2,1); 15 | hold on; 16 | plot(X1(i),Y1(i), 'o', 'LineWidth',2, 'MarkerEdgeColor','k',... 17 | 'MarkerFaceColor', cur_color, 'MarkerSize',10) 18 | 19 | hold off; 20 | title(strcat(fileNameToWrite,'_01')) 21 | subplot(1,2,2); 22 | hold on; 23 | plot(X2(i),Y2(i), 'o', 'LineWidth',2, 'MarkerEdgeColor','k',... 24 | 'MarkerFaceColor', cur_color, 'MarkerSize',10) 25 | hold off; 26 | end 27 | 28 | fileName = strcat('Saving correspondences to \t',fileNameToWrite); 29 | 30 | fprintf(fileName) 31 | fprintf('\n') 32 | 33 | visualization_image = frame2im(getframe(h)); 34 | 35 | try 36 | visualization_image = visualization_image(81:end-80, 51:end-50,:); 37 | catch 38 | ; 39 | end 40 | imwrite(visualization_image, strcat('RESULTS/',fileNameToWrite), 'quality', 100) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComputerVision-LocalFeatures 2 | Feature detection and matching are an essential component of many computer vision applications. It is used for variety of applications for example aligning the two images so that they can be seamlessly stitched into a composite mosaics or establishing a dense set of correspondences so that a 3D model can be constructed. But selecting the features to compare and match the images is a still ongoing search area. There have been many algorithms implemented for this purpose. In this assignment we try to implement and review some algorithms like HARRIS, MSER, SIFT, PCA-SIFT, GLOH and then we test our algorithms in the symfeat dataset that contains image pairs exhibiting a range of dramatic variations in lighting, age, and rendering style. 3 | 4 | -------------------------------------------------------------------------------- /data/arch/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/arch/01.png -------------------------------------------------------------------------------- /data/arch/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/arch/02.png -------------------------------------------------------------------------------- /data/arch/H1to2: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | 0 1 0 3 | 0 0 1 4 | -------------------------------------------------------------------------------- /data/notredame/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/notredame/01.png -------------------------------------------------------------------------------- /data/notredame/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/notredame/02.png -------------------------------------------------------------------------------- /data/notredame/H1to2: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | 0 1 0 3 | 0 0 1 4 | -------------------------------------------------------------------------------- /data/notredame/allmatches.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/notredame/allmatches.mat -------------------------------------------------------------------------------- /data/sanmarco/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/sanmarco/01.png -------------------------------------------------------------------------------- /data/sanmarco/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/sanmarco/02.png -------------------------------------------------------------------------------- /data/sanmarco/H1to2: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | 0 1 0 3 | 0 0 1 4 | -------------------------------------------------------------------------------- /data/stargarder3/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/stargarder3/01.png -------------------------------------------------------------------------------- /data/stargarder3/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/stargarder3/02.png -------------------------------------------------------------------------------- /data/stargarder3/H1to2: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | 0 1 0 3 | 0 0 1 4 | -------------------------------------------------------------------------------- /data/worldbuilding/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/worldbuilding/01.png -------------------------------------------------------------------------------- /data/worldbuilding/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErolOZKAN-/ComputerVision-LocalFeatures/a7302be7032887e648b6acdf7ba2da20371cb0df/data/worldbuilding/02.png -------------------------------------------------------------------------------- /data/worldbuilding/H1to2: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | 0 1 0 3 | 0 0 1 4 | --------------------------------------------------------------------------------