前几天,用Qt写了个图像标注工具,最近电脑崩了,然后界面化的东西发不了了,待我将电脑
环境,编译好再发。这里先提供Qt源代码。
测试环境:win10 64x QtCreator5.7.0, opencv2.4.13
环境配置文件.pro,根据个人电脑路径,自行配制opencv
#-------------------------------------------------
#
# Project created by QtCreator 2017-05-25T21:01:11
#
#-------------------------------------------------
QT += core gui
QT += xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = image_lable_tool_ui
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
my_qlabel.cpp
HEADERS += mainwindow.h \
my_qlabel.h
FORMS += mainwindow.ui
INCLUDEPATH += C:/opencv-2.4.13/build/install/include \
C:/opencv-2.4.13/build/install/include/opencv \
C:/opencv-2.4.13/build/install/include/opencv2
LIBS += C:/opencv-2.4.13/build/install/x86/mingw/lib/libopencv_*
由于本人将图像显示在QLabel上,而又用到鼠标事件,所以,我自己定义了一个由QLabel继承来的类
my_qlabel 头文件.h
#ifndef MY_QLABEL_H
#define MY_QLABEL_H
#include
#include
#include
#include
class My_QLabel : public QLabel
{
Q_OBJECT
public:
explicit My_QLabel(QWidget *parent=0);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void leaveEvent(QEvent *event);
int Pos_x(){return x;}
int Pos_y(){return y;}
inline void setPress_flag(bool a){Press_flag=a;}
inline bool getPress_flag(){return Press_flag;}
inline void setRelease_flag(bool a){Release_flag=a;}
inline bool getRelease_flag(){return Release_flag;}
private:
int x,y;
bool Press_flag=false;
bool Release_flag=false;
signals:
void Mouse_Pressed();
void Mouse_Pos();
void Mouse_left();
void Mouse_Release();
};
#endif // MY_QLABEL_H
my_qlabel.cpp
#include "my_qlabel.h"
My_QLabel::My_QLabel(QWidget *parent):
QLabel(parent)
{
}
void My_QLabel::mouseMoveEvent(QMouseEvent *event)
{
this->x=event->x();
this->y=event->y();
emit Mouse_Pos();
}
void My_QLabel::mousePressEvent(QMouseEvent *event)
{
this->x=event->x();
this->y=event->y();
if(event->button()==Qt::LeftButton)
{
Press_flag=true;
Release_flag=false;
}
else
Press_flag=false;
emit Mouse_Pressed();
}
void My_QLabel::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
Press_flag=false;
Release_flag=true;
}
emit Mouse_Release();
}
void My_QLabel::leaveEvent(QEvent *event)
{
emit Mouse_left();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
void displayMat(cv::Mat & image);
bool checkedradioButton();
bool isDirExist(QString fullpath);
void clear_current_workspace();
cv::Rect portion2scaledReal(cv::Rect_<float>&);
cv::Rect portion2scaledReal_unscaled(cv::Rect_<float> &rect);
QString selectedLabel();
cv::Scalar setColor(QString&);
~MainWindow();
private slots:
//void on_openImagepushButton_clicked();
void on_setDirpushButton_clicked();
void on_nextpushButton_clicked();
void on_previouspushButton_clicked();
void Mouse_current_pos();
void Mouse_Pressed();
void Mouse_left();
void Mouse_Release();
void on_exprotXMLpushButton_clicked();
void on_PersonradioButton_clicked();
void on_CarradioButton_clicked();
void on_BusradioButton_clicked();
void on_MotorradioButton_clicked();
void on_BicycleradioButton_clicked();
void on_BBoxlistWidget_itemClicked(QListWidgetItem*);
void on_BBoxlistWidget_itemDoubleClicked(QListWidgetItem*);
//void on_BBoxlistWidget_doubleClicked(const QModelIndex &index);
void on_setXMLDirpushButton_clicked();
private:
Ui::MainWindow *ui;
cv::Mat current_src_image,current_dst_image;
int current_src_w,current_src_h;
QImage image;
QString imageDirString;
QString xmlDirString;
QFileInfoList imageFileInfoList;
std::vector listItem;
int image_info_index=0;
QLabel *dirLabel;
QLabel *imagenameLabel;
QLabel *posLabel;
QLabel *xmlDirLabel;
QTextCodec *code;
std::vector<std::pairfloat > > >total_bbox;
cv::Point_<float> begin_pos,end_pos;
cv::Scalar rgb;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "my_qlabel.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
dirLabel=new QLabel(tr("工作目录:"));
xmlDirLabel=new QLabel(tr("保存目录: "));
imagenameLabel=new QLabel(tr("图像名:"));
ui->statusBar->addWidget(dirLabel);
ui->statusBar->addWidget(xmlDirLabel);
ui->statusBar->addWidget(imagenameLabel);
posLabel=new QLabel(tr("坐标:X=NULL , Y=NULL "));
ui->statusBar->addWidget(posLabel);
code = QTextCodec::codecForName("gb18030");
connect(ui->nextpushButton,SIGNAL(clicked()),this,SLOT(on_nextpushButton_clicked()));
connect(ui->previouspushButton,SIGNAL(clicked()),this,SLOT(on_previouspushButton_clicked()));
connect(ui->Imagelabel,SIGNAL(Mouse_Pos()),this,SLOT(Mouse_current_pos()));
connect(ui->Imagelabel,SIGNAL(Mouse_Pressed()),this,SLOT(Mouse_Pressed()));
connect(ui->Imagelabel,SIGNAL(Mouse_left()),this,SLOT(Mouse_left()));
connect(ui->Imagelabel,SIGNAL(Mouse_Release()),this,SLOT(Mouse_Release()));
connect(ui->BBoxlistWidget,SIGNAL(itemDoubleClicked(QListWidgetItem *)),this,
SLOT(on_BBoxlistWidget_itemDoubleClicked(QListWidgetItem*)),Qt::UniqueConnection);
connect(ui->BBoxlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,
SLOT(on_BBoxlistWidget_itemClicked(QListWidgetItem*)));
}
MainWindow::~MainWindow()
{
delete ui;
delete dirLabel;
delete imagenameLabel;
delete posLabel;
// delete code;
//delete imagenameLabel;
}
void MainWindow::displayMat(cv::Mat & image)
{
cv::Mat rgb;
if(image.channels()==3)
{
cvtColor(image,rgb,CV_BGR2RGB);
this->image=QImage((const unsigned char *)(rgb.data),
rgb.cols,rgb.rows,
rgb.cols*rgb.channels(),
QImage::Format_RGB888
);
}
else
this->image=QImage((const unsigned char *)(rgb.data),
rgb.cols,rgb.rows,
rgb.cols*rgb.channels(),
QImage::Format_RGB888
);
ui->Imagelabel->resize(image.cols,image.rows);
ui->Imagelabel->setPixmap(QPixmap::fromImage(this->image));
}
void MainWindow::on_setDirpushButton_clicked()
{
QString DirName=QFileDialog::getExistingDirectory (this, tr("选择文件夹"),
tr("C:/Users/CharelCHEN/Desktop/imagedata/frame"),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
this->imageDirString=DirName;
//QTextCodec *code = QTextCodec::codecForName("gb18030");
QString name = code->fromUnicode(DirName).data();
QDir imageDir(name);
imageDir.setFilter(QDir::Files | QDir::NoSymLinks);
imageDir.setSorting(QDir::Size | QDir::Reversed);
this->imageFileInfoList=imageDir.entryInfoList();
QString image_qname=imageFileInfoList.at(image_info_index).fileName();
std::string image_name = code->fromUnicode(image_qname).data();
std::string image_dir = code->fromUnicode(DirName).data();
dirLabel->setText(tr("工作目录:")+this->imageDirString);
imageDir.cdUp();
xmlDirString=imageDir.absolutePath()+QString("/xml");
isDirExist(xmlDirString);
xmlDirLabel->setText(tr("保存目录: ")+this->xmlDirString);
if(image_name.find_last_of(".jpg"))
{
current_src_image=cv::imread(image_dir+'/'+image_name);
current_src_h=current_src_image.rows;
current_src_w=current_src_image.cols;
cv::resize(current_src_image,current_src_image,
cv::Size(current_src_w*0.8,current_src_h*0.8));
current_dst_image=current_src_image.clone();
imagenameLabel->setText(tr("图像名:")+imageFileInfoList.at(image_info_index).fileName());
}
displayMat(current_src_image);
}
void MainWindow::on_nextpushButton_clicked()
{
if(!imageDirString.isEmpty())
{
image_info_index++;
if(image_info_index==imageFileInfoList.size())
image_info_index=0;
std::string name=code->fromUnicode(imageFileInfoList.at(image_info_index).fileName()).data();
std::string dir=code->fromUnicode(imageDirString).data();
if(name.find_last_of(".jpg"))
{
current_src_image=cv::imread(dir+'/'+name);
current_src_h=current_src_image.rows;
current_src_w=current_src_image.cols;
cv::resize(current_src_image,current_src_image,
cv::Size(current_src_w*0.8,current_src_h*0.8));
current_dst_image=current_src_image.clone();
imagenameLabel->setText(tr("图像名:")+imageFileInfoList.at(image_info_index).fileName());
}
displayMat(current_src_image);
}
else
{
QMessageBox messageBox;
messageBox.critical(0,"错误!","工作目录为空");
messageBox.setFixedSize(500,200);
}
clear_current_workspace();
}
void MainWindow::on_previouspushButton_clicked()
{
if(!imageDirString.isEmpty())
{
image_info_index--;
if(image_info_index==-1)
image_info_index=imageFileInfoList.size()-1;
std::string name=code->fromUnicode(imageFileInfoList.at(image_info_index).fileName()).data();
std::string dir=code->fromUnicode(imageDirString).data();
if(name.find_last_of(".jpg"))
{
current_src_image=cv::imread(dir+'/'+name);
current_src_h=current_src_image.rows;
current_src_w=current_src_image.cols;
cv::resize(current_src_image,current_src_image,
cv::Size(current_src_w*0.8,current_src_h*0.8));
current_dst_image=current_src_image.clone();
imagenameLabel->setText(tr("图像名:")+imageFileInfoList.at(image_info_index).fileName());
}
displayMat(current_src_image);
}
else
{
QMessageBox messageBox;
messageBox.critical(0,"错误!","工作目录为空");
messageBox.setFixedSize(700,200);
}
clear_current_workspace();
//current
}
void MainWindow::Mouse_current_pos()
{
cv::Mat intermed_image=current_dst_image.clone();
if(!current_src_image.empty())
{
float x=ui->Imagelabel->Pos_x()*1.0/current_src_image.cols;
float y=ui->Imagelabel->Pos_y()*1.0/current_src_image.rows;
posLabel->setText(QString("坐标: X=%1 , Y=%2").arg(x).arg(y));
}
else
posLabel->setText(QString("坐标: X=NULL , Y=NULL"));
if(ui->Imagelabel->getPress_flag())
{
// QPainter painter(ui->Imagelabel);
end_pos.x=ui->Imagelabel->Pos_x()*1.0/current_src_image.cols;
end_pos.y=ui->Imagelabel->Pos_y()*1.0/current_src_image.rows;
cv::Point begin(begin_pos.x*current_src_image.cols,
begin_pos.y*current_src_image.rows);
cv::Point end(end_pos.x*current_src_image.cols,
end_pos.y*current_src_image.rows);
if(checkedradioButton())
{
cv::rectangle(intermed_image,cv::Rect(begin,end),rgb,2);
}
displayMat(intermed_image);
// displayMat(current_src_image);
//painter.drawRect(QRect(begin_pos,end_pos));
}
}
void MainWindow::Mouse_Pressed()
{
if(ui->Imagelabel->getPress_flag())
{
begin_pos.x=ui->Imagelabel->Pos_x()*1.0/current_src_image.cols;
begin_pos.y=ui->Imagelabel->Pos_y()*1.0/current_src_image.rows;
}
}
void MainWindow::Mouse_left()
{
posLabel->setText(QString("坐标: X=NULL , Y=NULL"));
}
void MainWindow::Mouse_Release()
{
current_dst_image=current_src_image.clone();
if(ui->Imagelabel->getRelease_flag())
{
for(int i=0;i
{
cv::Rect tmp=portion2scaledReal(total_bbox[i].second);
cv::Scalar RGB=setColor(total_bbox[i].first);
cv::rectangle(current_dst_image,tmp,RGB,2);
}
displayMat(current_dst_image);
end_pos.x=ui->Imagelabel->Pos_x()*1.0/current_src_image.cols;
end_pos.y=ui->Imagelabel->Pos_y()*1.0/current_src_image.rows;
cv::Rect_ tmp(begin_pos,end_pos);
cv::Rect tmp_real=portion2scaledReal(tmp);
if(checkedradioButton())
{
cv::rectangle(current_dst_image,tmp_real,rgb,2);
QString label=selectedLabel();
if(tmp.width>0.01 &&tmp.height>0.01)
{
total_bbox.push_back(std::make_pair(label,tmp));
QListWidgetItem *list=new QListWidgetItem(label,ui->BBoxlistWidget);
ui->BBoxlistWidget->insertItem(total_bbox.size()-1,list);
//list->setData(Qt::UserRole,QString(total_bbox.size()-1));
ui->BBoxlistWidget->show();
}
}
displayMat(current_dst_image);
}
ui->Imagelabel->setRelease_flag(false);
}
void MainWindow::on_exprotXMLpushButton_clicked()
{
QDomDocument doc("");
QDomElement root=doc.createElement("annotation");
doc.appendChild(root);
QDomElement tmp=doc.createElement("folder");
QDomText txt=doc.createTextNode(QDir(imageDirString).
dirName());
tmp.appendChild(txt);
root.appendChild(tmp);
tmp=doc.createElement("filename");
txt=doc.createTextNode(imageFileInfoList
[image_info_index].fileName());
tmp.appendChild(txt);
root.appendChild(tmp);
QDomElement src=doc.createElement("source");
tmp=doc.createElement("database");
txt=doc.createTextNode("");
root.appendChild(src);
tmp.appendChild(txt);
src.appendChild(tmp);
tmp=doc.createElement("annotation");
txt=doc.createTextNode("MyData");
tmp.appendChild(txt);
src.appendChild(tmp);
tmp=doc.createElement("image");
txt=doc.createTextNode("");
tmp.appendChild(txt);
src.appendChild(tmp);
src=doc.createElement("owners");
tmp=doc.createElement("flickrid");
txt=doc.createTextNode("");
root.appendChild(src);
tmp.appendChild(txt);
src.appendChild(tmp);
tmp=doc.createElement("name");
txt=doc.createTextNode("");
tmp.appendChild(txt);
src.appendChild(tmp);
QDomElement size=doc.createElement("size");
tmp=doc.createElement("width");
txt=doc.createTextNode(QString::number(current_src_h));
root.appendChild(size);
tmp.appendChild(txt);
size.appendChild(tmp);
tmp=doc.createElement("height");
txt=doc.createTextNode(QString::number(current_src_w));
tmp.appendChild(txt);
size.appendChild(tmp);
tmp=doc.createElement("depth");
txt=doc.createTextNode(QString::number(current_dst_image.channels()));
tmp.appendChild(txt);
size.appendChild(tmp);
tmp=doc.createElement("segmented");
txt=doc.createTextNode("0");
tmp.appendChild(txt);
root.appendChild(tmp);
for(int i=0;i
{
QDomElement object=doc.createElement("object");
QDomElement name=doc.createElement("name");
QDomText label=doc.createTextNode(total_bbox[i].first);
name.appendChild(label);
object.appendChild(name);
root.appendChild(object);
name=doc.createElement("pose");
label=doc.createTextNode("");
name.appendChild(label);
object.appendChild(name);
name=doc.createElement("truncated");
label=doc.createTextNode("");
name.appendChild(label);
object.appendChild(name);
name=doc.createElement("difficult");
label=doc.createTextNode("");
name.appendChild(label);
object.appendChild(name);
cv::Rect rect=portion2scaledReal_unscaled(total_bbox[i].second);
QDomElement bndbox=doc.createElement("bndbox");
object.appendChild(bndbox);
QDomElement xmin=doc.createElement("xmin");
QDomText txt=doc.createTextNode(QString::number(rect.x));
xmin.appendChild(txt);
bndbox.appendChild(xmin);
QDomElement ymin=doc.createElement("ymin");
txt=doc.createTextNode(QString::number(rect.y));
ymin.appendChild(txt);
bndbox.appendChild(ymin);
QDomElement xmax=doc.createElement("xmax");
txt=doc.createTextNode(QString::number(rect.x+rect.width));
xmax.appendChild(txt);
bndbox.appendChild(xmax);
QDomElement ymax=doc.createElement("ymax");
txt=doc.createTextNode(QString::number(rect.y+rect.height));
ymax.appendChild(txt);
bndbox.appendChild(ymax);
}
QString xmlname=imageFileInfoList[image_info_index].
fileName().split(".")[0]+".xml";
QFile fd(xmlDirString+'/'+xmlname);
if(fd.open(QIODevice::WriteOnly |QIODevice::Truncate))
{
QTextStream out(&fd);
out<;
fd.close();
}
}
void MainWindow::on_PersonradioButton_clicked()
{
if(ui->PersonradioButton->isChecked())
rgb=cv::Scalar(255,0,0);
}
void MainWindow::on_CarradioButton_clicked()
{
if(ui->CarradioButton->isChecked())
rgb=cv::Scalar(0,0,255);
}
void MainWindow::on_BusradioButton_clicked()
{
if(ui->BusradioButton->isChecked())
rgb=cv::Scalar(255,255,0);
}
void MainWindow::on_MotorradioButton_clicked()
{
if(ui->MotorradioButton->isChecked())
rgb=cv::Scalar(255,0,255);
}
void MainWindow::on_BicycleradioButton_clicked()
{
if(ui->BicycleradioButton->isChecked())
rgb=cv::Scalar(0,255,0);
}
bool MainWindow::checkedradioButton()
{
return ui->PersonradioButton->isChecked()|| ui->BicycleradioButton->isChecked()||
ui->CarradioButton->isChecked() || ui->BusradioButton->isChecked()||
ui->MotorradioButton->isChecked();
}
bool MainWindow::isDirExist(QString fullPath)
{
QDir dir(fullPath);
if(dir.exists())
{
return true;
}
else
{
bool ok=dir.mkdir(fullPath);
return ok;
}
}
void MainWindow::clear_current_workspace()
{
total_bbox.clear();
for(int i=0;i
{
delete listItem[i];
}
}
cv::Rect MainWindow::portion2scaledReal(cv::Rect_ &rect)
{
cv::Rect tr_rect;
tr_rect.x=current_src_image.cols*rect.x;
tr_rect.y=current_src_image.rows*rect.y;
tr_rect.width=current_src_image.cols*rect.width;
tr_rect.height=current_src_image.rows*rect.height;
return tr_rect;
}
cv::Rect MainWindow::portion2scaledReal_unscaled(cv::Rect_ &rect)
{
cv::Rect tr_rect;
tr_rect.x=current_src_w*rect.x;
tr_rect.y=current_src_h*rect.y;
tr_rect.width=current_src_w*rect.width;
tr_rect.height=current_src_h*rect.height;
return tr_rect;
}
QString MainWindow::selectedLabel()
{
if(ui->BicycleradioButton->isChecked())
return "Bicycle";
if(ui->PersonradioButton->isChecked())
return "Person";
if(ui->CarradioButton->isChecked())
return "Car";
if(ui->MotorradioButton->isChecked())
return "Motor";
if(ui->BusradioButton->isChecked())
return "Bus";
}
cv::Scalar MainWindow::setColor(QString &label)
{
cv::Scalar RGB;
if(label==QString("Bicycle"))
RGB=cv::Scalar(0,255,0);
if(label==QString("Person"))
RGB=cv::Scalar(255,0,0);
if(label== QString("Car"))
RGB=cv::Scalar(0,0,255);
if(label== QString("Motor"))
RGB=cv::Scalar(255,0,255);
if(label== QString("Bus"))
RGB=cv::Scalar(255,255,0);
return RGB;
}
void MainWindow::on_BBoxlistWidget_itemClicked(QListWidgetItem* it)
{
int row=ui->BBoxlistWidget->row(it);
cv::Mat tmp=current_src_image.clone();
setColor(total_bbox[row].first);
cv::rectangle(tmp,portion2scaledReal(total_bbox[row].second),rgb,2);
displayMat(tmp);
}
void MainWindow::on_BBoxlistWidget_itemDoubleClicked(QListWidgetItem* item)
{
//foreach(QListWidgetItem * item1, item)
// {
int row=ui->BBoxlistWidget->row(item);
ui->BBoxlistWidget->takeItem(row);
std::vector<std::pair > >::iterator it=total_bbox.begin()+row;
total_bbox.erase(it);
// }
ui->BBoxlistWidget->show();
displayMat(current_src_image);
}
void MainWindow::on_setXMLDirpushButton_clicked()
{
QString DirName=QFileDialog::getExistingDirectory (this, tr("选择文件夹"),
tr("C:/Users/CharelCHEN/Desktop/imagedata/xml"),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
QString name = code->fromUnicode(DirName).data();
this->xmlDirString=name;
xmlDirLabel->setText(tr("保存目录: ")+this->xmlDirString);
}
链接:http://pan.baidu.com/s/1i5zcd6H 密码:oolp