Skip to content

Fix/vlfeat compliance#112

Closed
griwodz wants to merge 33 commits intodevelopfrom
fix/vlfeatCompliance
Closed

Fix/vlfeat compliance#112
griwodz wants to merge 33 commits intodevelopfrom
fix/vlfeatCompliance

Conversation

@griwodz
Copy link
Copy Markdown
Member

@griwodz griwodz commented Oct 5, 2020

Description

The proposed change adds a descriptor computation that is compliant with VLFeat. The original PopSift descriptor was not because it used the angle differently: while VLFeat spreads the angular part of the descriptor over up to 8 bins of the descriptor's histogram, PopSift would only spread it over two. Furthermore, descriptors are arranged differently into the histograms (according to VLFeat documentation, VLFeat does that also differently from Lowe's original code).

Features list

For backward compatibility, the VLFeat descriptor is not the default descriptor. The following settings lead to results that seem to be identical to the VLFeat 0.9.20 C code and command line (the 0.9.21 command line does not work):

--desc-mode=vlfeat              : use the VLFeat descriptor extraction
--norm-mode=classic             : use L2 normalization, not RootSift
--norm-multi 9 --write-as-uchar : multiply descriptor values with 2^9 and cast to uchar
--write-with-ori                : output of descriptors in the same format as VLFeat command line (instead of OpenCV-compliant)
--initial-blur 0.5              : PopSift default
--sigma 1.6                     : PopSift default
--threshold 0                   : set the peak threshold to 0
--edge-threshold 10.0           : PopSift default

Implementation remarks

The L2 normalization had a bug that was removed.

The orientation computation does now use a bilateral filter, which does not appear to have any visible effect. This is a change from the previous PopSift default, and it may be safer to make it a VLFeat-specific option.

The threshold for accepting an orientation in VLFeat is computed before smoothing the histogram, PopSift did it after computing the histogram (consequently accepting fewer orientations). This was change to work like VLFeat.

@griwodz griwodz self-assigned this Oct 5, 2020
@griwodz griwodz added bugfix cuda issues related to cuda versions feature request prio:critical labels Oct 5, 2020
@griwodz griwodz added this to the v1.0.0 milestone Oct 5, 2020
}
norm = popsift::shuffle( norm, 0 );

descr.x = min( descr.x, 0.2f*norm );
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a direct comparison between the develop branch and develop with the L2 normalization bug fixed.
I compare the descriptors extracted from all images in the dataset containing boat, bark, bikes, graf, leuven, tree, ubc and wall.
The average number of descriptors extracted per image was 10000.
The largest difference before and after the fix was 2 descriptors changed in 1 value.

Comment thread src/application/main.cpp Outdated
Comment thread src/application/main.cpp Outdated
"loop, iloop, grid, igrid, notile, vlfeat\n"
"Default is loop\n"
"loop is OpenCV-like horizontal scanning, computing only valid points, grid extracts only useful points but rounds them, iloop uses linear texture and rotated gradiant fetching. igrid is grid with linear interpolation. notile is like igrid but avoids redundant gradiant fetching.")
"loop is OpenCV-like horizontal scanning, computing only valid points, grid extracts only useful points but rounds them, iloop uses linear texture and rotated gradiant fetching. igrid is grid with linear interpolation. notile is like igrid but avoids redundant gradiant fetching, vlfeat replicates vlfeat behaviour.")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe briefly remind the vlfeat behaviour like done for opencv for example

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have extended it and move it to Config::getDescModeUsage(). The usage is getting very long, I wonder if we should re-write this to support --desc-mode=?

Comment thread src/popsift/sift_conf.h Outdated
/// variant of IGrid, no duplicate gradient fetching
NoTile
NoTile,
/// extraction code according to VLFeat
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, maybe briefly remind the difference so we have it in the doc

Comment thread src/popsift/s_orientation.cu Outdated
/*
* Histogram smoothing helper
*/
#ifdef WITH_VLFEAT_SMOOTHING
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be better to use POPSIFT_WITH_VLFEAT_SMOOTHING or POPSIFT_USE_VLFEAT_SMOOTHING to avoid conflict and for consistency through repositories.

Also, is this supposed to be an option the user can choose or is it gonna be a kind of debugging or dev-only feature?
In the first case, we should then also add the option in cmake and add the definition at compile time

option(PopSift_USE_VLFEAT_SMOOTHING "Use VLFeat smoothing." ON)

...

# set the variable
if(PopSift_USE_VLFEAT_SMOOTHING)
  set(POPSIFT_USE_VLFEAT_SMOOTHING   1)
else()
  set(POPSIFT_USE_VLFEAT_SMOOTHING   0)
endif()

...

# add also the message in the final summary
message("******************************************")
message("Building configuration:\n")
message(STATUS "PopSift version: " ${PROJECT_VERSION})
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
...
message(STATUS "Using VLFeat smoothing: " ${POPSIFT_USE_VLFEAT_SMOOTHING})

and add the entry in cmake/sift_config.h

#define POPSIFT_USE_VLFEAT_SMOOTHING()            @POPSIFT_USE_VLFEAT_SMOOTHING@

and #include <popsift/sift_config.h> wherever it is used

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove the alternative and keep only VLFEAT_SMOOTHING. This is from the original development and the other setting has never been used.

Comment thread src/popsift/s_orientation.cu Outdated
/* Bilinear histogram seems to be VLFeat's default now.
* We emulate it because we have different orientations without it.
*/
#define WITH_BILINEAR_ORI
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as WITH_VLFEAT_SMOOTHING

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just comparing the effect of every little change on the descriptors. I think that the difference is big enough to make WITH_BILINEAR_ORI a Config parameter instead of a define.

Comment thread src/popsift/s_orientation.cu Outdated
bool predicate = ( bin < ORI_NBINS ) && ( sm_hist[bin] > max( sm_hist[prev], sm_hist[next] ) );
bool predicate = ( bin < ORI_NBINS ) && ( sm_hist[bin] > max( sm_hist[prev], sm_hist[next] ) ) && (sm_hist[bin] > 0.8f * maxval);

#define REFINE 2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can use WITH_VLFEAT_SMOOTHING or WITH_BILINEAR_ORI?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed WITH_VLFEAT_SMOOTHING because we have used only "true" for years.
I have replaced WITH_BILINEAR_ORI with a command line switch --ori-mode=BestBin or InterpolatedBin. The first is original PopSift behaviour, the second current VLFeat behaviour. But note that VLFeat is also using a #define to support BestBin instead.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 8, 2020

Seeing the descriptor distances, I have to go back to the code and check if there's a place in the code where I'm swapping the flags, because this is weird.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 11, 2020

@simogasp @fabiencastan Now it is really time to compare the VLFeat-compatible descriptor with the VLFeat-trained voctree. Our original orientation computation was never the problem, the descriptor computation is different. This led to a different probability distribution of values in the descriptors' 128 floats, which explains why the voctree code couldn't find matches with PopSift.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 11, 2020

This is the difference in the individual cells of the old PopSift descriptor. The 128 values are 4x4 histograms of 8 rotational bins each. The figure shows the 8 bins sides by side, for each bin the average difference between VLFeat and PopSift descritors for a 4x4 group.

descdist-boat1-new

You can see that the PopSift descriptor values are generally higher in the first bin, lower in the later bins.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 11, 2020

Now, with the VLFeat-compatible descriptor, it looks like this:

descdist-boat1-vlfeatdesc

The distribution is now pretty much identical.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 11, 2020

The success for correct matching is also quite a bit better. The figure shows L2 distance between the best descriptors (in purple) between the old descriptor on the left and VLFeat-compatible descriptor in the right.

descriptor

Comment thread src/popsift/sift_conf.cu Outdated
Comment thread src/popsift/sift_conf.cu

static bool stringIsame( string l, string r )
{
std::for_each( l.begin(), l.end(), [](char& c) { c = ::tolower(c); });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::for_each( l.begin(), l.end(), [](char& c) { c = ::tolower(c); });
// early exit
if(l.size() != r.size())
{
return false;
}
std::for_each( l.begin(), l.end(), [](char& c) { c = ::tolower(c); });

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take the proposed change. I wanted to go for strncmp, but Windows does apparently not have it, it has stricmp. And adding Boost just for this seemed like too much.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simogasp It would be really preferable to use strcasecmp() for non-Windows and _stricmp() for Windows. The first requires inclusion of strings.h (at least on Linux and Mac) and the other string.h. The first one is a function, the second is a macro. I'm too stupid to write a CMake test, so I gave up and wrote these crappy lines to make it run.
And is speed essential? It should be used to evaluate the command line.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is ok like this, it is just for comparing the string in the enum. And I agree that it's not worth to re-add boost just for this.

@griwodz
Copy link
Copy Markdown
Member Author

griwodz commented Oct 12, 2020

Btw.: the nice results were created with the following command line:
popsift-demo --pgmread-loading --norm-mode=classic --norm-multi 9 --write-as-uchar --write-with-ori --initial-blur 0.5 --sigma 1.6 --threshold 0 --edge-threshold 10.0 --desc-mode=vlfeat -i boat.pgm

@griwodz griwodz removed cuda issues related to cuda versions feature request prio:critical labels Oct 16, 2020
@griwodz griwodz mentioned this pull request Oct 16, 2020
@griwodz griwodz closed this Jan 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants