"git@developer.sourcefind.cn:change/sglang.git" did not exist on "9f47d686e52158bbd3872ec8a6d96fbc5de69134"
Unverified Commit 4ff365a5 authored by martin's avatar martin Committed by GitHub
Browse files

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
parent fc6992ac
...@@ -7065,25 +7065,9 @@ namespace dlib ...@@ -7065,25 +7065,9 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void image_display:: void image_display::
on_wheel_up ( zoom_in (
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_up(state);
return;
}
if (rect.contains(lastx,lasty) == false || hidden || !enabled)
return;
if (zoom_in_scale < 100 && zoom_out_scale == 1) if (zoom_in_scale < 100 && zoom_out_scale == 1)
{ {
const point mouse_loc(lastx, lasty); const point mouse_loc(lastx, lasty);
...@@ -7119,7 +7103,7 @@ namespace dlib ...@@ -7119,7 +7103,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void image_display:: void image_display::
on_wheel_down ( on_wheel_up (
unsigned long state unsigned long state
) )
{ {
...@@ -7130,14 +7114,22 @@ namespace dlib ...@@ -7130,14 +7114,22 @@ namespace dlib
// if CONTROL is not being held down // if CONTROL is not being held down
if ((state & base_window::CONTROL) == 0) if ((state & base_window::CONTROL) == 0)
{ {
scrollable_region::on_wheel_down(state); scrollable_region::on_wheel_up(state);
return; return;
} }
if (rect.contains(lastx,lasty) == false || hidden || !enabled) if (rect.contains(lastx,lasty) == false || hidden || !enabled)
return; return;
zoom_in();
}
// ----------------------------------------------------------------------------------------
void image_display::
zoom_out (
)
{
if (zoom_in_scale != 1) if (zoom_in_scale != 1)
{ {
const point mouse_loc(lastx, lasty); const point mouse_loc(lastx, lasty);
...@@ -7170,6 +7162,30 @@ namespace dlib ...@@ -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 // image_window member functions
......
...@@ -3493,6 +3493,12 @@ namespace dlib ...@@ -3493,6 +3493,12 @@ namespace dlib
bool overlay_editing_is_enabled ( bool overlay_editing_is_enabled (
) const { auto_mutex M(m); return overlay_editing_enabled; } ) const { auto_mutex M(m); return overlay_editing_enabled; }
void zoom_in (
);
void zoom_out (
);
private: private:
void draw ( void draw (
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <dlib/dir_nav.h> #include <dlib/dir_nav.h>
#include <dlib/clustering.h> #include <dlib/clustering.h>
#include <dlib/svm.h> #include <dlib/svm.h>
#include <dlib/statistics.h>
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -72,6 +73,56 @@ std::vector<assignment> angular_cluster ( ...@@ -72,6 +73,56 @@ std::vector<assignment> angular_cluster (
} }
return assignments; 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( ...@@ -134,7 +185,7 @@ int cluster_dataset(
return EXIT_FAILURE; 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); const unsigned long chip_size = get_option(parser, "size", 8000);
image_dataset_metadata::dataset data; image_dataset_metadata::dataset data;
...@@ -177,7 +228,12 @@ int cluster_dataset( ...@@ -177,7 +228,12 @@ int cluster_dataset(
} }
cout << "\nClustering objects..." << endl; 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. // Now output each cluster to disk as an XML file.
......
...@@ -588,7 +588,7 @@ int main(int argc, char** argv) ...@@ -588,7 +588,7 @@ int main(int argc, char** argv)
"The parts are instead simply mirrored to the flipped dataset.", 1); "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. " 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); "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); "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("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); 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) ...@@ -704,7 +704,7 @@ int main(int argc, char** argv)
parser.check_incompatible_options("box-images", "ignore"); parser.check_incompatible_options("box-images", "ignore");
const char* convert_args[] = {"pascal-xml","pascal-v1","idl"}; const char* convert_args[] = {"pascal-xml","pascal-v1","idl"};
parser.check_option_arg_range("convert", convert_args); 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("rotate", -360, 360);
parser.check_option_arg_range("size", 10*10, 1000*1000); parser.check_option_arg_range("size", 10*10, 1000*1000);
parser.check_option_arg_range("min-object-size", 1, 10000*10000); parser.check_option_arg_range("min-object-size", 1, 10000*10000);
......
...@@ -343,6 +343,16 @@ on_keydown ( ...@@ -343,6 +343,16 @@ on_keydown (
last_keyboard_jump_pos_update = 0; 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)) if (key == 'd' && (state&base_window::KBD_MOD_ALT))
{ {
remove_selected_images(); remove_selected_images();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment