├── .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 |
--------------------------------------------------------------------------------