Skip to content

Commit 41b0e24

Browse files
author
Gin
committed
can load new images for annotation
1 parent 3fa1764 commit 41b0e24

12 files changed

+117
-152
lines changed

SerialPrograms/Source/CommonFramework/VideoPipeline/VideoSession.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
#include "VideoSources/VideoSource_Null.h"
1313
#include "VideoSession.h"
1414

15-
//#include <iostream>
16-
//using std::cout;
17-
//using std::endl;
15+
// #include <iostream>
16+
// using std::cout;
17+
// using std::endl;
1818

1919
namespace PokemonAutomation{
2020

SerialPrograms/Source/ML/DataLabeling/SegmentAnythingModel.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void SAMSession::run(
208208

209209
// save the image embedding as a file with path <image_filepath>.embedding
210210
void save_image_embedding_to_disk(const std::string& image_filepath, const std::vector<float>& embedding){
211-
std::string embedding_path = image_filepath + ".embedding";
211+
const std::string embedding_path = image_filepath + ".embedding";
212212
std::ofstream fout(embedding_path, std::ios::binary);
213213
// write embedding shape
214214
fout.write(reinterpret_cast<const char*>(&SAM_EMBEDDER_OUTPUT_N_CHANNELS), sizeof(SAM_EMBEDDER_OUTPUT_N_CHANNELS));
@@ -249,6 +249,7 @@ bool load_image_embedding(const std::string& image_filepath, std::vector<float>&
249249
}
250250

251251

252+
// TODO: skip already computed embedding
252253
void compute_embeddings_for_folder(const std::string& embedding_model_path, const std::string& image_folder_path){
253254
QDir image_dir(image_folder_path.c_str());
254255
if (!image_dir.exists()){

SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,18 @@ JsonValue LabelImages::to_json() const{
238238
}
239239
return obj;
240240
}
241+
242+
void LabelImages::clear_for_new_image(){
243+
source_image_height = source_image_height = 0;
244+
m_image_embedding.clear();
245+
m_output_boolean_mask.clear();
246+
m_mask_image = ImageRGB32();
247+
m_annotations.clear();
248+
m_last_object_idx = 0;
249+
m_annotation_file_path = "";
250+
m_fail_to_load_annotation_file = false;
251+
}
252+
241253
QWidget* LabelImages::make_widget(QWidget& parent, PanelHolder& holder){
242254
return new LabelImages_Widget(parent, *this, holder);
243255
}
@@ -419,7 +431,7 @@ void LabelImages::compute_embeddings_for_folder(const std::string& image_folder_
419431

420432
LabelImages_Widget::~LabelImages_Widget(){
421433
m_program.FORM_LABEL.remove_listener(*this);
422-
delete m_switch_widget;
434+
delete m_image_display_widget;
423435
}
424436
LabelImages_Widget::LabelImages_Widget(
425437
QWidget& parent,
@@ -433,6 +445,9 @@ LabelImages_Widget::LabelImages_Widget(
433445
, m_drawn_box(*this, m_display_session.overlay())
434446
{
435447
m_program.FORM_LABEL.add_listener(*this);
448+
m_display_session.video_session().add_state_listener(*this);
449+
450+
m_embedding_info_label = new QLabel(this);
436451

437452
QVBoxLayout* layout = new QVBoxLayout(this);
438453
layout->setContentsMargins(0, 0, 0, 0);
@@ -447,8 +462,13 @@ LabelImages_Widget::LabelImages_Widget(
447462
QVBoxLayout* scroll_layout = new QVBoxLayout(scroll_inner);
448463
scroll_layout->setAlignment(Qt::AlignTop);
449464

450-
m_switch_widget = new ImageAnnotationDisplayWidget(*this, m_display_session, 0);
451-
scroll_layout->addWidget(m_switch_widget);
465+
m_image_display_widget = new ImageAnnotationDisplayWidget(*this, m_display_session, 0);
466+
scroll_layout->addWidget(m_image_display_widget);
467+
468+
QHBoxLayout* embedding_info_row = new QHBoxLayout();
469+
scroll_layout->addLayout(embedding_info_row);
470+
embedding_info_row->addWidget(new QLabel("<b>Image Embedding File:</b> ", this));
471+
embedding_info_row->addWidget(m_embedding_info_label);
452472

453473
QPushButton* button = new QPushButton("Delete Last Mask", scroll_inner);
454474
scroll_layout->addWidget(button);
@@ -478,17 +498,14 @@ LabelImages_Widget::LabelImages_Widget(
478498
}
479499
});
480500

481-
const auto cur_res = m_display_session.video_session().current_resolution();
482-
if (cur_res.width > 0 && cur_res.height > 0){
483-
const std::string& image_path = m_display_session.option().m_image_path;
484-
m_program.load_image_related_data(image_path, cur_res.width, cur_res.height);
485-
m_program.update_rendered_objects(m_overlay_set);
486-
}
487-
488-
489501
cout << "LabelImages_Widget built" << endl;
490502
}
491503

504+
void LabelImages_Widget::clear_for_new_image(){
505+
m_overlay_set.clear();
506+
m_program.clear_for_new_image();
507+
}
508+
492509
void LabelImages_Widget::on_config_value_changed(void* object){
493510
if (m_program.m_annotations.size() > 0 && m_program.m_last_object_idx < m_program.m_annotations.size()){
494511
std::string& cur_label = m_program.m_annotations[m_program.m_last_object_idx].label;
@@ -497,6 +514,39 @@ void LabelImages_Widget::on_config_value_changed(void* object){
497514
}
498515
}
499516

517+
// This callback function will be called whenever the display source (the image source) is loaded or reloaded:
518+
void LabelImages_Widget::post_startup(VideoSource* source){
519+
const std::string& image_path = m_display_session.option().m_image_path;
520+
521+
clear_for_new_image();
522+
if (image_path.size() == 0){
523+
m_embedding_info_label->setText("");
524+
return;
525+
}
526+
527+
const std::string embedding_path = image_path + ".embedding";
528+
const std::string embedding_path_display = "<IMAGE_FOLDER>/" + std::filesystem::path(embedding_path).filename().string();
529+
if (!std::filesystem::exists(embedding_path)){
530+
m_embedding_info_label->setText(QString::fromStdString(embedding_path_display + " Dose Not Exist. Cannot Annotate The Image!"));
531+
m_embedding_info_label->setStyleSheet("color: red");
532+
return;
533+
}
534+
535+
m_embedding_info_label->setText(QString::fromStdString(embedding_path_display));
536+
m_embedding_info_label->setStyleSheet("color: blue");
537+
538+
const auto cur_res = m_display_session.video_session().current_resolution();
539+
if (cur_res.width == 0 || cur_res.height == 0){
540+
QMessageBox box;
541+
box.warning(nullptr, "Invalid Image Dimension",
542+
QString::fromStdString("Loaded image " + image_path + " has invalid dimension: " + cur_res.to_string()));
543+
return;
544+
}
545+
546+
m_program.load_image_related_data(image_path, cur_res.width, cur_res.height);
547+
m_program.update_rendered_objects(m_overlay_set);
548+
}
549+
500550

501551

502552
}

SerialPrograms/Source/ML/Programs/ML_LabelImages.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
class QGraphicsView;
2727
class QGraphicsPixmapItem;
28+
class QLabel;
2829

2930
namespace PokemonAutomation{
3031

@@ -72,6 +73,9 @@ class LabelImages : public PanelInstance{
7273
virtual void from_json(const JsonValue& json) override;
7374
virtual JsonValue to_json() const override;
7475

76+
// called after loading a new image, clean up all internal data
77+
void clear_for_new_image();
78+
7579
// Load image related data:
7680
// - Image SAM embedding data file, which has the same file path but with a name suffix ".embedding"
7781
// - Existing annotation file, which is stored in a pre-defined ML_ANNOTATION_PATH() and with the same filename as
@@ -145,7 +149,7 @@ class DrawnBoundingBox : public ConfigOption::Listener, public VideoOverlay::Mou
145149
};
146150

147151

148-
class LabelImages_Widget : public PanelWidget, public ConfigOption::Listener{
152+
class LabelImages_Widget : public PanelWidget, public ConfigOption::Listener, public VideoSession::StateListener{
149153
public:
150154
~LabelImages_Widget();
151155
LabelImages_Widget(
@@ -154,14 +158,24 @@ class LabelImages_Widget : public PanelWidget, public ConfigOption::Listener{
154158
PanelHolder& holder
155159
);
156160

161+
// called after loading a new image, clean up all internal data
162+
void clear_for_new_image();
163+
157164
virtual void on_config_value_changed(void* object) override;
158165

166+
// Overwrites VideoSession::StateListener::post_startup().
167+
virtual void post_startup(VideoSource* source) override;
168+
159169
private:
160170
LabelImages& m_program;
161171
ImageAnnotationDisplaySession& m_display_session;
162-
ImageAnnotationDisplayWidget* m_switch_widget;
172+
173+
ImageAnnotationDisplayWidget* m_image_display_widget;
174+
163175
VideoOverlaySet m_overlay_set;
164176
DrawnBoundingBox m_drawn_box;
177+
178+
QLabel* m_embedding_info_label = nullptr;
165179
ConfigWidget* m_option_widget;
166180

167181
friend class DrawnBoundingBox;

SerialPrograms/Source/ML/UI/ML_ImageAnnotationCommandRow.cpp

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ ImageAnnotationCommandRow::ImageAnnotationCommandRow(
3333
{
3434
QHBoxLayout* command_row = new QHBoxLayout(this);
3535
command_row->setContentsMargins(0, 0, 0, 0);
36-
37-
command_row->addWidget(new QLabel("<b>Console Type:</b>", this), 2);
38-
command_row->addSpacing(5);
39-
4036
QHBoxLayout* row = new QHBoxLayout();
4137
command_row->addLayout(row, 12);
4238

@@ -80,12 +76,6 @@ ImageAnnotationCommandRow::ImageAnnotationCommandRow(
8076

8177
row->addSpacing(5);
8278

83-
m_load_profile_button = new QPushButton("Load Profile", this);
84-
row->addWidget(m_load_profile_button, 2);
85-
86-
m_save_profile_button = new QPushButton("Save Profile", this);
87-
row->addWidget(m_save_profile_button, 2);
88-
8979
// m_test_button = new QPushButton("Test Button", this);
9080
// row->addWidget(m_test_button, 3);
9181

@@ -132,30 +122,6 @@ ImageAnnotationCommandRow::ImageAnnotationCommandRow(
132122
this, [this](Qt::CheckState state){ m_session.set_enabled_stats(state == Qt::Checked); }
133123
);
134124
#endif
135-
connect(
136-
m_load_profile_button, &QPushButton::clicked,
137-
this, [this](bool) { emit load_profile(); }
138-
);
139-
connect(
140-
m_save_profile_button, &QPushButton::clicked,
141-
this, [this](bool) { emit save_profile(); }
142-
);
143-
144-
#if (QT_VERSION_MAJOR == 6) && (QT_VERSION_MINOR >= 8)
145-
if (IS_BETA_VERSION || PreloadSettings::instance().DEVELOPER_MODE){
146-
m_video_button = new QPushButton("Video Capture", this);
147-
command_row->addWidget(m_video_button, 2);
148-
if (GlobalSettings::instance().STREAM_HISTORY->enabled()){
149-
connect(
150-
m_video_button, &QPushButton::clicked,
151-
this, [this](bool){ emit video_requested(); }
152-
);
153-
}else{
154-
m_video_button->setEnabled(false);
155-
m_video_button->setToolTip("Please turn on Stream History to enable video capture.");
156-
}
157-
}
158-
#endif
159125

160126
m_session.add_listener(*this);
161127
}
@@ -177,11 +143,6 @@ void ImageAnnotationCommandRow::set_focus(bool focused){
177143
}
178144

179145
void ImageAnnotationCommandRow::update_ui(){
180-
// cout << "ImageAnnotationCommandRow::update_ui(): focus = " << m_last_known_focus << endl;
181-
182-
bool stopped = m_last_known_state == ProgramState::STOPPED;
183-
m_load_profile_button->setEnabled(stopped);
184-
185146
if (!m_last_known_focus){
186147
m_status->setText(
187148
QString::fromStdString(

SerialPrograms/Source/ML/UI/ML_ImageAnnotationCommandRow.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ class ImageAnnotationCommandRow :
3939
void on_key_press(const QKeyEvent& key);
4040
void on_key_release(const QKeyEvent& key);
4141

42-
signals:
43-
void load_profile();
44-
void save_profile();
45-
void screenshot_requested();
46-
void video_requested();
47-
4842
public:
4943
void set_focus(bool focused);
5044
void update_ui();
@@ -69,9 +63,6 @@ class ImageAnnotationCommandRow :
6963
QCheckBox* m_overlay_boxes;
7064
QCheckBox* m_overlay_stats;
7165

72-
QPushButton* m_load_profile_button;
73-
QPushButton* m_save_profile_button;
74-
QPushButton* m_video_button;
7566
bool m_last_known_focus;
7667
ProgramState m_last_known_state;
7768
};

SerialPrograms/Source/ML/UI/ML_ImageAnnotationDisplaySession.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
#include "ML_ImageAnnotationDisplayOption.h"
1111
#include "ML_ImageAnnotationDisplaySession.h"
1212

13-
//#include <iostream>
14-
//using std::cout;
15-
//using std::endl;
13+
#include <iostream>
14+
using std::cout;
15+
using std::endl;
1616

1717
namespace PokemonAutomation{
1818
namespace ML{
@@ -47,19 +47,10 @@ ImageAnnotationDisplaySession::ImageAnnotationDisplaySession(ImageAnnotationDisp
4747
}
4848

4949

50-
void ImageAnnotationDisplaySession::get(ImageAnnotationDisplayOption& option){
51-
option.m_image_path = m_display_option.m_image_path;
52-
m_overlay.get(option.m_overlay);
53-
}
54-
void ImageAnnotationDisplaySession::set(const ImageAnnotationDisplayOption& option){
55-
set_image_source(option.m_image_path);
56-
m_overlay.set(option.m_overlay);
57-
}
58-
5950
void ImageAnnotationDisplaySession::set_image_source(const std::string& path){
51+
m_display_option.m_image_path = path;
6052
m_still_image_descriptor->set_path(path);
6153
m_video_session.set_source(m_still_image_descriptor);
62-
m_display_option.m_image_path = path;
6354
}
6455

6556

SerialPrograms/Source/ML/UI/ML_ImageAnnotationDisplaySession.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ class ImageAnnotationDisplaySession {
4949
const ImageAnnotationDisplayOption& option() const { return m_display_option; }
5050

5151
public:
52-
void get(ImageAnnotationDisplayOption& option);
53-
void set(const ImageAnnotationDisplayOption& option);
5452

5553
VideoSession& video_session(){ return m_video_session; }
5654
VideoOverlaySession& overlay_session(){ return m_overlay; }

SerialPrograms/Source/ML/UI/ML_ImageAnnotationDisplayWidget.cpp

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -84,46 +84,6 @@ ImageAnnotationDisplayWidget::ImageAnnotationDisplayWidget(
8484
}
8585

8686
setFocusPolicy(Qt::StrongFocus);
87-
88-
connect(
89-
m_command, &ImageAnnotationCommandRow::load_profile,
90-
m_command, [this](){
91-
std::string path = QFileDialog::getOpenFileName(this, tr("Choose the name of your profile file"), "", tr("JSON files (*.json)")).toStdString();
92-
if (path.empty()){
93-
return;
94-
}
95-
96-
ImageAnnotationDisplayOption option;
97-
// Deserialize into this local option instance.
98-
option.load_json(load_json_file(path));
99-
100-
m_session.set(option);
101-
}
102-
);
103-
connect(
104-
m_command, &ImageAnnotationCommandRow::save_profile,
105-
m_command, [this](){
106-
std::string path = QFileDialog::getSaveFileName(this, tr("Choose the name of your profile file"), "", tr("JSON files (*.json)")).toStdString();
107-
if (path.empty()){
108-
return;
109-
}
110-
111-
// Create a copy of option, to be able to serialize it later on
112-
ImageAnnotationDisplayOption option;
113-
m_session.get(option);
114-
option.to_json().dump(path);
115-
}
116-
);
117-
118-
connect(
119-
m_command, &ImageAnnotationCommandRow::video_requested,
120-
m_video_display, [this](){
121-
global_dispatcher.dispatch([this]{
122-
std::string filename = SCREENSHOTS_PATH() + "video-" + now_to_filestring() + ".mp4";
123-
m_session.logger().log("Saving screenshot to: " + filename, COLOR_PURPLE);
124-
});
125-
}
126-
);
12787
}
12888

12989

0 commit comments

Comments
 (0)