天天看點

ImageLabeler-master(圖檔标注工具)

可以參考配套的文檔(作者的文檔)

技術要點:類的繼承,友元函數,自動補全,按鍵事件,listwidget,json資料解析,qlist,qmap,使用const宏定義,

類的繼承:class

CubeAnnotationItem

:

public

AnnotationItem

友元函數:friend

AnnotationContainer;

宏定義:

//

for

image

result

const

QString

SUFFIX_SEG_COLOR("_segment_color.png");

const

QString

SUFFIX_SEG_LABELID("_segment_labelId.png");

const

QString

SUFFIX_SEG3D_COLOR("_segment3d_color.png");

const

QString

SUFFIX_SEG3D_LABELID("_segment3d_labelId.png");

ImageLabeler-master(圖檔标注工具)
ImageLabeler-master(圖檔标注工具)

/*

LabelDialog(選擇label的一個對話框)

*

簡介:

*

界面:ui->lineEdit,LabelLineEdit

類型,綁定了

ui->listWidget(詳見

LabelLineEdit

的聲明)

*

ui->listWidget,用于顯示label,且有一個純色的icon代表label對應的顔色

*/

ImageLabeler-master(圖檔标注工具)

/*

LabelLineEdit (自動補全,綁定QlistWidget,按鍵上下選中)

*
							簡介:用作LabelDialog的一個部件,可綁定一個QListWidget實作一些關聯的效果
						           
*
							功能:a.
									輸入時根據
											labelListWidget
													的
															items
																	的
																			text
																					提供自動補全
																				           
*
							b.
									當
											labelListWidget
													的選中項改變時,相應的改變輸入框中的text
												           
*
							c.
									按下
											up和down
													鍵,可改變
															labelListWidget
																	的選中項。
																           
*/
				           

class

LabelLineEdit:

public

QLineEdit{

friend

LabelDialog;

public:

//

labelListWidget

構造時預設為

nullptr

explicit

LabelLineEdit(QWidget

*parent =

nullptr);

//

設定

labelListWidget,并實作功能

a

b

(自動補全

相應list的選中)

void

setLabelListWidget(QListWidget*

listWidget);

protected:

//

處理

up

down

鍵的按下事件,實作功能

c

(改變list的選中項)

void

keyPressEvent(QKeyEvent

*event);

private:

QListWidget*

labelListWidget;

};

LabelLineEdit::LabelLineEdit(QWidget

*parent):QLineEdit(parent),

labelListWidget(nullptr)

{

}

void

LabelLineEdit::setLabelListWidget(QListWidget

*listWidget){

labelListWidget

=

listWidget;

//

功能

a:

輸入時根據

labelListWidget

items

text

提供自動補全

QCompleter*

completer

=

new

QCompleter(this);

completer->setCompletionMode(QCompleter::InlineCompletion);

completer->setModel(labelListWidget->model());

this->setCompleter(completer);

//

功能

b:

labelListWidget

的選中項改變時,相應的改變輸入框中的text

connect(labelListWidget,

&QListWidget::currentItemChanged,

[this](QListWidgetItem

*currentItem){

this->setText(currentItem->text());

});

}

void

LabelLineEdit::keyPressEvent(QKeyEvent

*event){

//

功能

c:

按下

up和down

鍵,可改變

labelListWidget

的選中項

if

(event->key()

==

Qt::Key_Up){

if

(labelListWidget!=nullptr

&&

labelListWidget->count()>0){

int

newRow

=

std::max(0,

std::min(labelListWidget->currentRow()

-

1,

labelListWidget->count()-1));

labelListWidget->setCurrentRow(newRow);

this->setText(labelListWidget->currentItem()->text());

}

}else

if

(event->key()

==

Qt::Key_Down){

if

(labelListWidget!=nullptr

&&

labelListWidget->count()>0){

int

newRow

=

std::max(0,

std::min(labelListWidget->currentRow()

+

1,

labelListWidget->count()-1));

labelListWidget->setCurrentRow(newRow);

this->setText(labelListWidget->currentItem()->text());

}

}else{

QLineEdit::keyPressEvent(event);

}

}

/*

LabelManager -LabelProperty(json格式存儲label資料,解析json資料)

*

簡介:用來存儲label的相關性質的資料類型,存儲了label、color、visible、id

*

Json:該類的資料與json互相轉化時的格式為

*

{

*

"color":

[

*

Double,

//

R

*

Double,

//

G

*

Double

//

B

*

],

*

"id":

Double,

*

"label":

String,

*

"visible":

Bool

*

}

//---------------------------------LabelProperty-------------------------------------//

LabelProperty::LabelProperty(QString

label,

QColor

color,

bool

visible,

int

id)

:

label(label),

color(color),

visible(visible),id(id)

{

}

LabelProperty::LabelProperty():label(),

color(),

visible(true),

id(-1)

{

}

QJsonObject

LabelProperty::toJsonObject(){

QJsonArray

colorJson;

colorJson.append(color.red());

colorJson.append(color.green());

colorJson.append(color.blue());

QJsonObject

json;

json.insert("label",

label);

json.insert("id",

id);

json.insert("color",

colorJson);

json.insert("visible",

visible);

return

json;

}

void

LabelProperty::fromJsonObject(QJsonObject

json)

{

if

(json.contains("label")){

QJsonValue

value

=

json.value("label");

if

(value.isString()){

label

=

value.toString();

}else{

throw

JsonException("value

of

<label>

is

illegal");

}

}else{

throw

JsonException("no

data

<label>");

}

if

(json.contains("color")){

QJsonValue

value

=

json.value("color");

if

(value.isArray()){

QJsonArray

array

=

value.toArray();

if

(!array.at(0).isDouble()

||

!array.at(1).isDouble()

||

!array.at(2).isDouble()){

throw

JsonException("value

of

<color>

is

illegal");

}

int

r=static_cast<int>(array.at(0).toDouble());

int

g=static_cast<int>(array.at(1).toDouble());

int

b=static_cast<int>(array.at(2).toDouble());

color

=

QColor(r,g,b);

}else{

throw

JsonException("value

of

<color>

is

illegal");

}

}else{

throw

JsonException("no

data

<color>");

}

if

(json.contains("visible")){

QJsonValue

value

=

json.value("visible");

if

(value.isBool()){

visible

=

value.toBool();

}else{

throw

JsonException("value

of

<visible>

is

illegal");

}

}else{

throw

JsonException("no

data

<visible>");

}

if

(json.contains("id")){

QJsonValue

value

=

json.value("id");

if

(value.isDouble()){

id

=

static_cast<int>(value.toDouble());

}else{

throw

JsonException("value

of

<id>

is

illegal");

}

}else{

throw

JsonException("no

data

<id>");

}

}

/*

LabelManager(增加删除修改查詢label,)

*

簡介:管理label相關的資料的類,主要與ui->labelListWidget同步

*

注意:在addLabel前應檢查是否已經存在該label

*

*

Json:該類的資料與json互相轉化時的格式為

*

[

LabelProperty,

LabelProperty,

...

]

//

Array中的元素的格式為LabelProperty的格式

*/

使用map存儲labels;

QMap<QString,

LabelProperty>

labels;

/*

CustomListWidget

*

簡介:作為MainWindow中的部件,根據所需提供了更友善的函數接口以及事件響應

*

是MainWindow中

annoListWidget、labelListWidget、fileListWidget的類型

*

界面:每個

item

從左至右組成為:一個用于check的小框(可有可無),一個icon(可有可無),以及text

*

事件:滑鼠若點選到listwidget空白區域,即沒有item的區域,則清除list的所有選中狀态

*

鍵盤按下

up/down

鍵改變list的選中項

*

注意:a.

該類應為單選模式(SingleSelection),且不應該被更改;

*

b.

該類不應出現不同的item的text相同的情況,

*

這種情況在該項目中是不會發生的,因為:

*

1.

annoList中每個label相同的标注被一個各不相同的instance

id辨別

*

2.

fileList中不會出現檔案重名的情況

*

3.

labelList在加入item時會根據labelManager檢查label是否已經存在

*/

Listwidget中的右鍵菜單

void

MainWindow::provideLabelContextMenu(const

QPoint

&pos)

{

QPoint

globalPos

=

ui->labelListWidget->mapToGlobal(pos);

QModelIndex

modelIdx

=

ui->labelListWidget->indexAt(pos);

if

(!modelIdx.isValid())

return;

int

row

=

modelIdx.row();

auto

item

=

ui->labelListWidget->item(row);

QMenu

submenu;

submenu.addAction("Change

Color");

submenu.addAction("Delete");

QAction*

rightClickItem

=

submenu.exec(globalPos);

if

(rightClickItem){

if

(rightClickItem->text().contains("Delete")){

removeLabelRequest(item->text());

}else

if

(rightClickItem->text().contains("Change

Color")){

QColor

color

=

QColorDialog::getColor(Qt::white,

this,

"Choose

Color");

if

(color.isValid()){

labelManager.setColor(item->text(),color);

}

}

}

}

/*

FileManager(靜态函數友善調用,)

*

簡介:管理與檔案相關的狀态的類型

*

功能:a.

實作靜态函數作為更便捷的處理檔案名、讀寫檔案的接口

*

b.

打開檔案或檔案夾,生成預設的輸出檔案名(包括label和annotation的輸出檔案)

*

c.

記錄距離上次儲存後是否有未儲存的修改

*

d.

可選中檔案,切換顯示的圖像,并與

ui->fileListWidget

同步

*/

/*

RectAnnotationItem(繪制矩形,标記用json格式存儲)

*

簡介:用于2D

Detection的标注類型,比父類多記錄了一個像素坐标的矩形

rect

表示bounding

box

*

*

Json:該類的資料與json互相轉化時的格式如下,points表示兩個矩形的左上和右下頂點

*

{

*

"label":

String

*

"id":

Double

*

"points":

[

*

[

*

Double,

*

Double

*

],

*

[

*

Double,

*

Double

*

]

*

]

*

}

*/

/*

SegStroke(繪制多邊形)

*

簡介:用于表示2D分割标注中一

"筆畫"

的資料類型

*

筆畫:筆畫共分為三種,分别為圓形畫筆、方形畫筆、輪廓

*

對應的type的值分别為

"circle_pen"

"square_pen"

"contour"

*

當type為畫筆時,points中記錄的是畫筆中心經過路徑,penWidth記錄畫筆的大小;

*

當type為輪廓時,points依次記錄輪廓上的點,并用多邊形連接配接它們,特别地,當點比較稠密時,可視為光滑閉合曲線

*

當type為輪廓時,penWidth無意義,一般記為1,也可不記

*

*

Json:該類的資料與json互相轉化時的格式如下,

*

{

*

"type":

String

//

取值為

"circle_pen"

"square_pen"

"contour"

*

"penWidth":

Double

*

"points":

[

[Double,

Double],

[Double,

Double],

...

]

//Array類型,表示xy坐标

*

}

*/

/*

Basic_SegAnnotationItem

*

簡介:用于表示Segmentation标注的類模闆,該項目中認為一個分割标注可由多個筆畫(stroke_type類型)合并組成

*

對應2D和3D分割标注,stroke_type分别為SegStroke和SegStroke3D

*

*

Json:該類的資料與json互相轉化時的格式如下

*

{

*

"label":

String

*

"id":

Double

*

"strokes":

[

stroke_type,

stroke_type,

...

]

//

Array的元素的格式為SegStroke或SegStroke3D對應的格式

*

}

*/

Common(一些基本的功能,多個命名空間)

#ifndef
										COMMON_H
           
#define
											COMMON_H
										           
#include
											"canvasbase.h"
										           
#include
											"cubeannotationitem.h"
										           
#include
											<QList>
										           
#include
											<QColor>
										           
#include
											<QRect>
										           
#include
											<QPoint>
										           
#include
											<QString>
										           
#include
											<cmath>
										           
#include
											<map>
										           
namespace
											ColorUtils{
											           
extern
												QList<QColor>
																	randomColors(int
																			count);
																		           
extern
												QColor
														randomColor();
													           
extern
												QIcon
														iconFromColor(QColor
																color,
																		QSize
																			size
																				=
																						QSize(16,16));
																										           
}
								           
namespace
											CanvasUtils
													{
												           
const
												int
													DEFAULT_PEN_WIDTH=15;
														           
const
												int
													LABEL_PIXEL_SIZE
														=
																15;
																           
const
												int
													pixEps=5;
														           
enum
												EditingRectEdge{
												           
TOP,
													BOTTOM,
																LEFT,
																			RIGHT
																		           
};
									           
extern
												bool
														onRectTop(QPoint
																pos,
																		QRect
																			rect);
																		           
extern
												bool
														onRectBottom(QPoint
																pos,
																		QRect
																			rect);
																		           
extern
												bool
														onRectLeft(QPoint
																pos,
																		QRect
																			rect);
																		           
extern
												bool
														onRectRight(QPoint
																pos,
																		QRect
																			rect);
																		           
//
												z:
														min
																->
																		max
																				<=>
																						top
																								->
																										bottom
																									           
//
												x:
														min
																->
																		max
																				<=>
																						left
																								->
																										right
																									           
//
												y:
														min
																->
																		max
																				<=>
																						back
																								->
																										front
																									           
enum
												EditingCubeFace{
												           
TOPf,
													BOTTOMf,
																LEFTf,
																			RIGHTf,
																						FRONTf,
																									BACKf
																								           
};
									           
extern
												bool
														onCubeTop(Point3D
																pos,
																		Cuboid
																			cube);
																		           
extern
												bool
														onCubeBottom(Point3D
																pos,
																		Cuboid
																			cube);
																		           
extern
												bool
														onCubeLeft(Point3D
																pos,
																		Cuboid
																			cube);
																		           
extern
												bool
														onCubeRight(Point3D
																pos,
																		Cuboid
																			cube);
																		           
extern
												bool
														onCubeFront(Point3D
																pos,
																		Cuboid
																			cube);
																		           
extern
												bool
														onCubeBack(Point3D
																pos,
																		Cuboid
																			cube);
																		           
}
								           
namespace
											StringConstants{
											           
const
												std::map<TaskMode,QString>
																				taskText
																					={{DETECTION,
																									"Detection
																											"},
																											           
{SEGMENTATION,
														"Segmentation
																"},
																           
{DETECTION3D,
														"3D
																Detection
																		"},
																		           
{SEGMENTATION3D,
														"3D
																Segmentation
																		"}};
																		           
const
												std::map<DrawMode,QString>
																				drawModeText={{RECTANGLE,
																							"Rectangle
																									"},
																									           
{CIRCLEPEN,
														"Circle
																Pen
																		"},
																		           
{SQUAREPEN,
														"Square
																Pen
																		"},
																		           
{CONTOUR,
														"Contour
																"},
																           
{POLYGEN,
														"Polygonal
																Contour
																		"}};
																		           
extern
												inline
														bool
																is2dTask(const
																			QString
																					&text)
																							{
																						           
return
												text
														==
															taskText.at(DETECTION)
																		||
																				text
																						==
																							taskText.at(SEGMENTATION);
																							           
}
									           
extern
												inline
														bool
																is3dTask(const
																			QString
																					&text)
																							{
																						           
return
												text
														==
															taskText.at(DETECTION3D)
																		||
																				text
																						==
																							taskText.at(SEGMENTATION3D);
																							           
}
									           
extern
												inline
														bool
																isDetectTask(const
																			QString
																					&text)
																							{
																						           
return
												text
														==
															taskText.at(DETECTION)
																		||
																				text
																						==
																							taskText.at(DETECTION3D);
																							           
}
									           
extern
												inline
														bool
																isSegmentTask(const
																			QString
																					&text)
																							{
																						           
return
												text
														==
															taskText.at(SEGMENTATION)
																		||
																				text
																						==
																							taskText.at(SEGMENTATION3D);
																							           
}
									           
extern
												DrawMode
														getDrawModeFromText(const
																	QString
																			&text);
																		           
extern
												TaskMode
														getTaskFromText(const
																	QString
																			&text);
																		           
//
												for
														single
																image
															           
const
												QString
													SUFFIX_DET_LABEL_ANNO("_detect_labels_annotations.json");
														           
const
												QString
													SUFFIX_SEG_LABEL_ANNO("_segment_labels_annotations.json");
														           
//
												for
														multiple
																image
															           
const
												QString
													FILENAME_DIR_LABEL("labels.json");
														           
const
												QString
													SUFFIX_DET_ANNO("_detect_annotations.json");
														           
const
												QString
													SUFFIX_SEG_ANNO("_segment_annotations.json");
													           
//
												for
														3d
																image
															           
const
												QString
													FILENAME_DET3D_LABEL_ANNO("detect3d_labels_annotations.json");
														           
const
												QString
													FILENAME_SEG3D_LABEL_ANNO("segment3d_labels_annotations.json");
														           
//
												for
														image
																result
															           
const
												QString
													SUFFIX_SEG_COLOR("_segment_color.png");
														           
const
												QString
													SUFFIX_SEG_LABELID("_segment_labelId.png");
														           
const
												QString
													SUFFIX_SEG3D_COLOR("_segment3d_color.png");
														           
const
												QString
													SUFFIX_SEG3D_LABELID("_segment3d_labelId.png");
														           
}
								           
#endif
											//
													COMMON_H