.2.0+dfsg_contrib_modules_line_descriptor_tutorials_tutorial
In this tutorial it will be shown how to:
- use the BinaryDescriptor interface to extract lines and store them in KeyLine objects
- use the same interface to compute descriptors for every extracted line
- use the BynaryDescriptorMatcher to determine matches among descriptors obtained from different images
Lines extraction and descriptors computation
In the following snippet of code, it is shown how to detect lines from an image. The LSD extractor is initialized with LSD_REFINE_ADV option; remaining parameters are left to their default values. A mask of ones is used in order to accept all extracted lines, which, at the end, are displayed using random colors for octave 0.
55 static const char* keys =
56 {
"{@image_path | | Image path }" };
60 cout <<
"\nThis example shows the functionalities of lines extraction " <<
"furnished by BinaryDescriptor class\n"
61 <<
"Please, run this sample using a command in the form\n" <<
"./example_line_descriptor_lines_extraction <path_to_input_image>" << endl;
64 int main(
int argc,
char** argv )
70 if( image_path.
empty() )
78 if( imageMat.
data == NULL )
80 std::cout <<
"Error, image could not be loaded. Please, check its path" << std::endl;
91 vector<KeyLine> lines;
95 bd->
detect( imageMat, lines, 2, 1, mask );
100 for (
size_t i = 0;
i < lines.size();
i++ )
106 int R = ( rand() % (int) ( 255 + 1 ) );
107 int G = ( rand() % (int) ( 255 + 1 ) );
108 int B = ( rand() % (int) ( 255 + 1 ) );
115 line( output, pt1, pt2,
Scalar( B, G, R ), 3 );
121 imshow(
"LSD lines", output );
This is the result obtained for famous cameraman image:
Another way to extract lines is using LSDDetector class; such class uses the LSD extractor to compute lines. To obtain this result, it is sufficient to use the snippet code seen above, just modifying it by the rows
Ptr<LSDDetector> lsd = LSDDetector::createLSDDetector();
std::vector<KeyLine> keylines;
lsd->detect( imageMat, keylines, mask );
Here's the result returned by LSD detector again on cameraman picture:
Once keylines have been detected, it is possible to compute their descriptors as shown in the following:
55 static const char* keys =
56 {
"{@image_path | | Image path }" };
60 std::cout <<
"\nThis example shows the functionalities of lines extraction " <<
"and descriptors computation furnished by BinaryDescriptor class\n"
61 <<
"Please, run this sample using a command in the form\n" <<
"./example_line_descriptor_compute_descriptors <path_to_input_image>"
65 int main(
int argc,
char** argv )
71 if( image_path.
empty() )
79 if( imageMat.
data == NULL )
81 std::cout <<
"Error, image could not be loaded. Please, check its path" << std::endl;
91 std::vector<KeyLine> keylines;
92 bd->
detect( imageMat, keylines, mask );
97 bd->
compute( imageMat, keylines, descriptors);
Matching among descriptors
If we have extracted descriptors from two different images, it is possible to search for matches among them. One way of doing it is matching exactly a descriptor to each input query descriptor, choosing the one at closest distance:
51 #define MATCHES_DIST_THRESHOLD 25
56 static const char* keys =
57 {
"{@image_path1 | | Image path 1 }"
58 "{@image_path2 | | Image path 2 }" };
62 std::cout <<
"\nThis example shows the functionalities of lines extraction " <<
"and descriptors computation furnished by BinaryDescriptor class\n"
63 <<
"Please, run this sample using a command in the form\n" <<
"./example_line_descriptor_compute_descriptors <path_to_input_image 1>"
64 <<
"<path_to_input_image 2>" << std::endl;
68 int main(
int argc,
char** argv )
75 if( image_path1.
empty() || image_path2.empty() )
85 if( imageMat1.
data == NULL || imageMat2.
data == NULL )
87 std::cout <<
"Error, images could not be loaded. Please, check their path" << std::endl;
98 std::vector<KeyLine> keylines1, keylines2;
101 ( *bd )( imageMat1, mask1, keylines1, descr1,
false, false );
102 ( *bd )( imageMat2, mask2, keylines2, descr2,
false, false );
105 std::vector<KeyLine> lbd_octave1, lbd_octave2;
106 Mat left_lbd, right_lbd;
107 for (
int i = 0;
i < (int) keylines1.size();
i++ )
109 if( keylines1[
i].octave == 0 )
116 for (
int j = 0; j < (int) keylines2.size(); j++ )
118 if( keylines2[j].octave == 0 )
120 lbd_octave2.push_back( keylines2[j] );
129 std::vector<DMatch> matches;
130 bdm->
match( left_lbd, right_lbd, matches );
133 std::vector<DMatch> good_matches;
134 for (
int i = 0;
i < (int) matches.size();
i++ )
136 if( matches[
i].distance < MATCHES_DIST_THRESHOLD )
137 good_matches.push_back( matches[
i] );
143 std::vector<char> mask( matches.size(), 1 );
147 imshow(
"Matches", outImg );
149 imwrite(
"/home/ubisum/Desktop/images/env_match/matches.jpg", outImg);
154 std::vector<KeyLine> klsd1, klsd2;
155 Mat lsd_descr1, lsd_descr2;
156 lsd->
detect( imageMat1, klsd1, 2, 2, mask1 );
157 lsd->
detect( imageMat2, klsd2, 2, 2, mask2 );
160 bd->
compute( imageMat1, klsd1, lsd_descr1 );
161 bd->
compute( imageMat2, klsd2, lsd_descr2 );
164 std::vector<KeyLine> octave0_1, octave0_2;
165 Mat leftDEscr, rightDescr;
166 for (
int i = 0;
i < (int) klsd1.size();
i++ )
168 if( klsd1[
i].octave == 1 )
170 octave0_1.push_back( klsd1[
i] );
175 for (
int j = 0; j < (int) klsd2.size(); j++ )
177 if( klsd2[j].octave == 1 )
179 octave0_2.push_back( klsd2[j] );
185 std::vector<DMatch> lsd_matches;
186 bdm->
match( leftDEscr, rightDescr, lsd_matches );
189 good_matches.clear();
190 for (
int i = 0;
i < (int) lsd_matches.size();
i++ )
192 if( lsd_matches[
i].distance < MATCHES_DIST_THRESHOLD )
193 good_matches.push_back( lsd_matches[
i] );
198 resize( imageMat1, imageMat1,
Size( imageMat1.cols / 2, imageMat1.rows / 2 ) );
199 resize( imageMat2, imageMat2,
Size( imageMat2.cols / 2, imageMat2.rows / 2 ) );
200 std::vector<char> lsd_mask( matches.size(), 1 );
204 imshow(
"LSD matches", lsd_outImg );
Sometimes, we could be interested in searching for the closest k descriptors, given an input one. This requires to modify slightly previous code:
std::vector<std::vector<DMatch> > matches;
bdm->knnMatch( descr1, descr2, matches, 6 );
In the above example, the closest 6 descriptors are returned for every query. In some cases, we could have a search radius and look for all descriptors distant at the most r from input query. Previous code must me modified:
std::vector<std::vector<DMatch> > matches;
bdm->radiusMatch( queries, matches, 30 );
Here's an example om matching among descriptors extratced from original cameraman image and its downsampled (and blurred) version:
Querying internal database
The BynaryDescriptorMatcher class, owns an internal database that can be populated with descriptors extracted from different images and queried using one of the modalities described in previous section. Population of internal dataset can be done using the add function; such function doesn't directly add new data to database, but it just stores it them locally. The real update happens when function train is invoked or when any querying function is executed, since each of them invokes train before querying. When queried, internal database not only returns required descriptors, but, for every returned match, it is able to tell which image matched descriptor was extracted from. An example of internal dataset usage is described in the following code; after adding locally new descriptors, a radius search is invoked. This provokes local data to be transferred to dataset, which, in turn, is then queried.
55 static const std::string images[] =
56 {
"cameraman.jpg",
"church.jpg",
"church2.png",
"einstein.jpg",
"stuff.jpg" };
58 static const char* keys =
59 {
"{@image_path | | Image path }" };
63 std::cout <<
"\nThis example shows the functionalities of radius matching " <<
"Please, run this sample using a command in the form\n"
64 <<
"./example_line_descriptor_radius_matching <path_to_input_images>/" << std::endl;
67 int main(
int argc,
char** argv )
74 int num_elements =
sizeof ( images ) /
sizeof ( images[0] );
75 std::vector < Mat > descriptorsMat;
76 std::vector < std::vector<KeyLine> > linesMat;
82 for (
int i = 0;
i < num_elements;
i++ )
85 std::stringstream image_path;
86 image_path << pathToImages << images[
i];
87 std::cout << image_path.str().
c_str() << std::endl;
90 Mat loadedImage =
imread( image_path.str().c_str(), 1 );
91 if( loadedImage.
data == NULL )
93 std::cout <<
"Could not load images." << std::endl;
99 std::vector < KeyLine > lines;
101 bd->
detect( loadedImage, lines );
102 bd->
compute( loadedImage, lines, computedDescr );
104 descriptorsMat.push_back( computedDescr );
105 linesMat.push_back( lines );
111 for (
size_t j = 0; j < descriptorsMat.size(); j++ )
113 if( descriptorsMat[j].rows >= 5 )
114 queries.
push_back( descriptorsMat[j].rowRange( 0, 5 ) );
116 else if( descriptorsMat[j].rows > 0 && descriptorsMat[j].rows < 5 )
120 std::cout <<
"It has been generated a matrix of " << queries.
rows <<
" descriptors" << std::endl;
126 bdm->
add( descriptorsMat );
129 std::vector < std::vector<DMatch> > matches;
131 std::cout <<
"size matches sample " << matches.size() << std::endl;
133 for (
int i = 0;
i < (int) matches.size();
i++ )
135 for (
int j = 0; j < (int) matches[
i].size(); j++ )
137 std::cout <<
"match: " << matches[
i][j].queryIdx <<
" " << matches[
i][j].trainIdx <<
" " << matches[
i][j].distance << std::endl;