mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
imglab: chinese ("automatic") clustering, keyboard shortcuts for zooming (#2007)
* imglab: add support for using chinese whispers for more automatic clustering * widgets: refactor out zooming from wheel handling * tools/imglab/src/metadata_editor.cpp imglab: add keyboard shortcuts for zooming
This commit is contained in:
parent
fc6992ac04
commit
4ff365a530
@ -7065,25 +7065,9 @@ namespace dlib
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void image_display::
|
||||
on_wheel_up (
|
||||
unsigned long state
|
||||
zoom_in (
|
||||
)
|
||||
{
|
||||
// disable mouse wheel if the user is drawing a rectangle
|
||||
if (drawing_rect)
|
||||
return;
|
||||
|
||||
// if CONTROL is not being held down
|
||||
if ((state & base_window::CONTROL) == 0)
|
||||
{
|
||||
scrollable_region::on_wheel_up(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.contains(lastx,lasty) == false || hidden || !enabled)
|
||||
return;
|
||||
|
||||
|
||||
if (zoom_in_scale < 100 && zoom_out_scale == 1)
|
||||
{
|
||||
const point mouse_loc(lastx, lasty);
|
||||
@ -7119,7 +7103,7 @@ namespace dlib
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void image_display::
|
||||
on_wheel_down (
|
||||
on_wheel_up (
|
||||
unsigned long state
|
||||
)
|
||||
{
|
||||
@ -7130,14 +7114,22 @@ namespace dlib
|
||||
// if CONTROL is not being held down
|
||||
if ((state & base_window::CONTROL) == 0)
|
||||
{
|
||||
scrollable_region::on_wheel_down(state);
|
||||
scrollable_region::on_wheel_up(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.contains(lastx,lasty) == false || hidden || !enabled)
|
||||
return;
|
||||
|
||||
zoom_in();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void image_display::
|
||||
zoom_out (
|
||||
)
|
||||
{
|
||||
if (zoom_in_scale != 1)
|
||||
{
|
||||
const point mouse_loc(lastx, lasty);
|
||||
@ -7170,6 +7162,30 @@ namespace dlib
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void image_display::
|
||||
on_wheel_down (
|
||||
unsigned long state
|
||||
)
|
||||
{
|
||||
// disable mouse wheel if the user is drawing a rectangle
|
||||
if (drawing_rect)
|
||||
return;
|
||||
|
||||
// if CONTROL is not being held down
|
||||
if ((state & base_window::CONTROL) == 0)
|
||||
{
|
||||
scrollable_region::on_wheel_down(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.contains(lastx,lasty) == false || hidden || !enabled)
|
||||
return;
|
||||
|
||||
zoom_out();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// image_window member functions
|
||||
|
@ -3493,6 +3493,12 @@ namespace dlib
|
||||
bool overlay_editing_is_enabled (
|
||||
) const { auto_mutex M(m); return overlay_editing_enabled; }
|
||||
|
||||
void zoom_in (
|
||||
);
|
||||
|
||||
void zoom_out (
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
void draw (
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <dlib/dir_nav.h>
|
||||
#include <dlib/clustering.h>
|
||||
#include <dlib/svm.h>
|
||||
#include <dlib/statistics.h>
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
@ -72,6 +73,56 @@ std::vector<assignment> angular_cluster (
|
||||
}
|
||||
return assignments;
|
||||
}
|
||||
std::vector<assignment> chinese_cluster (
|
||||
std::vector<matrix<double,0,1> > feats,
|
||||
unsigned long &num_clusters
|
||||
)
|
||||
{
|
||||
// try to find a good value to select if we should add a vertex in the graph
|
||||
matrix<double,0,1> m;
|
||||
for (unsigned long i = 0; i < feats.size(); ++i)
|
||||
m += feats[i];
|
||||
m /= feats.size();
|
||||
|
||||
for (unsigned long i = 0; i < feats.size(); ++i)
|
||||
{
|
||||
feats[i] -= m;
|
||||
double len = length(feats[i]);
|
||||
if (len != 0)
|
||||
feats[i] /= len;
|
||||
}
|
||||
|
||||
running_stats<double> rs;
|
||||
for (size_t i = 0; i < feats.size(); ++i) {
|
||||
for (size_t j = i; j < feats.size(); ++j) {
|
||||
rs.add(length(feats[i] - feats[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// add vertices for chinese whispers to find clusters
|
||||
std::vector<sample_pair> edges;
|
||||
for (size_t i = 0; i < feats.size(); ++i) {
|
||||
for (size_t j = i; j < feats.size(); ++j) {
|
||||
if (length(feats[i] - feats[j]) < rs.mean()) {
|
||||
edges.push_back(sample_pair(i, j, length(feats[i] - feats[j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned long> labels;
|
||||
num_clusters = chinese_whispers(edges, labels);
|
||||
|
||||
std::vector<assignment> assignments;
|
||||
for (unsigned long i = 0; i < feats.size(); ++i)
|
||||
{
|
||||
assignment temp;
|
||||
temp.c = labels[i];
|
||||
temp.dist = length(feats[i]);
|
||||
temp.idx = i;
|
||||
assignments.push_back(temp);
|
||||
}
|
||||
return assignments;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
@ -134,7 +185,7 @@ int cluster_dataset(
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const unsigned long num_clusters = get_option(parser, "cluster", 2);
|
||||
unsigned long num_clusters = get_option(parser, "cluster", 0);
|
||||
const unsigned long chip_size = get_option(parser, "size", 8000);
|
||||
|
||||
image_dataset_metadata::dataset data;
|
||||
@ -177,7 +228,12 @@ int cluster_dataset(
|
||||
}
|
||||
|
||||
cout << "\nClustering objects..." << endl;
|
||||
std::vector<assignment> assignments = angular_cluster(feats, num_clusters);
|
||||
std::vector<assignment> assignments;
|
||||
if (num_clusters) {
|
||||
assignments = angular_cluster(feats, num_clusters);
|
||||
} else {
|
||||
assignments = chinese_cluster(feats, num_clusters);
|
||||
}
|
||||
|
||||
|
||||
// Now output each cluster to disk as an XML file.
|
||||
|
@ -588,7 +588,7 @@ int main(int argc, char** argv)
|
||||
"The parts are instead simply mirrored to the flipped dataset.", 1);
|
||||
parser.add_option("rotate", "Read an XML image dataset and output a copy that is rotated counter clockwise by <arg> degrees. "
|
||||
"The output is saved to an XML file prefixed with rotated_<arg>.",1);
|
||||
parser.add_option("cluster", "Cluster all the objects in an XML file into <arg> different clusters and save "
|
||||
parser.add_option("cluster", "Cluster all the objects in an XML file into <arg> different clusters (pass 0 to find automatically) and save "
|
||||
"the results as cluster_###.xml and cluster_###.jpg files.",1);
|
||||
parser.add_option("ignore", "Mark boxes labeled as <arg> as ignored. The resulting XML file is output as a separate file and the original is not modified.",1);
|
||||
parser.add_option("rmlabel","Remove all boxes labeled <arg> and save the results to a new XML file.",1);
|
||||
@ -704,7 +704,7 @@ int main(int argc, char** argv)
|
||||
parser.check_incompatible_options("box-images", "ignore");
|
||||
const char* convert_args[] = {"pascal-xml","pascal-v1","idl"};
|
||||
parser.check_option_arg_range("convert", convert_args);
|
||||
parser.check_option_arg_range("cluster", 2, 999);
|
||||
parser.check_option_arg_range("cluster", 0, 999);
|
||||
parser.check_option_arg_range("rotate", -360, 360);
|
||||
parser.check_option_arg_range("size", 10*10, 1000*1000);
|
||||
parser.check_option_arg_range("min-object-size", 1, 10000*10000);
|
||||
|
@ -343,6 +343,16 @@ on_keydown (
|
||||
last_keyboard_jump_pos_update = 0;
|
||||
}
|
||||
|
||||
if (key == '=')
|
||||
{
|
||||
display.zoom_in();
|
||||
}
|
||||
|
||||
if (key == '-')
|
||||
{
|
||||
display.zoom_out();
|
||||
}
|
||||
|
||||
if (key == 'd' && (state&base_window::KBD_MOD_ALT))
|
||||
{
|
||||
remove_selected_images();
|
||||
|
Loading…
Reference in New Issue
Block a user