-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Localizer/works without cost matrix #32
base: main
Are you sure you want to change the base?
Conversation
… consistency on all code parts then
… consistency on all code parts then
@niosus, could you have a look at C++ part? Thank you :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, the logic is easy to follow and the code is well written and styled. So I am approving the PR.
That being said, there was a couple of places where the code can be slightly improved to follow best practices and reduce the potential for future errors creeping up. Please see the comments in the code for those.
namespace loc = localization; | ||
|
||
std::vector<std::unique_ptr<loc::features::iFeature>> | ||
loadFeatures(const std::string &path2folder) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good practice to put functions in a cpp
file into an unnamed namespace to enforce internal linkage of these functions, i.e., to guarantee that they are only visible from this file. So I would put the loadFeatures
function in one:
namespace {
std::vector<std::unique_ptr<loc::features::iFeature>>
loadFeatures(const std::string &path2folder) {...}
} // namespace
LOG(INFO) << "Loading the features to hash with LSH."; | ||
std::vector<std::string> featureNames = | ||
loc::database::listProtoDir(path2folder, ".Feature"); | ||
std::vector<std::unique_ptr<loc::features::iFeature>> features; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you might want to reserve the memory for the features if you have a lot of those:
features.reserve(featureNames.size());
LOG(INFO) << "===== Online place recognition with LSH ====\n"; | ||
|
||
if (argc < 2) { | ||
printf("[ERROR] Not enough input parameters.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why not use LOG(FATAL) << "message"
instead? It also terminates the program with an error code.
if (argc < 2) { | ||
printf("[ERROR] Not enough input parameters.\n"); | ||
printf("Proper usage: ./cost_matrix_based_matching_lsh config_file.yaml\n"); | ||
exit(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Follow up on above, if a program terminates with an error it probably should not return code 0
as it will be interpreted as "program terminated correctly".
|
||
std::string config_file = argv[1]; | ||
ConfigParser parser; | ||
parser.parseYaml(config_file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: a small design suggestions that might make sense here. Why now pass the config_file
into the constructor of the ConfigParser
directly?
/*tableNum=*/1, | ||
/*keySize=*/12, | ||
/*multiProbeLevel=*/2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it is a good practice to put such magic numbers as constexpr int kTableNum
etc into the unnamed namespace at the top of the file. This way they are easy to find upon glancing into the file.
/*multiProbeLevel=*/2); | ||
relocalizer->train(loadFeatures(parser.path2ref)); | ||
|
||
auto successorManager = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be const?
/*type=*/loc::features::FeatureType::Cnn_Feature, | ||
/*bufferSize=*/parser.bufferSize); | ||
|
||
auto relocalizer = std::make_unique<loc::relocalizers::LshCvHashing>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be const?
std::string path2refImg = ""; | ||
std::string imgExt = ""; | ||
std::string costMatrix = ""; | ||
std::string costsOutputName = "costs.MatchingCosts.pb"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally speaking, using default values on which your logic depends is frowned upon. The reason is that if your logic changes, these default values are easy to forget. I would suggest to set the default value to empty and just pass the appropriate values into a constructor that takes just the values you need. This way, when reading the code it should be easy to see which objects are created with which values.
message CostMatrix { | ||
optional int32 rows = 20; | ||
optional int32 cols = 21; | ||
repeated double values = 1; | ||
} | ||
|
||
// Is used to store matching costs with associated query and reference id. | ||
// Does not require all elements of the cost matrix to be present |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments usually go out of date quite quickly and then become confusing to read. Maybe jut add the check whenever you read the message and remove this comment?
This PR adds new message type to
localization_protos
. This type is called "MatchingCosts" and is used to store individual matching costs for a pair of images with [query_id, ref_id]. The difference to "CostMatrix" is that "MatchingCosts" are not required to store all values of the cost matrix of sizerow x col
but can store just individual values. This is necessary to be able to visualize the "online" operation of the sequence matching algorithm.Additionally, this PR adds functionality to read and write "MatchingCosts" from C++, Python and viewer interfaces.