目录
?
功能:CentralWidget 负责主窗口中心组件的界面初始化以及后续中心组件的管理。
其两个派生类分别负责2D、3D中心组件,2d和3d的模式可以进行切换。
子类CentralWInit2D方法都是实现父类方法。CentralWInit3D有一些自己的方法。
都是虚函数。
#ifndef CENTRALWIDGET_H
#define CENTRALWIDGET_H
#include<QMainWindow>
#include<QWidget>
#include<QListWidgetItem>
#include"Namespace.h"
/// \brief 中心组件基类
class My::CentralWidget:public QWidget{
Q_OBJECT
public:
signals:
/// \brief 标注选中状态改变信号
void selectedChanged(int index,bool b);
/// \brief 标注删除信号
void labelDeleted(int index);
/// \brief 标注解析完毕信号
void labelsFinished(QList<My::Shape*>& shapes);
/// \brief 标注添加信号
void labelAdded(My::Shape* shape,int index);
/// \brief 标注改变信号
void labelChanged(int index,My::Shape* shape);
public:
CentralWidget(QWidget* parent):QWidget(parent){}
/// \brief 用来初始化中心组件
virtual void setUp(QMainWindow* w);
/// \brief 解析文件(显示图片,解析标注形状)
virtual void parse(const QString& fileName,const QString& labelfileName);//解析标注文件
/// \brief 改变标注的状态,槽函数
virtual void changeShapeLabel(QListWidgetItem* item);
/// \brief 改变标注的选中状态、槽函数
virtual void changeSelected();
/// \brief 创建标注形状
virtual void createShape(My::shapeStatus s);
/// \brief 处理按键事件
virtual void keyPressHandle(int k);
/// \brief 编辑标注
virtual void editLabel();
/// \brief 删除标注
virtual void deleteLabel();
/// \brief 编辑画刷大小,画刷是用来进行分割标注
virtual void editBrush();
/// \brief 编辑标注形状的颜色
virtual void editColor();
/// \brief 放大功能
virtual void zoomIn();
/// \brief 缩小功能
virtual void zoomOut();
/// \brief 使中心组件宽度适应主窗口
virtual void fitWindow();
/// \brief 恢复图片原始大小
virtual void originalSize();
/// \brief 放大镜功能
virtual void magnifier(bool b);
/// \brief 保存文件功能
virtual void save(const QString& fileName);
/// \brief 隐藏标注
virtual void hidePolygons();
/// \brief 显示标注
virtual void showPolygons();
/// \brief 关闭文件功能
virtual void closeFile();
virtual ~CentralWidget()=0;
};
#endif // CENTRALWIDGET_H
该子类就是实现父类方法。
#ifndef CENTRALWINIT2D_H
#define CENTRALWINIT2D_H
#include<QScrollArea>
#include<QListWidgetItem>
#include"Shape2D.h"
#include"CentralWidget.h"
/// \brief 2d中心组件,继承CentralWidget
///
/// 内部的绘画以及标注相关的动作交由Label类
/// 命令的撤销和重做交由Command2D类
/// 标注文件的解析和存储交由Parse类进行处理
class CentralWInit2D:public My::CentralWidget{
Q_OBJECT
private:
/// \brief 2d中心组件滚动区域
QScrollArea* sarea;
public:
/// \brief 命令栈用来存放所用到的所有标注形状
QList<My::Shape2D*> trashshapes;
/// \brief 中心绘制组件,用来展示图片、绘制标注
My::Label* label;
/// \brief 命令栈组件,用来实现撤销、重做命令
My::Command2D* command;
/// \brief 构造函数
CentralWInit2D(QWidget* parent);
/// \brief 用来初始化中心组件
virtual void setUp(QMainWindow* w);
/// \brief 解析文件(显示图片,解析标注形状)
virtual void parse(const QString& fileName,const QString& labelfileName);/// \brief 解析标注文件
/// \brief 改变标注的状态,槽函数
virtual void changeShapeLabel(QListWidgetItem* item);
/// \brief 改变标注的选中状态、槽函数
virtual void changeSelected();
/// \brief 创建标注形状
virtual void createShape(My::shapeStatus s);
/// \brief 处理按键事件
virtual void keyPressHandle(int k);
/// \brief 编辑标注
virtual void editLabel();
/// \brief 删除标注
virtual void deleteLabel();
/// \brief 编辑画刷大小,画刷是用来进行分割标注
virtual void editBrush();
/// \brief 编辑标注形状的颜色
virtual void editColor();
/// \brief 放大功能
virtual void zoomIn();
/// \brief 缩小功能
virtual void zoomOut();
/// \brief 使中心组件宽度适应主窗口
virtual void fitWindow();
/// \brief 恢复图片原始大小
virtual void originalSize();
/// \brief 放大镜功能
virtual void magnifier(bool b);
/// \brief 保存文件功能
virtual void save(const QString& fileName);
/// \brief 隐藏标注
virtual void hidePolygons();
/// \brief 显示标注
virtual void showPolygons();
/// \brief 关闭当前文件
void closeFile();
~CentralWInit2D();
};
#endif // CENTRALWINIT_H
新建command, sarea, label三个对象?;三者关系
/// \brief 2d中心组件构造函数
CentralWInit2D::CentralWInit2D(QWidget* w):My::CentralWidget (w){
//初始化command
command=new My::Command2D();
command->manager=this;
//初始化中心滚动区域
sarea=new QScrollArea();
//初始化label
label=new My::Label(sarea);
label->manager=this;
}
/// \brief 2d中心组件初始化函数
void CentralWInit2D::setUp(QMainWindow *w){
w->setCentralWidget(sarea); // 将中心滚动区域 设置为主窗口 w 的中心组件。
sarea->setWidget(label); // 将标签(label)设置为滚动区域(sarea)的组件。
sarea->setAlignment(Qt::AlignCenter);
}
?载入标注文件
/// \brief 2d中心组件的解析函数
///
/// 在2d模式下,有文件读入时,会调用解析函数,初始化label中的图片以及标注等信息
void CentralWInit2D::parse(const QString &fileName,const QString &labelfileName){
label->status=My::NoShape;//初始为noshape状态
label->current=-1;//当前标注初始为-1,即不存在
//加载图片
label->pixmap->load(fileName);
//调用Parse的静态解析函数,初始化标注形状
My::Parse::parse(fileName,label->shapes,labelfileName);
//清空trashshape
trashshapes.clear(); // 存放删除的shape垃圾站
//更新label
label->update();
//发送解析完毕信号,初始化标签列表
QList<My::Shape*> temp;
for(int i=0;i<label->shapes.length();i++){
temp.push_back(label->shapes[i]);
}
emit labelsFinished(temp);
}
标签列表:
/// \brief 改变标注状态
///
/// 当标签列表中的item发生改变时,便会调用该槽函数
void CentralWInit2D::changeShapeLabel(QListWidgetItem *item){
//获得标签列表组件
QListWidget* lw=item->listWidget();
//定位改变item的位置 获取当前item在标签列表中的位置(行号)。
int index=lw->row(item);
//同步item的状态,如被隐藏,以及标注文字被改变等
label->shapes[index]->isHide=!(item->checkState());
label->shapes[index]->label=item->text();
//更新
label->update();
}
/// \brief 改变当前被选中的标注
///
/// 当标签列表中选中发生改变时,会调用该槽函数
void CentralWInit2D::changeSelected(){
//获取标签列表组件
QListWidget* lw=qobject_cast<QListWidget*>(sender()); // 获取发送信号的对象,即标签列表组件。
int temp=lw->count();
//同步选中状态,若被选中,则改变形状的填充状态为被选中,同时改变当前标注值即current。若不被选中,则反之
for(int index=0;index<lw->count();index++){
if(lw->item(index)->isSelected()){
label->shapes[index]->isFill=true;
temp=index;
}
else label->shapes[index]->isFill=false;
}
//若无被选中的标注,则更新current为-1;反之则为被选中的序号
if(temp==lw->count())label->current=-1;
else label->current=temp;
//改变current的同时,发出信号,使mainwindow改变为Focus状态,该状态下可对标注进行相应的更改
if(label->current!=-1)emit selectedChanged(label->current,true);
//更新
label->update();
}
/// \brief 创建标注形状
///
/// 当触发创建各种形状时,会经过mainwindow调用该函数
void CentralWInit2D::createShape(My::shapeStatus s){
//若是在创建形状的状态下改变创建的形状类型,若之前有未创建完的标注,则删掉
if(label->status==My::BrushShape || label->status==My::RectangleShape || label->status==My::PolygonsShape || label->status==My::CircleShape){
if(label->current!=-1){
label->shapes.pop_back();
label->current=-1;
}
}
//同步更改label的状态
label->status=s; //{BrushShape,...,CurveShape,NoShape,InShape};
//如果之前是选中状态即Focus状态,则发射信号,使mainwindow进入创建状态
if(label->current!=-1)emit(selectedChanged(label->current,false));
//更改current为-1;
label->current=-1;
}
?回车键和esc键
/// \brief 处理创建标注过程中的按键事件
///
/// 当是回车键和esc键时,mainwindow会将事件转发到这里来进行处理
void CentralWInit2D::keyPressHandle(int k){
if(k==Qt::Key_Enter || k==Qt::Key_Return){ // 多边形时,按回车结束标注。
//如果是创建形状状态
if(label->status==My::PolygonsShape || label->status==My::BrushShape || label->status==My::CurveShape){
if(label->current==-1)return;
//如果当前已创建标注形状
bool isOk;
//提醒用户键入标注文字
QString text=QInputDialog::getText(this,"label me!","Please input the label",QLineEdit::Normal,"",&isOk);
if(isOk){
//添加标注,同时发射信号,使标签列表组件同步的增加标注
label->shapes[label->current]->label=text;
emit(labelAdded(label->shapes[label->current],label->current));
command->logAdd(label->current);
//更改current为-1
label->current=-1;
return;
}
}
return;
}
if(k==Qt::Key_Escape){
//如果是在创建形状过程中
if(label->status==My::PolygonsShape || label->status==My::CircleShape || label->status==My::RectangleShape || label->status==My::BrushShape || label->status==My::CurveShape){
if(label->current==-1)return;
//如果之前有创建的形状,则删掉
else{
label->shapes.removeLast();
label->current=-1;
label->update();
}
}
return;
}
}
?
待续。。。
参考:GitHub - jameslahm/labelme: A image annotation software for 2D or 3D images