浏览代码

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

gapchich 13 年之前
父节点
当前提交
f479ec68e9
共有 10 个文件被更改,包括 468 次插入57 次删除
  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__ */