Skip to content

Commit db6505c

Browse files
author
Gin
committed
better box selection
1 parent 1caa1b5 commit db6505c

File tree

4 files changed

+73
-8
lines changed

4 files changed

+73
-8
lines changed

SerialPrograms/Source/CommonFramework/ImageTools/ImageBoxes.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,28 @@ size_t ImagePixelBox::distance_y(const ImagePixelBox& box) const{
9595
return 0;
9696
}
9797

98+
size_t ImagePixelBox::distance_to_point_x(const size_t x) const{
99+
size_t min_x = std::max(this->min_x, x);
100+
size_t max_x = std::min(this->max_x, x);
101+
return min_x - max_x;
102+
}
103+
// The distance to a point on y axis. If the point is in the box, the distance is 0.
104+
size_t ImagePixelBox::distance_to_point_y(const size_t y) const{
105+
size_t min_y = std::max(this->min_y, y);
106+
size_t max_y = std::min(this->max_y, y);
107+
return min_y - max_y;
108+
}
109+
// The distance from the box center to a point on x axis
110+
size_t ImagePixelBox::center_distance_to_point_x(const size_t x) const{
111+
size_t d = center_x() - x;
112+
return d > 0 ? d : -d;
113+
}
114+
// The distance from the box center to a point on y axis
115+
size_t ImagePixelBox::center_distance_to_point_y(const size_t y) const{
116+
size_t d = center_y() - y;
117+
return d > 0 ? d : -d;
118+
}
119+
98120

99121
ImageViewRGB32 extract_box_reference(const ImageViewRGB32& image, const ImagePixelBox& box){
100122
return image.sub_image(box.min_x, box.min_y, box.width(), box.height());

SerialPrograms/Source/CommonFramework/ImageTools/ImageBoxes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ struct ImagePixelBox : public Rectangle<size_t>{
5656
size_t distance_x(const ImagePixelBox& box) const;
5757
// The distance to another box on y axis. If two boxes overlap, the distance is 0.
5858
size_t distance_y(const ImagePixelBox& box) const;
59+
// The distance to a point on x axis. If the point is in the box, the distance is 0.
60+
size_t distance_to_point_x(const size_t x) const;
61+
// The distance to a point on y axis. If the point is in the box, the distance is 0.
62+
size_t distance_to_point_y(const size_t y) const;
63+
// The distance from the box center to a point on x axis
64+
size_t center_distance_to_point_x(const size_t x) const;
65+
// The distance from the box center to a point on y axis
66+
size_t center_distance_to_point_y(const size_t y) const;
5967
};
6068

6169
// An axis aligned box in the normalized image space. Used for getting a crop from an image for various

SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -447,19 +447,39 @@ void LabelImages::change_annotation_selection_by_mouse(double x, double y){
447447
if (source_image_width == 0 || source_image_height == 0 || m_annotations.size() == 0){
448448
return;
449449
}
450+
451+
const size_t px = (size_t)std::max<double>(source_image_width * x + 0.5, 0);
452+
const size_t py = (size_t)std::max<double>(source_image_height * y + 0.5, 0);
450453

451454
double closest_distance = DBL_MAX;
455+
std::vector<size_t> zero_distance_annotations;
452456
for(size_t i = 0; i < m_annotations.size(); i++){
453-
ImageFloatBox float_box = pixelbox_to_floatbox(source_image_width, source_image_height, m_annotations[i].mask_box);
454-
double center_x = float_box.x + float_box.width/2.0;
455-
double center_y = float_box.y + float_box.height/2.0;
456-
double d2 = (center_x-x)*(center_x-x) + (center_y-y)*(center_y-y);
457+
const size_t dx = m_annotations[i].mask_box.distance_to_point_x(px);
458+
const size_t dy = m_annotations[i].mask_box.distance_to_point_y(py);
459+
const size_t d2 = dx*dx + dy*dy;
460+
if (d2 == 0){
461+
zero_distance_annotations.push_back(i);
462+
}
457463
if (d2 < closest_distance){
458464
closest_distance = d2;
459465
m_selected_obj_idx = i;
460466
}
461467
}
462468

469+
if (zero_distance_annotations.size() > 1){
470+
// this point is inside multiple boxes, we then use the closest to the box center to determine
471+
closest_distance = DBL_MAX;
472+
for(size_t i : zero_distance_annotations){
473+
const size_t dx = m_annotations[i].mask_box.center_distance_to_point_x(px);
474+
const size_t dy = m_annotations[i].mask_box.center_distance_to_point_y(py);
475+
const size_t d2 = dx*dx + dy*dy;
476+
if (d2 < closest_distance){
477+
closest_distance = d2;
478+
m_selected_obj_idx = i;
479+
}
480+
}
481+
}
482+
463483
auto new_label = m_annotations[m_selected_obj_idx].label;
464484
set_selected_label(new_label);
465485
}
@@ -779,17 +799,30 @@ void LabelImages_Widget::on_mouse_press(double x, double y){
779799
m_mouse_end.emplace();
780800
m_mouse_start->first = m_mouse_end->first = x;
781801
m_mouse_start->second = m_mouse_end->second = y;
802+
m_mouse_start_time = std::chrono::high_resolution_clock::now();
782803
}
783804

784805
void LabelImages_Widget::on_mouse_release(double x, double y){
785-
if (m_mouse_start == m_mouse_end){
806+
const std::chrono::duration<double> duration = std::chrono::high_resolution_clock::now() - m_mouse_start_time;
807+
const double rel_x = std::fabs(m_mouse_start->first - m_mouse_end->first);
808+
const double rel_y = std::fabs(m_mouse_start->second - m_mouse_end->second);
809+
810+
m_mouse_start.reset();
811+
m_mouse_end.reset();
812+
813+
// cout << "Mouse release " << (rel_x) << " " << (rel_y) << " duration " << duration << " " <<
814+
// (duration < std::chrono::milliseconds(150)) << endl;
815+
816+
// user may have very small movement while doing quick clicking. To register this as a simple click, use relative
817+
// screen distance threshold 0.0015 and click duration threshold 0.15 second:
818+
if ((rel_x == 0 && rel_y == 0) || (rel_x < 0.0015 && rel_y < 0.0015 && duration < std::chrono::milliseconds(150))){
786819
// process mouse clicking
787820
// change currently selected annotation
788821
// also change the option values in the UI
789822
m_program.change_annotation_selection_by_mouse(x, y);
823+
return;
790824
}
791-
m_mouse_start.reset();
792-
m_mouse_end.reset();
825+
793826
m_program.compute_mask();
794827
}
795828

SerialPrograms/Source/ML/Programs/ML_LabelImages.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
#ifndef PokemonAutomation_ML_LabelImages_H
88
#define PokemonAutomation_ML_LabelImages_H
99

10-
#include <QGraphicsScene>
1110
#include <memory>
11+
#include <chrono>
12+
#include <QGraphicsScene>
1213
#include "Common/Cpp/Options/BatchOption.h"
1314
#include "Common/Cpp/Options/FloatingPointOption.h"
1415
#include "Common/Cpp/Options/EnumDropdownOption.h"
@@ -219,6 +220,7 @@ class LabelImages_Widget : public PanelWidget,
219220

220221
std::optional<std::pair<double, double>> m_mouse_start;
221222
std::optional<std::pair<double, double>> m_mouse_end;
223+
std::chrono::time_point<std::chrono::high_resolution_clock> m_mouse_start_time;
222224
};
223225

224226

0 commit comments

Comments
 (0)