Skip to content

Commit d0f8707

Browse files
author
Gin
committed
add feature to select and delete selected annotation
1 parent dd7f178 commit d0f8707

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <QFileDialog>
88
#include <QLabel>
99
#include <QDir>
10+
#include <cfloat>
1011
#include <QDirIterator>
1112
#include <QVBoxLayout>
1213
#include <QGraphicsView>
@@ -189,7 +190,7 @@ void LabelImages::clear_for_new_image(){
189190
m_output_boolean_mask.clear();
190191
m_mask_image = ImageRGB32();
191192
m_annotations.clear();
192-
m_last_object_idx = 0;
193+
m_selected_obj_idx = 0;
193194
m_annotation_file_path = "";
194195
m_fail_to_load_annotation_file = false;
195196
}
@@ -255,7 +256,7 @@ void LabelImages::load_image_related_data(const std::string& image_path, size_t
255256
);
256257
}
257258
}
258-
m_last_object_idx = m_annotations.size();
259+
m_selected_obj_idx = m_annotations.size();
259260
cout << "Loaded existing annotation file " << m_annotation_file_path << endl;
260261
}
261262

@@ -272,7 +273,7 @@ void LabelImages::update_rendered_objects(VideoOverlaySet& overlay_set){
272273
if (form != nullptr){
273274
label = form->display_name();
274275
}
275-
Color mask_box_color = (i_obj == m_last_object_idx) ? COLOR_BLACK : COLOR_BLUE;
276+
Color mask_box_color = (i_obj == m_selected_obj_idx) ? COLOR_BLACK : COLOR_BLUE;
276277
overlay_set.add(mask_box_color, mask_float_box, label);
277278
size_t mask_width = obj.mask_box.width();
278279
size_t mask_height = obj.mask_box.height();
@@ -359,7 +360,7 @@ void LabelImages::compute_mask(VideoOverlaySet& overlay_set){
359360
}
360361

361362
annotation.label = label;
362-
m_last_object_idx = m_annotations.size();
363+
m_selected_obj_idx = m_annotations.size();
363364
m_annotations.emplace_back(std::move(annotation));
364365

365366
update_rendered_objects(overlay_set);
@@ -372,12 +373,54 @@ void LabelImages::compute_embeddings_for_folder(const std::string& image_folder_
372373
ML::compute_embeddings_for_folder(embedding_model_path, image_folder_path);
373374
}
374375

375-
void LabelImages::delete_last_annotation(){
376-
if (m_annotations.size() > 0){
377-
m_annotations.pop_back();
376+
void LabelImages::delete_selected_annotation(){
377+
if (m_annotations.size() == 0 || m_selected_obj_idx >= m_annotations.size()){
378+
return;
378379
}
379-
if (m_annotations.size() > 0){
380-
m_last_object_idx = m_annotations.size() - 1;
380+
381+
m_annotations.erase(m_annotations.begin() + m_selected_obj_idx);
382+
383+
if (m_annotations.size() == 0){
384+
m_selected_obj_idx = 0;
385+
return;
386+
}
387+
388+
if (m_selected_obj_idx >= m_annotations.size()){
389+
m_selected_obj_idx = m_annotations.size() - 1;
390+
} else{
391+
// no change to the currently selected index
392+
}
393+
394+
std::string& cur_label = m_annotations[m_selected_obj_idx].label;
395+
FORM_LABEL.set_by_slug(cur_label);
396+
}
397+
398+
void LabelImages::change_annotation_selection_by_mouse(double x, double y){
399+
if (m_annotations.size() == 0){
400+
return;
401+
}
402+
// no annotation image loaded
403+
if (source_image_width == 0 || source_image_height == 0){
404+
return;
405+
}
406+
407+
auto& cur_ui_label = FORM_LABEL.slug();
408+
409+
double closest_distance = DBL_MAX;
410+
for(size_t i = 0; i < m_annotations.size(); i++){
411+
ImageFloatBox float_box = pixelbox_to_floatbox(source_image_width, source_image_height, m_annotations[i].mask_box);
412+
double center_x = float_box.x + float_box.width/2.0;
413+
double center_y = float_box.y + float_box.height/2.0;
414+
double d2 = (center_x-x)*(center_x-x) + (center_y-y)*(center_y-y);
415+
if (d2 < closest_distance){
416+
closest_distance = d2;
417+
m_selected_obj_idx = i;
418+
}
419+
}
420+
421+
auto new_label = m_annotations[m_selected_obj_idx].label;
422+
if (cur_ui_label != new_label){
423+
FORM_LABEL.set_by_slug(new_label);
381424
}
382425
}
383426

@@ -440,7 +483,7 @@ LabelImages_Widget::LabelImages_Widget(
440483
scroll_layout->addWidget(button);
441484
connect(button, &QPushButton::clicked, this, [this](bool){
442485
auto& program = this->m_program;
443-
program.delete_last_annotation();
486+
program.delete_selected_annotation();
444487
program.update_rendered_objects(this->m_overlay_set);
445488
});
446489

@@ -468,9 +511,13 @@ void LabelImages_Widget::clear_for_new_image(){
468511
}
469512

470513
void LabelImages_Widget::on_config_value_changed(void* object){
471-
if (m_program.m_annotations.size() > 0 && m_program.m_last_object_idx < m_program.m_annotations.size()){
472-
std::string& cur_label = m_program.m_annotations[m_program.m_last_object_idx].label;
473-
cur_label = m_program.FORM_LABEL.slug();
514+
// TODO: the logic here should be part of LabelImage program
515+
if (m_program.m_annotations.size() > 0 && m_program.m_selected_obj_idx < m_program.m_annotations.size()){
516+
std::string& cur_label = m_program.m_annotations[m_program.m_selected_obj_idx].label;
517+
const std::string& ui_slug = m_program.FORM_LABEL.slug();
518+
if (ui_slug != cur_label){
519+
cur_label = m_program.FORM_LABEL.slug();
520+
}
474521
}
475522
m_program.update_rendered_objects(m_overlay_set);
476523
}
@@ -495,7 +542,7 @@ void LabelImages_Widget::post_startup(VideoSource* source){
495542
}
496543

497544
m_embedding_info_label->setText(QString::fromStdString(embedding_path_display));
498-
m_embedding_info_label->setStyleSheet("color: blue");
545+
m_embedding_info_label->setStyleSheet("color: green");
499546

500547
const auto cur_res = m_display_session.video_session().current_resolution();
501548
if (cur_res.width == 0 || cur_res.height == 0){
@@ -512,7 +559,7 @@ void LabelImages_Widget::post_startup(VideoSource* source){
512559
void LabelImages_Widget::key_release(QKeyEvent* event){
513560
const auto key = Qt::Key(event->key());
514561
if (key == Qt::Key::Key_Delete || key == Qt::Key::Key_Backspace){
515-
m_program.delete_last_annotation();
562+
m_program.delete_selected_annotation();
516563
m_program.update_rendered_objects(m_overlay_set);
517564
}
518565
}
@@ -529,6 +576,12 @@ void LabelImages_Widget::on_mouse_press(double x, double y){
529576
}
530577

531578
void LabelImages_Widget::on_mouse_release(double x, double y){
579+
if (m_mouse_start == m_mouse_end){
580+
// process mouse clicking
581+
// change currently selected annotation
582+
// also change the option values in the UI
583+
m_program.change_annotation_selection_by_mouse(x, y);
584+
}
532585
m_mouse_start.reset();
533586
m_mouse_end.reset();
534587
m_program.compute_mask(m_overlay_set);

SerialPrograms/Source/ML/Programs/ML_LabelImages.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class LabelImages_Widget;
5252
struct ObjectAnnotation{
5353
ImagePixelBox user_box; // user drawn loose bounding box
5454
ImagePixelBox mask_box;
55-
std::vector<bool> mask;
55+
std::vector<bool> mask; // size() equals the total pixels in mask_box
5656
std::string label = "unknown";
5757

5858
ObjectAnnotation();
@@ -97,8 +97,10 @@ class LabelImages : public PanelInstance{
9797
// This can be very slow!
9898
void compute_embeddings_for_folder(const std::string& image_folder);
9999

100-
// Delete the last object annotation.
101-
void delete_last_annotation();
100+
// Delete the currently selected object annotation.
101+
void delete_selected_annotation();
102+
103+
void change_annotation_selection_by_mouse(double x, double y);
102104

103105
private:
104106
friend class LabelImages_Widget;
@@ -126,7 +128,10 @@ class LabelImages : public PanelInstance{
126128

127129
std::unique_ptr<SAMSession> m_sam_session;
128130
std::vector<ObjectAnnotation> m_annotations;
129-
size_t m_last_object_idx = 0;
131+
132+
// currently selected annotated object's index
133+
// if this value == m_annotations.size(), it means the user is not selecting anything
134+
size_t m_selected_obj_idx = 0;
130135
std::string m_annotation_file_path;
131136
// if we find an annotation file that is supposed to be created by user in a previous session, but
132137
// we fail to load it, then we shouldn't overwrite this file to possibly erase the previous work.

0 commit comments

Comments
 (0)