• 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");

     

    /* LabelDialog(选择label的一个对话框)

    * 简介:

    * 界面:ui->lineEdit,LabelLineEdit 类型,绑定了 ui->listWidget(详见 LabelLineEdit 的声明)

    * ui->listWidget,用于显示label,且有一个纯色的icon代表label对应的颜色

    */

    /* 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
    												

  • 相关阅读:
    20200917-2 词频统计
    20200910-2 博客作业
    20200910-1 每周例行报告
    20200910-3命令行和控制台编程
    使用Requests库实现api接口测试(Python)
    Python Lambda函数的几种使用方法
    文本与向量之间的转换
    Oracle连接出现error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
    一图看懂新一代人工智能知识体系大全
    SqlDeveloper连接MySQL出现The connection property ‘zeroDateTimeBehavior’ acceptable values are: ‘CONVERT_TO_NULL’, ‘EXCEPTION’ or ‘ROUND’. The value ‘convertToNull’ is not acceptable 错误
  • 原文地址:https://www.cnblogs.com/tangyuanjie/p/14304607.html
Copyright © 2020-2023  润新知