Przeglądaj źródła

-added menu->view to see the result of image segmentation
-added undo/redo for poly selecting tool(edit->undo/redo, ctrl+z/y)
-added a possibility to interrupt recursive searching for images

gapchich 13 lat temu
rodzic
commit
7dda85666b
4 zmienionych plików z 235 dodań i 151 usunięć
  1. 36 0
      ImageHolder.cpp
  2. 3 0
      ImageHolder.h
  3. 182 151
      ImageLabeler.cpp
  4. 14 0
      ImageLabeler.h

+ 36 - 0
ImageHolder.cpp

@@ -494,6 +494,42 @@ ImageHolder::tool()
 	return tool_;
 }
 
+void
+ImageHolder::undo()
+{
+	if (PolygonTool == tool_ &&
+		NewSelection == state_ &&
+		!polygon_.poly.isEmpty())
+	{
+		list_poly_history_.append(polygon_.poly.last());
+		polygon_.poly.pop_back();
+		repaint_needed_ = 1;
+	}
+
+	if (repaint_needed_) {
+		update();
+		repaint_needed_ = 0;
+	}
+}
+
+void
+ImageHolder::redo()
+{
+	if (PolygonTool == tool_ &&
+		NewSelection == state_ &&
+		!list_poly_history_.isEmpty())
+	{
+		polygon_.poly.append(list_poly_history_.last());
+		list_poly_history_.pop_back();
+		repaint_needed_ = 1;
+	}
+
+	if (repaint_needed_) {
+		update();
+		repaint_needed_ = 0;
+	}
+}
+
 void
 ImageHolder::keyPressEvent(QKeyEvent *anEvent)
 {

+ 3 - 0
ImageHolder.h

@@ -90,6 +90,8 @@ public slots:
 	void confirmSelection();
 	void focusOnArea(QListWidgetItem *anItem);
 	void clearFocusOnArea();
+	void undo();
+	void redo();
 
 signals:
 	void selectionStarted();
@@ -101,6 +103,7 @@ private:
 	QList< BoundingBox > *list_bounding_box_;
 	QList< Polygon > *list_polygon_;
 	QList< uint > *list_label_color_;
+	QList< QPoint > list_poly_history_;
 	QPixmap *image_;
 	int *main_label_;
 	BoundingBox bounding_box_;

+ 182 - 151
ImageLabeler.cpp

@@ -22,6 +22,7 @@
 #include <QButtonGroup>
 #include <QListWidget>
 #include <QListWidgetItem>
+#include <QDesktopWidget>
 #include <QFileDialog>
 #include <QColorDialog>
 #include <QDir>
@@ -48,6 +49,9 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 	/* options */
 	auto_color_generation_ = 0;
 
+	/* flags */
+	interrupt_search_ = 0;
+
 	/*
 	 * menu bar part begins
 	 */
@@ -57,32 +61,39 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 
 	menu_file_ = new QMenu(menu_bar_);
 	menu_file_->setTitle(tr("&File"));
+	menu_view_ = new QMenu(menu_bar_);
+	menu_view_->setTitle(tr("&View"));
 	menu_edit_ = new QMenu(menu_bar_);
 	menu_edit_->setTitle(tr("&Edit"));
 	menu_help_ = new QMenu(menu_bar_);
 	menu_help_->setTitle(tr("&Help"));
 
+	/* menu file */
 	action_open_images_ = new QAction(this);
 	action_open_images_->setText(tr("&Load images"));
-
 	action_open_labeled_image_ = new QAction(this);
 	action_open_labeled_image_->setText(tr("&Open labeled image"));
-
 	action_load_legend_ = new QAction(this);
 	action_load_legend_->setText(tr("Load &legend"));
-
 	action_save_labels_ = new QAction(this);
 	action_save_labels_->setText(tr("&Save all info"));
 	action_save_labels_->setEnabled(false);
-
 	action_save_segmented_ = new QAction(this);
 	action_save_segmented_->setText(tr("Save segmented &picture"));
 	action_save_segmented_->setEnabled(false);
-
 	action_save_legend_ = new QAction(this);
 	action_save_legend_->setText(tr("Save &legend"));
 	action_save_legend_->setEnabled(false);
-
+	action_quit_ = new QAction(this);
+	action_quit_->setText(tr("&Quit"));
+	/* menu view */
+	action_view_normal_ = new QAction(this);
+	action_view_normal_->setText(tr("&Normal"));
+	action_view_normal_->setEnabled(false);
+	action_view_segmented_ = new QAction(this);
+	action_view_segmented_->setText(tr("&Segmented"));
+	action_view_segmented_->setEnabled(false);
+	/* menu edit */
 	action_undo_ = new QAction(this);
 	action_undo_->setText(tr("&Undo"));
 	action_undo_->setEnabled(false);
@@ -103,7 +114,7 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 	action_add_description_->setEnabled(false);
 	action_options_ = new QAction(this);
 	action_options_->setText(tr("&Options"));
-
+	/* menu help */
 	action_help_content_ = new QAction(this);
 	action_help_content_->setText(tr("&Help content"));
 	action_help_content_->setEnabled(false);
@@ -112,13 +123,6 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 	action_about_->setEnabled(false);
 	/* ------------------ */
 
-	action_quit_ = new QAction(this);
-	action_quit_->setText(tr("&Quit"));
-
-	menu_bar_->addAction(menu_file_->menuAction());
-	menu_bar_->addAction(menu_edit_->menuAction());
-	menu_bar_->addAction(menu_help_->menuAction());
-
 	menu_file_->addAction(action_open_images_);
 	menu_file_->addAction(action_open_labeled_image_);
 	menu_file_->addAction(action_load_legend_);
@@ -127,6 +131,9 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 	menu_file_->addAction(action_save_labels_);
 	menu_file_->addAction(action_quit_);
 
+	menu_view_->addAction(action_view_normal_);
+	menu_view_->addAction(action_view_segmented_);
+
 	menu_edit_->addAction(action_undo_);
 	menu_edit_->addAction(action_redo_);
 	menu_edit_->addAction(action_bound_box_tool_);
@@ -138,6 +145,11 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 	menu_help_->addAction(action_help_content_);
 	menu_help_->addAction(action_about_);
 
+	menu_bar_->addAction(menu_file_->menuAction());
+	menu_bar_->addAction(menu_view_->menuAction());
+	menu_bar_->addAction(menu_edit_->menuAction());
+	menu_bar_->addAction(menu_help_->menuAction());
+
 	/*
 	 * popup menu part begins
 	 */
@@ -378,6 +390,42 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 		this,
 		SLOT(saveAllInfo())
 		);
+	connect(
+		action_view_normal_,
+		SIGNAL(triggered()),
+		this,
+		SLOT(viewNormal())
+		);
+	connect(
+		action_view_segmented_,
+		SIGNAL(triggered()),
+		this,
+		SLOT(viewSegmented())
+		);
+	connect(
+		action_undo_,
+		SIGNAL(triggered()),
+		image_holder_,
+		SLOT(undo())
+		);
+	connect(
+		action_redo_,
+		SIGNAL(triggered()),
+		image_holder_,
+		SLOT(redo())
+		);
+	connect(
+		action_add_description_,
+		SIGNAL(triggered()),
+		&image_description_form_,
+		SLOT(show())
+		);
+	connect(
+		action_options_,
+		SIGNAL(triggered()),
+		&options_form_,
+		SLOT(show())
+		);
 	connect(
 		button_add_label_,
 		SIGNAL(clicked()),
@@ -503,18 +551,6 @@ ImageLabeler::ImageLabeler(QWidget *aParent) :
 		this,
 		SLOT(removeLabel())
 		);
-	connect(
-		action_add_description_,
-		SIGNAL(triggered()),
-		&image_description_form_,
-		SLOT(show())
-		);
-	connect(
-		action_options_,
-		SIGNAL(triggered()),
-		&options_form_,
-		SLOT(show())
-		);
 	connect(
 		image_holder_,
 		SIGNAL(selectionStarted()),
@@ -557,6 +593,8 @@ ImageLabeler::~ImageLabeler()
 	delete action_save_legend_;
 	delete action_save_segmented_;
 	delete action_save_labels_;
+	delete action_view_normal_;
+	delete action_view_segmented_;
 	delete action_undo_;
 	delete action_redo_;
 	delete action_bound_box_tool_;
@@ -568,6 +606,7 @@ ImageLabeler::~ImageLabeler()
 	delete action_help_content_;
 
 	delete menu_file_;
+	delete menu_view_;
 	delete menu_edit_;
 	delete menu_help_;
 
@@ -1007,6 +1046,11 @@ ImageLabeler::getImagesFromDir(const QDir &dir)
 	/* avoiding freezing during recursive search for files */
 	QApplication::processEvents();
 
+	if (interrupt_search_) {
+		clearAll();
+		return;
+	}
+
 	QStringList filenameFilter;
 	filenameFilter <<
 		"*.jpeg" <<
@@ -1116,6 +1160,14 @@ ImageLabeler::saveAllInfo()
 	QDomText pathToImage = doc.createTextNode(*current_image_);
 	image.appendChild(pathToImage);
 
+	if (!segmented_image_.isEmpty()) {
+		QDomElement segmentedImage = doc.createElement(tr("segmented"));
+		root.appendChild(segmentedImage);
+
+		QDomText pathToSegmented = doc.createTextNode(segmented_image_);
+		image.appendChild(pathToSegmented);
+	}
+
 	QDomElement description = doc.createElement(tr("description"));
 	root.appendChild(description);
 
@@ -1123,88 +1175,6 @@ ImageLabeler::saveAllInfo()
 	description.appendChild(descriptionText);
 
 	legendToXml(&doc, &root);
-//	QDomElement legend = doc.createElement(tr("legend"));
-//	root.appendChild(legend);
-//
-//	/* storing all labels made by user */
-//	int labelCount = list_label_->count();
-//	for (int i = 0; i < labelCount; i++) {
-//		QDomElement label = doc.createElement(tr("label"));
-//		label.setAttribute("color", QString("%1").arg(list_label_colors_.at(i), 0, 16));
-//		label.setAttribute("id", i);
-//
-//		QString priority;
-//		if (main_label_ == i)
-//			priority.append("1");
-//		else
-//			priority.append("0");
-//		label.setAttribute("isMain", priority);
-//
-//		QString labelText = list_label_->item(i)->text();
-//
-//		/* removing the number prefix of label */
-//		if (-1 != labelText.indexOf(QString("%1: ").arg(i))) {
-//			labelText = labelText.mid(3, labelText.size() - 3);
-//		}
-//
-//		QDomText labelName = doc.createTextNode(labelText);
-//		label.appendChild(labelName);
-//		legend.appendChild(label);
-//	}
-//
-//	/* in case we have no labels */
-//	if (0 == labelCount) {
-//		QDomElement label = doc.createElement(tr("label"));
-//		label.setAttribute(tr("id"), -1);
-//		legend.appendChild(label);
-//	}
-
-	/* objects - selected areas */
-	objectsToXml(&doc, &root);
-//	QDomElement objects = doc.createElement(tr("objects"));
-//	root.appendChild(objects);
-//
-//	/* rects first */
-//	for (int i = 0; i < list_bounding_box_.size(); i++) {
-//		QDomElement rectData = doc.createElement(tr("bbox"));
-//
-//		rectData.setAttribute("id", list_bounding_box_.at(i).label_ID_);
-//
-//		QRect rect = list_bounding_box_.at(i).rect.normalized();
-//
-//		QString rectDataString =
-//			QString("%1;%2;%3;%4;").
-//				arg(rect.x()).
-//				arg(rect.y()).
-//				arg(rect.width()).
-//				arg(rect.height());
-//
-//		QDomText rectDataText = doc.createTextNode(rectDataString);
-//		rectData.appendChild(rectDataText);
-//		objects.appendChild(rectData);
-//	}
-//
-//	/* polys next */
-//	for (int i = 0; i < list_polygon_.size(); i++) {
-//		QDomElement polyData = doc.createElement(tr("poly"));
-//
-//		polyData.setAttribute("id", list_polygon_.at(i).label_ID_);
-//
-//		QPolygon poly = list_polygon_.at(i).poly;
-//
-//		QString polyDataString;
-//		for (int j = 0; j < poly.count(); j++)
-//			polyDataString.append(
-//				QString("%1;%2;").
-//					arg(poly.point(j).x()).
-//					arg(poly.point(j).y())
-//				);
-//
-//
-//		QDomText polyDataText = doc.createTextNode(polyDataString);
-//		polyData.appendChild(polyDataText);
-//		objects.appendChild(polyData);
-//	}
 
 	setPureData();
 	QDomElement pureData = doc.createElement(tr("pure_data"));
@@ -1340,8 +1310,14 @@ ImageLabeler::saveSegmentedPicture()
 			newImage.setPixel(j, i, list_label_colors_.at(pure_data_[i][j]));
 		}
 
-	if (!newImage.save(filename, "png", 100))
+	if (!newImage.save(filename, "png", 100)) {
 		showWarning(tr("An error occurred while saving the segmented image"));
+		return;
+		/* NOTREACHED */
+	}
+
+	segmented_image_ = filename;
+	action_view_segmented_->setEnabled(true);
 }
 
 void
@@ -1362,42 +1338,6 @@ ImageLabeler::saveLegend()
 
 		legendToXml(&doc, &root);
 
-//		QDomElement legend = doc.createElement(tr("legend"));
-//		root.appendChild(legend);
-//
-//		/* storing all labels made by user */
-//		int labelCount = list_label_->count();
-//		for (int i = 0; i < labelCount; i++) {
-//			QDomElement label = doc.createElement(tr("label"));
-//			label.setAttribute("color", QString("%1").arg(list_label_colors_.at(i), 0, 16));
-//			label.setAttribute("id", i);
-//
-//			QString priority;
-//			if (main_label_ == i)
-//				priority.append("1");
-//			else
-//				priority.append("0");
-//			label.setAttribute("isMain", priority);
-//
-//			QString labelText = list_label_->item(i)->text();
-//
-//			/* removing the number prefix of label */
-//			if (-1 != labelText.indexOf(QString("%1: ").arg(i))) {
-//				labelText = labelText.mid(3, labelText.size() - 3);
-//			}
-//
-//			QDomText labelName = doc.createTextNode(labelText);
-//			label.appendChild(labelName);
-//			legend.appendChild(label);
-//		}
-//
-//		/* in case we have no labels */
-//		if (0 == labelCount) {
-//			QDomElement label = doc.createElement(tr("label"));
-//			label.setAttribute(tr("id"), -1);
-//			legend.appendChild(label);
-//		}
-
 		QString xml = doc.toString();
 		/* ------------------------------------------------------------------------
 		 * XML part ends
@@ -1495,7 +1435,7 @@ ImageLabeler::loadInfo()
 			/* path to the image */
 			if (element.tagName() == "image") {
 				string = element.text();
-				if (string.isNull()) {
+				if (string.isEmpty()) {
 					showWarning(
 						tr(
 						"The file with data doesn't contain path to the image"
@@ -1508,11 +1448,21 @@ ImageLabeler::loadInfo()
 				current_image_ = list_images_->end();
 				current_image_--;
 				image_->load(*current_image_);
+				image_holder_->resize(image_->size());
 				image_holder_->setPixmap(*image_);
 			}
+			/* path to the segmented image */
+			if (element.tagName() == "segmented") {
+				string = element.text();
+				if (string.isEmpty()) {
+					continue;
+				}
+				segmented_image_ = string;
+				action_view_segmented_->setEnabled(true);
+			}
 			/* image description */
 			else if (element.tagName() == "description" &&
-				!element.text().isNull()) {
+				!element.text().isEmpty()) {
 				image_description_ = element.text();
 			}
 			/* legend */
@@ -1527,7 +1477,7 @@ ImageLabeler::loadInfo()
 				while(!subNode.isNull()) {
 					subElement = subNode.toElement();
 
-					if (subElement.isNull() || subElement.text().isNull()) {
+					if (subElement.isNull() || subElement.text().isEmpty()) {
 						subNode = subNode.nextSibling();
 						continue;
 					}
@@ -1585,8 +1535,36 @@ ImageLabeler::loadImages()
 
 	clearAllTool();
 
+	QWidget *searchInProgress = new QWidget(0);
+	searchInProgress->setWindowTitle(tr("Loading images"));
+	QLabel *info = new QLabel(searchInProgress);
+	info->setText(
+		tr("Program is looking for all image files in your directory recursively."));
+	QPushButton *cancel = new QPushButton(tr("Cancel"), searchInProgress);
+	connect(cancel, SIGNAL(clicked()), this, SLOT(interruptSearch()));
+	QVBoxLayout *layout = new QVBoxLayout(searchInProgress);
+	searchInProgress->setLayout(layout);
+	layout->addWidget(info);
+	layout->addWidget(cancel);
+	searchInProgress->adjustSize();
+	searchInProgress->move(QApplication::desktop()->screen()->rect().center() - rect().center());
+	searchInProgress->show();
+
 	getImagesFromDir(QDir(dirName));
 
+	cancel->disconnect();
+	searchInProgress->hide();
+	delete info;
+	delete cancel;
+	delete layout;
+	delete searchInProgress;
+
+	if (interrupt_search_) {
+		interrupt_search_ = 0;
+		return;
+		/* NOTREACHED */
+	}
+
 	if (list_images_->isEmpty()) {
 		showWarning(tr("The folder you selected contains no images"));
 		return;
@@ -1671,7 +1649,7 @@ ImageLabeler::loadLegendFromNode(QDomElement *anElement)
 	while(!subNode.isNull()) {
 		subElement = subNode.toElement();
 
-		if (!subElement.isNull() && !subElement.text().isNull()) {
+		if (!subElement.isNull() && !subElement.text().isEmpty()) {
 			string = subElement.attribute("id");
 			bool ok = 0;
 			id = string.toInt(&ok, 10);
@@ -2253,6 +2231,9 @@ ImageLabeler::clearAll()
 	list_images_->clear();
 	main_label_ = -1;
 	image_holder_->clearAll();
+	segmented_image_.clear();
+	action_view_normal_->setEnabled(false);
+	action_view_segmented_->setEnabled(false);
 }
 
 void
@@ -2284,6 +2265,8 @@ ImageLabeler::enableTools()
 	action_bound_box_tool_->setEnabled(true);
 	action_polygon_tool_->setEnabled(true);
 	action_add_description_->setEnabled(true);
+	action_undo_->setEnabled(true);
+	action_redo_->setEnabled(true);
 	button_bound_box_tool_->setEnabled(true);
 	button_polygon_tool_->setEnabled(true);
 	button_add_label_->setEnabled(true);
@@ -2304,6 +2287,8 @@ ImageLabeler::disableTools()
 	action_bound_box_tool_->setEnabled(false);
 	action_polygon_tool_->setEnabled(false);
 	action_add_description_->setEnabled(false);
+	action_undo_->setEnabled(false);
+	action_redo_->setEnabled(false);
 	button_bound_box_tool_->setEnabled(false);
 	button_polygon_tool_->setEnabled(false);
 	button_add_label_->setEnabled(false);
@@ -2461,6 +2446,42 @@ ImageLabeler::onOptionsSet()
 	auto_color_generation_ = options_form_.autoColorGeneration();
 }
 
+void
+ImageLabeler::viewNormal()
+{
+	if ((*current_image_).isEmpty()) {
+		return;
+		/* NOTREACHED */
+	}
+
+	image_->load(*current_image_);
+	image_holder_->setPixmap(*image_);
+
+	action_view_segmented_->setEnabled(true);
+	action_view_normal_->setEnabled(false);
+}
+
+void
+ImageLabeler::viewSegmented()
+{
+	if (segmented_image_.isEmpty()) {
+		return;
+		/* NOTREACHED */
+	}
+
+	image_->load(segmented_image_);
+	image_holder_->setPixmap(*image_);
+
+	action_view_segmented_->setEnabled(false);
+	action_view_normal_->setEnabled(true);
+}
+
+void
+ImageLabeler::interruptSearch()
+{
+	interrupt_search_ = 1;
+}
+
 void
 ImageLabeler::resizeEvent (QResizeEvent *anEvent)
 {
@@ -2486,7 +2507,8 @@ ImageLabeler::keyPressEvent(QKeyEvent *anEvent)
 		nextImage();
 	}
 
-	if (Qt::Key_Enter == anEvent->key() &&
+	if ((Qt::Key_Enter == anEvent->key() ||
+		Qt::Key_Return == anEvent->key()) &&
 	//	Qt::NoModifier == anEvent->modifiers() &&
 		ImageHolder::NewSelection == image_holder_->state()) {
 		confirmSelection();
@@ -2497,10 +2519,19 @@ ImageLabeler::keyPressEvent(QKeyEvent *anEvent)
 		image_holder_->clearFocusOnArea();
 	}
 
+	if (Qt::Key_Z == anEvent->key() &&
+		Qt::ControlModifier == anEvent->modifiers()) {
+		image_holder_->undo();
+	}
+
+	if (Qt::Key_Y == anEvent->key() &&
+		Qt::ControlModifier == anEvent->modifiers()) {
+		image_holder_->redo();
+	}
+
 	QWidget::keyPressEvent(anEvent);
 }
 
-/* TODO: finish scaling */
 void
 ImageLabeler::wheelEvent(QWheelEvent *anEvent)
 {

+ 14 - 0
ImageLabeler.h

@@ -124,13 +124,18 @@ public slots:
 	void setPureData();
 	void setLabelColor();
 	void setLabelColor(int anID, QColor aColor);
+	void viewNormal();
+	void viewSegmented();
+	void interruptSearch();
 
 private:
 	/* menu */
 	QMenuBar *menu_bar_;
 	QMenu *menu_file_;
+	QMenu *menu_view_;
 	QMenu *menu_edit_;
 	QMenu *menu_help_;
+	/* menu file */
 	QAction *action_open_images_;
 	QAction *action_open_image_;
 	QAction *action_open_labeled_image_;
@@ -139,6 +144,10 @@ private:
 	QAction *action_save_segmented_;
 	QAction *action_save_legend_;
 	QAction *action_quit_;
+	/* menu view */
+	QAction *action_view_normal_;
+	QAction *action_view_segmented_;
+	/* menu edit */
 	QAction *action_undo_;
 	QAction *action_redo_;
 	QAction *action_bound_box_tool_;
@@ -146,6 +155,7 @@ private:
 	QAction *action_tagging_tool_;
 	QAction *action_add_description_;
 	QAction *action_options_;
+
 	QAction *action_about_;
 	QAction *action_help_content_;
 
@@ -211,6 +221,7 @@ private:
 	QString image_description_;
 	QStringList *list_images_;
 	QStringList::iterator current_image_;
+	QString segmented_image_;
 	QList< BoundingBox > list_bounding_box_;
 	QList< Polygon > list_polygon_;
 	QList< uint > list_label_colors_;
@@ -219,6 +230,9 @@ private:
 
 	/* options */
 	bool auto_color_generation_;
+
+	/* flags */
+	bool interrupt_search_;
 };
 
 #endif /* __IMAGELABELER_H__ */