Browse Source

-added buttons, labels, regrouped menu
-polygon editing is more flexible now:
new point creating is available
point deleting is available

gapchich 13 năm trước cách đây
mục cha
commit
f479ec68e9
10 tập tin đã thay đổi với 468 bổ sung57 xóa
  1. 129 10
      ImageHolder.cpp
  2. 15 6
      ImageHolder.h
  3. 200 29
      ImageLabeler.cpp
  4. 37 2
      ImageLabeler.h
  5. 2 1
      ImageLabeler.pro
  6. 3 1
      Makefile
  7. 4 4
      Makefile.Debug
  8. 4 4
      Makefile.Release
  9. 61 0
      functions.cpp
  10. 13 0
      functions.h

+ 129 - 10
ImageHolder.cpp

@@ -31,6 +31,8 @@ ImageHolder::ImageHolder(QWidget *aParent)
 	hovered_point_.figureID = -1;
 	hovered_point_.pointID = -1;
 
+	selected_point_ = -1;
+
 	list_bounding_box_ = 0;
 	main_label_ = 0;
 	//list_bounding_box_ = new QList< QRect >;
@@ -111,7 +113,7 @@ void
 ImageHolder::drawBoundingBoxes(
 	QPainter *aPainter,
 	QPen *aPen
-)
+) const
 {
 	if (0 == list_bounding_box_)
 	{
@@ -225,7 +227,7 @@ void
 ImageHolder::drawPolygons(
 	QPainter *aPainter,
 	QPen *aPen
-)
+) const
 {
 	if (0 == list_polygon_)
 	{
@@ -280,9 +282,10 @@ ImageHolder::drawPolygons(
 				circPen.setColor(aPen->color());
 				aPainter->setPen(circPen);
 				/* filling the point if it is hovered */
-				if (j == hovered_point_.pointID &&
+				if ((j == hovered_point_.pointID &&
 					i == hovered_point_.figureID &&
-					PolyFigure == hovered_point_.figure) {
+					PolyFigure == hovered_point_.figure) ||
+					j == selected_point_) {
 					QBrush brush;
 					brush.setColor(aPen->color());
 					brush.setStyle(Qt::SolidPattern);
@@ -603,28 +606,28 @@ ImageHolder::confirmSelection()
 
 //! returns state
 ImageHolder::State
-ImageHolder::state()
+ImageHolder::state() const
 {
 	return state_;
 }
 
 //! returns tool
 ImageHolder::Tool
-ImageHolder::tool()
+ImageHolder::tool() const
 {
 	return tool_;
 }
 
 //! returns focused_selection_
 int
-ImageHolder::focusedSelection()
+ImageHolder::focusedSelection() const
 {
 	return focused_selection_;
 }
 
 //! returns focused_selection_type_
 Figure
-ImageHolder::focusedSelectionType()
+ImageHolder::focusedSelectionType() const
 {
 	return focused_selection_type_;
 }
@@ -752,6 +755,81 @@ ImageHolder::checkForPoints(QPoint *aPos)
 	repaint_needed_ = 1;
 }
 
+//! Returns position index of the point in polygon
+/*!
+ * \param[in] aPos point to insert into the polygon
+ * \param[in] aPoly polygon
+ */
+int
+ImageHolder::posInPolygon(QPoint *aPos, QPolygon *aPoly) const
+{
+	if (!aPos || !aPoly || aPoly->count() < 2 || aPos->isNull()) {
+		return -1;
+		/* NOTREACHED */
+	}
+
+	int x = aPos->x();
+	int y = aPos->y();
+
+	int index = 0;
+	int dist = 100000;
+	int temp = 0;
+	int count = aPoly->count();
+	QRect rect;
+
+	for (int i = 0; i < count - 1; i++) {
+		temp = pointToLineDistance(
+			QLine(aPoly->at(i), aPoly->at(i + 1)),
+			*aPos
+			);
+		rect.setTopLeft(aPoly->at(i));
+		rect.setBottomRight(aPoly->at(i + 1));
+		rect = rect.normalized();
+		if (temp < dist &&
+			((x < rect.right() && rect.left() < x) ||
+			(y < rect.bottom() && rect.top() < y)))
+		{
+			dist = temp;
+			index = i + 1;
+		}
+	}
+
+	/* first and last points */
+	temp = pointToLineDistance(
+		QLine(aPoly->at(0), aPoly->at(count - 1)),
+		*aPos
+		);
+
+	rect.setTopLeft(aPoly->at(0));
+	rect.setBottomRight(aPoly->at(count - 1));
+	rect = rect.normalized();
+	if (temp < dist &&
+		((x < rect.right() && rect.left() < x) ||
+		(y < rect.bottom() && rect.top() < y)))
+	{
+		index = 0;
+	}
+
+	return index;
+}
+
+//! Removes selected point from focused polygon
+void
+ImageHolder::removeSelectedPoint()
+{
+	if (-1 == selected_point_ ||
+		-1 == focused_selection_ ||
+		focused_selection_type_ != PolyFigure)
+	{
+		return;
+		/* NOTREACHED */
+	}
+
+	list_polygon_->at(focused_selection_)->poly.remove(selected_point_);
+	selected_point_ = -1;
+	update();
+}
+
 void
 ImageHolder::keyPressEvent(QKeyEvent *anEvent)
 {
@@ -779,7 +857,7 @@ ImageHolder::mouseMoveEvent(QMouseEvent *anEvent)
 	if (height() < anEvent->pos().y())
 		pos.setY(height() - 1);
 
-
+	/* modifying rectangle  */
 	if ((anEvent->buttons() & Qt::LeftButton) &&
 		BoundingBoxTool == tool_ &&
 		NewSelection == state_ &&
@@ -788,12 +866,12 @@ ImageHolder::mouseMoveEvent(QMouseEvent *anEvent)
 		triggerBoundBox(pos, prev_cursor_pos_, &(bounding_box_.rect));
 	}
 
+	/* moving last point of the poly during creating a new one */
 	if (PolygonTool == tool_ &&
 		NewSelection == state_ &&
 		(anEvent->buttons() & Qt::LeftButton))
 	{
 		polygon_.poly.setPoint(polygon_.poly.count() - 1, pos);
-		//triggerPolygon(pos, &(polygon_.poly));
 		repaint_needed_ = 1;
 	}
 
@@ -883,6 +961,47 @@ ImageHolder::mousePressEvent(QMouseEvent *anEvent)
 				polygon_.poly << prev_cursor_pos_;
 			}
 		}
+
+		/* selecting a point */
+		selected_point_ = -1;
+		repaint_needed_ = 1;
+		if (-1 != hovered_point_.figureID &&
+			!list_polygon_->isEmpty() &&
+			PolyFigure == hovered_point_.figure &&
+			hovered_point_.figureID == focused_selection_)
+		{
+			selected_point_ = hovered_point_.pointID;
+		}
+	}
+
+	if (repaint_needed_) {
+		update();
+		repaint_needed_ = 0;
+	}
+}
+
+void
+ImageHolder::mouseDoubleClickEvent(QMouseEvent *anEvent)
+{
+	QPoint pos = anEvent->pos() / scale_;
+
+	/* new point for polygon */
+	if (-1 == hovered_point_.figureID &&
+		!list_polygon_->isEmpty() &&
+		-1 != focused_selection_ &&
+		PolyFigure == focused_selection_type_ &&
+		(anEvent->buttons() & Qt::LeftButton))
+	{
+		Polygon *poly = list_polygon_->at(focused_selection_);
+		int index = posInPolygon(&pos, &(poly->poly));
+
+		if (index < 0 || poly->poly.count() <= index) {
+			return;
+			/* NOTREACHED */
+		}
+
+		poly->poly.insert(index, pos);
+		repaint_needed_ = 1;
 	}
 
 	if (repaint_needed_) {

+ 15 - 6
ImageHolder.h

@@ -58,6 +58,7 @@ protected:
 	void keyPressEvent(QKeyEvent *anEvent);
 	void mouseMoveEvent(QMouseEvent *anEvent);
 	void mousePressEvent(QMouseEvent *anEvent);
+	void mouseDoubleClickEvent(QMouseEvent *anEvent);
 	void mouseReleaseEvent(QMouseEvent *anEvent);
 	void paintEvent (QPaintEvent *anEvent);
 
@@ -73,12 +74,16 @@ protected:
 	void drawBoundingBoxes(
 		QPainter *aPainter,
 		QPen *aPen
-		);
+		) const;
 	void drawPolygons(
 		QPainter *aPainter,
 		QPen *aPen
-		);
+		) const;
 	void checkForPoints(QPoint *aPos);
+	int posInPolygon(
+		QPoint *aPos,
+		QPolygon *aPoly
+		) const;
 
 public:
 	enum Tool {
@@ -102,10 +107,10 @@ public:
 	void setMainLabelNum(int *aNum);
 	void setImage(QPixmap *anImage);
 	void scaleImage(ZoomDirection aDirection, double scaleFactor);
-	int focusedSelection();
-	Figure focusedSelectionType();
-	State state();
-	Tool tool();
+	int focusedSelection() const;
+	Figure focusedSelectionType() const;
+	State state() const;
+	Tool tool() const;
 
 
 public slots:
@@ -117,6 +122,7 @@ public slots:
 	void clearHoveredPoint();
 	void undo();
 	void redo();
+	void removeSelectedPoint();
 
 signals:
 	void selectionStarted();
@@ -168,6 +174,9 @@ private:
 	//! \see checkForPoints(QPoint *aPos)
 	HoveredPoint hovered_point_;
 
+	//! keeps the selected point number
+	int selected_point_;
+
 	//! \brief keeps the position of a mouse when it was clicked
 	QPoint prev_cursor_pos_;
 

+ 200 - 29
ImageLabeler.cpp

@@ -80,6 +80,12 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 
 	menu_file_ = new QMenu(menu_bar_);
 	menu_file_->setTitle(tr("&File"));
+
+	menu_save_ = new QMenu(menu_bar_);
+	menu_save_->setTitle(tr("&Save"));
+	menu_load_ = new QMenu(menu_bar_);
+	menu_load_->setTitle(tr("&Load"));
+
 	menu_pascal_ = new QMenu(menu_bar_);
 	menu_pascal_->setTitle(tr("&Pascal"));
 	menu_view_ = new QMenu(menu_bar_);
@@ -151,15 +157,18 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	action_about_->setEnabled(false);
 	/* ------------------ */
 
-	menu_file_->addAction(action_open_image_);
-	menu_file_->addAction(action_open_images_);
-	menu_file_->addAction(action_open_labeled_image_);
-	menu_file_->addAction(action_load_legend_);
+	menu_load_->addAction(action_open_image_);
+	menu_load_->addAction(action_open_images_);
+	menu_load_->addAction(action_open_labeled_image_);
+	menu_load_->addAction(action_load_legend_);
+	menu_save_->addAction(action_save_segmented_);
+	menu_save_->addAction(action_save_legend_);
+	menu_save_->addAction(action_save_all_);
+	menu_file_->addAction(menu_load_->menuAction());
+	menu_file_->addAction(menu_save_->menuAction());
 	menu_file_->addAction(menu_pascal_->menuAction());
-	menu_file_->addSeparator();
-	menu_file_->addAction(action_save_segmented_);
-	menu_file_->addAction(action_save_legend_);
-	menu_file_->addAction(action_save_all_);
+	//menu_file_->addSeparator();
+
 	menu_file_->addSeparator();
 	menu_file_->addAction(action_quit_);
 
@@ -247,13 +256,14 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	image_ = new QPixmap(500, 500);
 	image_->fill(QColor(Qt::white));
 
-	image_holder_ = new ImageHolder;//(frame_image_);
+	image_holder_ = new ImageHolder;
 	image_holder_->setPixmap(*image_);
 	image_holder_->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
 	image_holder_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
 	image_holder_->setScaledContents(true);
 	image_holder_->setFrameStyle(QFrame::Box | QFrame::Plain);
 	image_holder_->setLineWidth(0);
+	image_holder_->setFocusPolicy(Qt::StrongFocus);
 
 	frame_image_->setWidget(image_holder_);
 
@@ -265,6 +275,7 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	list_images_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
 
 	label_toolbox_ = new QLabel(tr("Tool box"), frame_toolbox_);
+	label_list_label_ = new QLabel(tr("Object labels:"), central_widget_);
 	label_list_areas_ = new QLabel(tr("Selected areas:"), central_widget_);
 	label_list_images_ = new QLabel(tr("Loaded images:"), central_widget_);
 
@@ -305,6 +316,22 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	button_remove_label_->setText(tr("Remove label"));
 	button_remove_label_->setEnabled(false);
 
+	button_delete_area_ = new QPushButton(frame_labelbox_);
+	button_delete_area_->setText(tr("Delete area"));
+	button_delete_area_->setEnabled(false);
+	button_change_area_ = new QPushButton(frame_labelbox_);
+	button_change_area_->setText(tr("Change area"));
+	button_change_area_->setEnabled(false);
+	button_change_area_text_ = new QPushButton(frame_labelbox_);
+	button_change_area_text_->setText(tr("Change area text"));
+	button_change_area_text_->setEnabled(false);
+
+	button_add_image_ = new QPushButton(frame_toolbox_);
+	button_add_image_->setText(tr("Add"));
+	button_remove_image_ = new QPushButton(frame_toolbox_);
+	button_remove_image_->setText(tr("Remove"));
+	button_remove_image_->setEnabled(false);
+
 	button_prev_image_ = new QPushButton(central_widget_);
 	button_prev_image_->setText("←");
 	button_next_image_ = new QPushButton(central_widget_);
@@ -316,6 +343,7 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	layout_main_ = new QHBoxLayout(central_widget_);
 	layout_left_ = new QVBoxLayout();
 	layout_toolbox_ = new QVBoxLayout();
+	layout_imagelist_buttons_ = new QHBoxLayout();
 	layout_center_ = new QVBoxLayout();
 	layout_frame_image_ = new QVBoxLayout();
 	layout_image_widget_ = new QGridLayout();
@@ -323,6 +351,7 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	layout_right_ = new QVBoxLayout();
 	layout_labelbox_ = new QVBoxLayout();
 	layout_labelbox_buttons_ = new QHBoxLayout();
+	layout_areabox_buttons_ = new QVBoxLayout();
 
 	layout_main_->addLayout(layout_left_);
 	layout_main_->addLayout(layout_center_);
@@ -348,6 +377,11 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	/* stretch is for making toolbox as small as it can be */
 	layout_toolbox_->addSpacing(10);
 	layout_left_->addWidget(label_list_images_);
+
+	layout_left_->addLayout(layout_imagelist_buttons_);
+	layout_imagelist_buttons_->addWidget(button_add_image_);
+	layout_imagelist_buttons_->addWidget(button_remove_image_);
+
 	layout_left_->addWidget(list_images_widget_);
 	list_images_widget_->setFixedWidth(200);
 	layout_left_->addStretch(1);
@@ -370,12 +404,21 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	frame_labelbox_->setFixedWidth(200);
 	frame_labelbox_->setLayout(layout_labelbox_);
 
+	layout_labelbox_->addWidget(label_list_label_);
+
 	layout_labelbox_->addLayout(layout_labelbox_buttons_);
 	layout_labelbox_buttons_->addWidget(button_add_label_);
 	layout_labelbox_buttons_->addWidget(button_remove_label_);
 
 	layout_labelbox_->addWidget(list_label_);
 	layout_labelbox_->addWidget(label_list_areas_);
+
+	layout_labelbox_->addLayout(layout_areabox_buttons_);
+	layout_areabox_buttons_->addWidget(button_delete_area_);
+	layout_areabox_buttons_->addWidget(button_change_area_);
+	layout_areabox_buttons_->addWidget(button_change_area_text_);
+	layout_areabox_buttons_->setSpacing(0);
+
 	layout_labelbox_->addWidget(list_areas_);
 
 	connect(
@@ -462,6 +505,12 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 		image_holder_,
 		SLOT(redo())
 		);
+	connect(
+		action_tagging_tool_,
+		SIGNAL(triggered()),
+		&line_edit_form_,
+		SLOT(setTags())
+		);
 	connect(
 		action_add_description_,
 		SIGNAL(triggered()),
@@ -483,7 +532,26 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 	connect(
 		button_remove_label_,
 		SIGNAL(clicked()),
-		this, SLOT(removeLabel())
+		this,
+		SLOT(removeLabel())
+		);
+	connect(
+		button_delete_area_,
+		SIGNAL(clicked()),
+		this,
+		SLOT(deleteArea())
+		);
+	connect(
+		button_change_area_,
+		SIGNAL(clicked()),
+		this,
+		SLOT(focusOnArea())
+		);
+	connect(
+		button_change_area_text_,
+		SIGNAL(clicked()),
+		this,
+		SLOT(editArea())
 		);
 	connect(
 		button_next_image_,
@@ -533,6 +601,18 @@ ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
 		this,
 		SLOT(clearLabelList())
 		);
+	connect(
+		button_add_image_,
+		SIGNAL(clicked()),
+		this,
+		SLOT(loadImage())
+		);
+	connect(
+		button_remove_image_,
+		SIGNAL(clicked()),
+		this,
+		SLOT(removeImage())
+		);
 	connect(
 		button_confirm_selection_,
 		SIGNAL(clicked()),
@@ -691,6 +771,8 @@ ImageLabeler::~ImageLabeler()
 	delete action_about_;
 	delete action_help_content_;
 
+	delete menu_load_;
+	delete menu_save_;
 	delete menu_pascal_;
 	delete menu_file_;
 	delete menu_view_;
@@ -720,6 +802,9 @@ ImageLabeler::~ImageLabeler()
 	delete button_add_label_;
 	delete button_remove_label_;
 	delete button_bound_box_tool_;
+	delete button_delete_area_;
+	delete button_change_area_;
+	delete button_change_area_text_;
 	delete button_polygon_tool_;
 	delete button_tagging_tool_;
 	delete button_clear_selection_tool_;
@@ -730,6 +815,7 @@ ImageLabeler::~ImageLabeler()
 
 	delete button_confirm_selection_;
 
+	delete label_list_label_;
 	delete label_list_areas_;
 	delete label_toolbox_;
 	delete label_list_images_;
@@ -737,12 +823,14 @@ ImageLabeler::~ImageLabeler()
 	delete list_label_;
 	delete list_images_widget_;
 
+	delete layout_imagelist_buttons_;
 	delete layout_toolbox_;
 	delete layout_right_;
 	delete layout_center_buttons_;
 	delete layout_frame_image_;
 	delete layout_center_;
 	delete layout_labelbox_buttons_;
+	delete layout_areabox_buttons_;
 	delete layout_labelbox_;
 	delete layout_left_;
 	delete layout_main_;
@@ -845,6 +933,8 @@ ImageLabeler::addImage(Image *anImage)
 
 	list_images_widget_->addItem(newItem);
 	list_images_->append(*anImage);
+
+	button_remove_image_->setEnabled(true);
 }
 
 //! A slot member creating new label with default parameters
@@ -1009,13 +1099,8 @@ ImageLabeler::removeLabel()
 void
 ImageLabeler::removeLabel(int aLabelID)
 {
-	if (0 == list_label_->count()) {
-		return;
-		/* NOTREACHED */
-	}
-
 	/* we need to keep BACKGROUND category */
-	if (aLabelID < 1) {
+	if (0 == list_label_->count() || aLabelID < 1) {
 		return;
 		/* NOTREACHED */
 	}
@@ -1162,8 +1247,20 @@ ImageLabeler::editArea()
 	list_areas_->blockSignals(oldState);
 }
 
-//! \brief A slot member parsing a text of the changed item and tries to edit
-//! the corresponding area
+void
+ImageLabeler::focusOnArea()
+{
+	QListWidgetItem *current = list_areas_->currentItem();
+	if (!current || !list_areas_->count()) {
+		return;
+		/* NOTREACHED */
+	}
+
+	image_holder_->focusOnArea(current);
+}
+
+//! \brief A slot member parsing a text of the changed item
+//! and tries to edit the corresponding area
 /*!
  *  \see polyFromListItemText(QString *aString,int *oldID)
  *  \see BBoxFromListItemText(QString *aString,int *oldID)
@@ -1268,8 +1365,9 @@ ImageLabeler::onAreaEdit()
 void
 ImageLabeler::deleteArea()
 {
-	if (!deleteArea(list_areas_->currentItem()))
-		showWarning(tr("An error occurred while deleting the area"));
+	deleteArea(list_areas_->currentItem());
+	/*if (!deleteArea(list_areas_->currentItem()))
+		showWarning(tr("An error occurred while deleting the area"));*/
 }
 
 //! A slot member deleting certain area in the list_areas_ widget
@@ -1347,6 +1445,13 @@ ImageLabeler::deleteArea(QListWidgetItem *anItem)
 	image_holder_->update();
 
 	unsaved_data_ = 1;
+
+	if (!list_areas_->count()) {
+		button_delete_area_->setEnabled(false);
+		button_change_area_->setEnabled(false);
+		button_change_area_text_->setEnabled(false);
+	}
+
 	return true;
 }
 
@@ -1657,18 +1762,29 @@ ImageLabeler::saveAllInfo()
 
 	objectsToXml(&doc, &root);
 
-	setPureData();
-	QDomElement pureData = doc.createElement(tr("pure_data"));
+	/* image size */
 	QSize imageSize = image_->size();
-	QString pixelValues;
+	QString imageSizeString;
+	imageSizeString.append(QString("%1;%2").
+		arg(imageSize.width()).
+		arg(imageSize.height()));
+
+	QDomElement imageSizeElement = doc.createElement(tr("image_size"));
+	QDomText imageSizeText = doc.createTextNode(imageSizeString);
+	imageSizeElement.appendChild(imageSizeText);
+	root.appendChild(imageSizeElement);
 
+	/* pure data */
+	setPureData();
+	QString pixelValues;
 	for (int i = 0; i < imageSize.height(); i++) {
 		for (int j = 0; j < imageSize.width(); j++) {
-			pixelValues.append(QString("%1").arg(pure_data_[i][j]));
+			pixelValues.append(QString("%1;").arg(pure_data_[i][j]));
 		}
 		pixelValues.append("\n");
 	}
 
+	QDomElement pureData = doc.createElement(tr("pure_data"));
 	QDomText pureDataText = doc.createTextNode(pixelValues);
 	pureData.appendChild(pureDataText);
 	root.appendChild(pureData);
@@ -2019,6 +2135,10 @@ ImageLabeler::loadInfo(QString filename)
 				QDomNode subNode = element.firstChild();
 				QDomElement subElement;
 
+				button_delete_area_->setEnabled(false);
+				button_change_area_->setEnabled(false);
+				button_change_area_text_->setEnabled(false);
+
 				while(!subNode.isNull()) {
 					subElement = subNode.toElement();
 
@@ -2041,13 +2161,22 @@ ImageLabeler::loadInfo(QString filename)
 
 					string = subElement.text();
 
-					if (subElement.tagName() == "bbox") {
+					if (subElement.tagName() == "bbox")
 						addBBoxFromData(&string, &id);
-					}
-					if (subElement.tagName() == "poly") {
+					else if (subElement.tagName() == "poly")
 						addPolyFromData(&string, &id);
+					else {
+						qDebug() <<
+							"loadInfo: "
+							"poly id format is corrupted";
+						subNode = subNode.nextSibling();
+						continue;
 					}
 
+					button_delete_area_->setEnabled(true);
+					button_change_area_->setEnabled(true);
+					button_change_area_text_->setEnabled(true);
+
 					subNode = subNode.nextSibling();
 				}
 			}
@@ -3429,6 +3558,9 @@ ImageLabeler::confirmSelection()
 		break;
 	}
 	button_confirm_selection_->setEnabled(false);
+	button_delete_area_->setEnabled(true);
+	button_change_area_->setEnabled(true);
+	button_change_area_text_->setEnabled(true);
 
 	unsaved_data_ = 1;
 }
@@ -3522,6 +3654,7 @@ ImageLabeler::enableTools()
 	action_save_legend_->setEnabled(true);
 	action_bound_box_tool_->setEnabled(true);
 	action_polygon_tool_->setEnabled(true);
+	action_tagging_tool_->setEnabled(true);
 	action_add_description_->setEnabled(true);
 	action_undo_->setEnabled(true);
 	action_redo_->setEnabled(true);
@@ -3549,6 +3682,7 @@ ImageLabeler::disableTools()
 	action_save_legend_->setEnabled(false);
 	action_bound_box_tool_->setEnabled(false);
 	action_polygon_tool_->setEnabled(false);
+	action_tagging_tool_->setEnabled(false);
 	button_tagging_tool_->setEnabled(false);
 	action_add_description_->setEnabled(false);
 	action_undo_->setEnabled(false);
@@ -3838,8 +3972,8 @@ ImageLabeler::selectImage(QListWidgetItem *anItem)
 		/* NOTREACHED */
 	}
 	clearAllTool();
-	clearLabelList();
-	clearLabelColorList();
+	//clearLabelList();
+	//clearLabelColorList();
 
 	image_ID_ = list_images_widget_->row(anItem);
 
@@ -3865,10 +3999,13 @@ ImageLabeler::selectImage(int anImageID)
 		/* NOTREACHED */
 	}
 
+	action_view_segmented_->setEnabled(false);
+
 	/* checking if it was labeled before */
 	if (list_images_->at(anImageID).labeled_ &&
 		!list_images_->at(anImageID).pas_)
 	{
+		list_label_colors_.clear();
 		list_label_->clear();
 		QString labeled =
 			alterFileName(list_images_->at(anImageID).image_, "_labeled");
@@ -3904,7 +4041,16 @@ ImageLabeler::selectImage(int anImageID)
 void
 ImageLabeler::removeImage()
 {
+	int imageCount = list_images_widget_->count();
 	int num = list_images_widget_->currentRow();
+
+	if (!imageCount || num < 0 || imageCount <= num ||
+		list_images_->count() != imageCount)
+	{
+		return;
+		/* NOTREACHED */
+	}
+
 	list_images_widget_->takeItem(num);
 	list_images_->takeAt(num);
 
@@ -3913,6 +4059,9 @@ ImageLabeler::removeImage()
 		newStr.prepend(QString("%1: ").arg(i));
 		list_images_widget_->item(i)->setText(newStr);
 	}
+
+	if (1 == imageCount)
+		button_remove_image_->setEnabled(false);
 }
 
 //! A protected member which is being automatically called on every image resize
@@ -3992,6 +4141,26 @@ ImageLabeler::keyPressEvent(QKeyEvent *anEvent)
 		image_holder_->redo();
 	}
 
+	if (Qt::Key_Delete == anEvent->key() &&
+		list_areas_->hasFocus()) {
+		deleteArea();
+	}
+
+	if (Qt::Key_Delete == anEvent->key() &&
+		list_label_->hasFocus()) {
+		removeLabel();
+	}
+
+	if (Qt::Key_Delete == anEvent->key() &&
+		list_images_widget_->hasFocus()) {
+		removeImage();
+	}
+
+	if (Qt::Key_Delete == anEvent->key() &&
+		image_holder_->hasFocus()) {
+		image_holder_->removeSelectedPoint();
+	}
+
 	QWidget::keyPressEvent(anEvent);
 }
 
@@ -4033,6 +4202,8 @@ ImageLabeler::closeEvent(QCloseEvent *anEvent)
 {
 	Q_UNUSED(anEvent)
 	writeSettings();
+
+	askForUnsavedData();
 }
 
 /*

+ 37 - 2
ImageLabeler.h

@@ -136,6 +136,7 @@ public slots:
 	void setLabelID(QListWidgetItem *anItem);
 	void toggleLabelPriority();
 
+	void focusOnArea();
 	void editArea();
 	void deleteArea();
 
@@ -176,14 +177,23 @@ public slots:
 	void readSettings();
 
 private:
-	/* menu */
+	/*
+	 *  menu
+	 */
+
 	//! main menu bar contains all other menus
 	QMenuBar *menu_bar_;
 
-	//! \brief contains all actions connected with file loading and saving files.
+	//! \brief contains all actions connected with file loading and saving.
 	//! also contains menu_pascal_
 	QMenu *menu_file_;
 
+	//! \brief contains all actions connected with file saving.
+	QMenu *menu_save_;
+
+	//! \brief contains all actions connected with file saving.
+	QMenu *menu_load_;
+
 	//! contains actions for loading PASCAL xml file and PASCAL polygon
 	QMenu *menu_pascal_;
 
@@ -310,6 +320,7 @@ private:
 	QHBoxLayout *layout_main_;
 	QVBoxLayout *layout_left_;
 	QVBoxLayout *layout_toolbox_;
+	QHBoxLayout *layout_imagelist_buttons_;
 	QVBoxLayout *layout_center_;
 	QVBoxLayout *layout_frame_image_;
 	QGridLayout *layout_image_widget_;
@@ -317,6 +328,7 @@ private:
 	QVBoxLayout *layout_right_;
 	QVBoxLayout *layout_labelbox_;
 	QHBoxLayout *layout_labelbox_buttons_;
+	QVBoxLayout *layout_areabox_buttons_;
 
 	/* widgets */
 	//!	parent for all widgets
@@ -345,6 +357,9 @@ private:
 	//! just an information label
 	QLabel *label_toolbox_;
 
+	//! just an information label
+	QLabel *label_list_label_;
+
 	//! just an information label
 	QLabel *label_list_areas_;
 
@@ -404,6 +419,26 @@ private:
 	//! \see removeLabel()
 	QPushButton *button_remove_label_;
 
+	//! \brief button deleting current area
+	//! \see deleteArea()
+	QPushButton *button_delete_area_;
+
+	//! \brief button allowing area text changing
+	//! \see editArea()
+	QPushButton *button_change_area_text_;
+
+	//! \brief button allowing area modifying
+	//! \see focusOnArea()
+	QPushButton *button_change_area_;
+
+	//! \brief button removing current image
+	//! \see loadImage()
+	QPushButton *button_add_image_;
+
+	//! \brief button removing current image
+	//! \see removeImage()
+	QPushButton *button_remove_image_;
+
 	//! \brief button switching to the next image
 	//! \see nextImage()
 	QPushButton *button_prev_image_;

+ 2 - 1
ImageLabeler.pro

@@ -2,7 +2,8 @@ TEMPLATE = app
 TARGET = ImageLabeler
 QT += core \
     gui \
-    xml
+    xml \
+    webkit
 HEADERS += LineEditForm.h \
     OptionsForm.h \
     functions.h \

+ 3 - 1
Makefile

@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building: ImageLabeler
-# Generated by qmake (2.01a) (Qt 4.7.1) on: Thu Oct 20 15:46:56 2011
+# Generated by qmake (2.01a) (Qt 4.7.1) on: Mon Oct 24 16:50:05 2011
 # Project:  ImageLabeler.pro
 # Template: app
 # Command: /usr/bin/qmake CONFIG+=debug_and_release -o Makefile ImageLabeler.pro
@@ -85,6 +85,7 @@ Makefile: ImageLabeler.pro  /usr/share/qt4/mkspecs/default/qmake.conf /usr/share
 		/usr/share/qt4/mkspecs/features/yacc.prf \
 		/usr/share/qt4/mkspecs/features/lex.prf \
 		/usr/share/qt4/mkspecs/features/include_source_dir.prf \
+		/usr/lib64/libQtWebKit.prl \
 		/usr/lib64/libQtXml.prl \
 		/usr/lib64/libQtCore.prl \
 		/usr/lib64/libQtGui.prl
@@ -111,6 +112,7 @@ Makefile: ImageLabeler.pro  /usr/share/qt4/mkspecs/default/qmake.conf /usr/share
 /usr/share/qt4/mkspecs/features/yacc.prf:
 /usr/share/qt4/mkspecs/features/lex.prf:
 /usr/share/qt4/mkspecs/features/include_source_dir.prf:
+/usr/lib64/libQtWebKit.prl:
 /usr/lib64/libQtXml.prl:
 /usr/lib64/libQtCore.prl:
 /usr/lib64/libQtGui.prl:

+ 4 - 4
Makefile.Debug

@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building: ImageLabeler
-# Generated by qmake (2.01a) (Qt 4.7.1) on: Thu Oct 20 15:46:55 2011
+# Generated by qmake (2.01a) (Qt 4.7.1) on: Mon Oct 24 16:50:05 2011
 # Project:  ImageLabeler.pro
 # Template: app
 #############################################################################
@@ -9,13 +9,13 @@
 
 CC            = gcc
 CXX           = g++
-DEFINES       = -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+DEFINES       = -DQT_WEBKIT_LIB -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
 CFLAGS        = -m64 -pipe -g -Wall -W -D_REENTRANT $(DEFINES)
 CXXFLAGS      = -m64 -pipe -g -Wall -W -D_REENTRANT $(DEFINES)
-INCPATH       = -I/usr/share/qt4/mkspecs/default -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtXml -I/usr/include -Idebug
+INCPATH       = -I/usr/share/qt4/mkspecs/default -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtXml -I/usr/include/QtWebKit -I/usr/include -Idebug
 LINK          = g++
 LFLAGS        = -m64
-LIBS          = $(SUBLIBS)  -L/usr/lib64 -lQtXml -L/usr/lib64 -lQtGui -L/usr/X11R6/lib64 -lQtCore -lpthread 
+LIBS          = $(SUBLIBS)  -L/usr/lib64 -lQtWebKit -lQtXml -L/usr/lib64 -lQtGui -L/usr/X11R6/lib64 -lQtCore -lpthread 
 AR            = ar cqs
 RANLIB        = 
 QMAKE         = /usr/bin/qmake

+ 4 - 4
Makefile.Release

@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building: ImageLabeler
-# Generated by qmake (2.01a) (Qt 4.7.1) on: Thu Oct 20 15:46:55 2011
+# Generated by qmake (2.01a) (Qt 4.7.1) on: Mon Oct 24 16:50:05 2011
 # Project:  ImageLabeler.pro
 # Template: app
 #############################################################################
@@ -9,13 +9,13 @@
 
 CC            = gcc
 CXX           = g++
-DEFINES       = -DQT_NO_DEBUG -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+DEFINES       = -DQT_NO_DEBUG -DQT_WEBKIT_LIB -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
 CFLAGS        = -m64 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
 CXXFLAGS      = -m64 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
-INCPATH       = -I/usr/share/qt4/mkspecs/default -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtXml -I/usr/include -Irelease
+INCPATH       = -I/usr/share/qt4/mkspecs/default -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtXml -I/usr/include/QtWebKit -I/usr/include -Irelease
 LINK          = g++
 LFLAGS        = -m64 -Wl,-O1
-LIBS          = $(SUBLIBS)  -L/usr/lib64 -lQtXml -L/usr/lib64 -lQtGui -L/usr/X11R6/lib64 -lQtCore -lpthread 
+LIBS          = $(SUBLIBS)  -L/usr/lib64 -lQtWebKit -lQtXml -L/usr/lib64 -lQtGui -L/usr/X11R6/lib64 -lQtCore -lpthread 
 AR            = ar cqs
 RANLIB        = 
 QMAKE         = /usr/bin/qmake

+ 61 - 0
functions.cpp

@@ -12,6 +12,9 @@
 #include <QDomDocument>
 #include <QDomNode>
 #include <QDomText>
+#include <QPoint>
+#include <QLine>
+#include <qmath.h>
 #include <QDebug>
 
 //! Gets number from a string which is located between aFirstStr and aSecondStr
@@ -128,6 +131,64 @@ getPathFromFilename(const QString &aFilename)
 	return path;
 }
 
+//! Calculates coefficients a,b,c (ax + by + c = 0) for the straight line
+/*!
+ * \see ImageHolder::posInPolygon(QPoint *aPos,QPolygon *aPoly)
+ * \param[in] p1 first point defining the line
+ * \param[in] p2 second point defining the line
+ * \param[out] a pointer to the coefficient
+ * \param[out] b pointer to the coefficient
+ * \param[out] c pointer to the coefficient
+ */
+void
+calcLineCoeff(
+	const QPoint &p1,
+	const QPoint &p2,
+	int *a,
+	int *b,
+	int *c
+)
+{
+	*a = p1.y() - p2.y();
+	*b = p2.x() - p1.x();
+	*c = (p1.x() * p2.y()) - (p2.x() * p1.y());
+}
+
+//! Returns the distance between point and a line
+/*!
+ * \see calcLineCoeff(
+	const QPoint &p1,
+	const QPoint &p2,
+	int *a,
+	int *b,
+	int *c
+	)
+	\see ImageHolder::posInPolygon(QPoint *aPos,QPolygon *aPoly)
+ * \param[in] aLine line
+ * \param[in] aPoint point
+ */
+int
+pointToLineDistance(
+	const QLine &aLine,
+	const QPoint &aPoint
+)
+{
+	int a, b, c;
+	int distance = 0;
+
+	calcLineCoeff(
+		aLine.p1(),
+		aLine.p2(),
+		&a,
+		&b,
+		&c
+		);
+
+	distance = qAbs((a * aPoint.x()) + (b * aPoint.y()) + c);
+
+	return distance;
+}
+
 /*
  *
  */

+ 13 - 0
functions.h

@@ -11,6 +11,8 @@
 class QString;
 class QChar;
 class QDomDocument;
+class QPoint;
+class QLine;
 
 QString getDirFromPath(
 	const QString *aPath
@@ -34,6 +36,17 @@ QString removePath(
 QString getPathFromFilename(
 	const QString &aFilename
 	);
+void calcLineCoeff(
+	const QPoint &p1,
+	const QPoint &p2,
+	int *a,
+	int *b,
+	int *c
+	);
+int pointToLineDistance(
+	const QLine &aLine,
+	const QPoint &aPoint
+	);
 
 #endif /* __FUNCTIONS_H__ */