由于项目需要,编写一个简单的图像标注软件。
在这篇文章的基础上做了一些修改,添加了标注者信息、记录标注信息,生成图片格式的groundtruth、生成的groundtruth与原图大小相同、能够自动加载文件夹下的下一幅图像等。
http://blog.csdn.net/lanbing510/article/details/48251311
都是一些比较简单的方法,简单说一下我的思路:
首先,创建自己的QT Application。
*开发环境Qt5.4.2+opencv3.0+vs2013. 貌似可以直接用Qt Creator,不过我没用。安装和环境配置不再叙述,直接创建工程喽!
选择Qt Application,然后输入工程名,点击确定就可以了。
配置工程环境。
选择好自己的版本
这里也一样。
配置管理器也需要注意一下,选择64位还是32位根据自己的配置情况来定呦。
如果你的QT是64位,貌似opencv也需要是64位的。我在这里出过错,开始opencv是32位,就是x86,debug时提示错误,后来改成x64就可以了。
这时候,你可以点击“本地Windows调试器”旁边的绿色按钮运行一下,会出现一个简单的界面,说明你的配置没有问题。可以进行下一步了。
将已有的文件加载到自己的工程中。
红色框中的是添加的现有文件,其余的是创建工程的时候自己生成的。
那么如何避免加载imagelabel.ui,而加载mainwindow.ui?
非常简单,只需要修改main.cpp就ok了。
#include "imagelabel.h"
#include "mainwindow.h"
#include "setparameterdialog.h"
#include
//#include
//Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//ImageLabel w;
MainWindow w;
w.show();
return a.exec();
}
是不是很简单,现在如果你运行,就是mainwindow.ui所呈现的界面啦。
开始修改功能。
4.1 ui界面修改
Qt中的ui界面修改非常简单,你可以选择用代码来编辑,也可以使用可视化的界面,将一些元素拖拽到界面上,对属性做一些修改就可以了。
是不是分分钟就可以搞定,哈哈哈~
对setparameter进行差不多的操作:
修改出你满意的界面之后,对界面的按钮进行响应。也就是要进行代码的修改喽!
下面我只针对添加的功能,叙述我做出修改的部分,引用的代码当中有的:设置,打开图片,保存图片、连线,填充等不会详细描述呦
4.2 添加标注者信息
记录标注者信息的方式是创建文件夹,为不同的标注者创建不同的文件夹,保存时路径:输出路径\标注者\不同类型的标注\图像名。
首先获取“标注者”文本框中的值:
//获取文本框中的值
//读取图片的路径
QString imgPath=prSetDlg->getImagePath();
//这里fileFormat为起始图片的文件名
QString imgfileFormat=prSetDlg->getFileFormat();
//输出路径
QString outPath=prSetDlg->getOutputPath();
//标注者
QString markName=prSetDlg->getMarkerName();
然后将值赋给提前定义好的成员变量:
if(imgPath==""||imgfileFormat==""||outPath==""||markName=="")
{
QMessageBox::information(NULL, "Information", "Please Set The Parematers",QMessageBox::Ok , QMessageBox::Ok);
}
else
{
fileFormat = imgfileFormat;
markerName = markName;
}
这样,在对图片处理完毕,进行保存的时候,利用QDir获取路径,如果不存在就创建:
outPath=outPath+"\\"+markerName;
imgOutputPath = outputPath +"\\"+ lesionName + "\\" + fileFormat;
imgOutputPath.sprintf(imgOutputPath.toStdString().c_str());
//判断路径是否存在,不存在就创建
QDir *temp = new QDir;
QString dir = outputPath +"\\"+ lesionName;
bool exist = temp->exists(outputPath);
if (!exist)
{
if(temp->mkdir(outputPath))
QMessageBox::information(NULL, tr("Create save path"), "Create makerName path ok!", QMessageBox::Ok);;
}
exist = temp->exists(dir);
if (!exist)
{
if (temp->mkdir(dir))
QMessageBox::information(NULL, tr("Create save path"), "Create lesionName path ok!", QMessageBox::Ok);;
}
if (!imwrite(imgOutputPath.toStdString(), img_mask_binary))
{
QMessageBox::information(NULL,"Save Error","Please Check Your Save Path!",QMessageBox::Ok);
}
注意在前面包含头文件:
#include
4.3 自动加载下一张图片
这里用的方法是获取文件夹下的所有图片,将信息保存在QFileInfoList 中。
QFileInfoList MainWindow::getFileInfoList(QString inputPath)
{
QDir dir(inputPath);
dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
dir.setSorting(QDir::DirsFirst);
QFileInfoList list = dir.entryInfoList();
return list;
}
获取当前图片在list中的位置:
imageNum = 0;
//获取要打开图像在文件夹中的序号
list = getFileInfoList(inputPath);
QFileInfo fileInfo;
for (int i = 0; i < list.size(); i++)
{
fileInfo = list.at(i);
if (fileInfo.fileName() == fileFormat)
{
imageNum = i;
break;
}
}
读取下一张图片:
bool MainWindow::readNextImage()
{
//先找到当前文件(第一幅图片)的序号
int flag=imageNum+1;
if (flag < list.size())
{
contour.clear();
QFileInfo fileinfo = list.at(flag);
fileFormat = fileinfo.fileName();
//显示在状态栏
ui->frameshowLabel->setText(fileFormat);
imgInputPath = inputPath + fileFormat;
imgInputPath.sprintf(imgInputPath.toStdString().c_str());//,frameIdx);
img_cur = imread(imgInputPath.toStdString());
if (!img_cur.empty())
{
img_cur.copyTo(img_pre);
displayMat(img_cur);
img_orignal = img_cur;
// prSetDlg->setStartFrame(QString("%1").arg(frameIdx));
mask.create(img_cur.size(), CV_8UC1);
imageNum++;
return true;
}
else
{
QMessageBox::information(NULL, "Read Failure", "Failed To Read " + imgInputPath, QMessageBox::Ok, QMessageBox::Ok);
return false;
}
}
else
{
QMessageBox::information(NULL, "Read Failure", "There is the last image!" , QMessageBox::Ok, QMessageBox::Ok);
return false;
}
}
4.4 记录不同的标注类型信息
意思是:对同一张图片,可能需要针对它不同的方面进行标注,我做的是对眼底图像病变的标注,一般有四种病变类型,切换函数如下:
void MainWindow::on_nextLesionPushButton_clicked()
{
if (lesionFlag==1)
{
ui->nextLesionPushButton->setText("S***");
lesionName = ui->nextLesionPushButton->text();
readImage();
lesionFlag = 2;
}
else if (lesionFlag==2)
{
ui->nextLesionPushButton->setText("He***");
lesionName = ui->nextLesionPushButton->text();
readImage();
lesionFlag = 3;
}
else if (lesionFlag==3)
{
ui->nextLesionPushButton->setText("M***");
lesionName = ui->nextLesionPushButton->text();
readImage();
lesionFlag = 4;
}
else if (lesionFlag==4)
{
ui->nextLesionPushButton->setText("H***");
lesionName = ui->nextLesionPushButton->text();
readImage();
lesionFlag = 1;
}
else
{
//出错处理,debug的时候用
QMessageBox::information(NULL, "Error", "Maybe your code have bugs!", QMessageBox::Ok);
}
}
4.5 生成与原图大小相同的图片格式的groundtruth。
一般,可以根据图片的大小动态地改变窗口的大小:
ui->label->setPixmap(QPixmap::fromImage(img));
ui->label->resize(ui->label->pixmap()->size());
ui->label->show();
在保存时,resize一下图像,使其与原始图像一样大:
Mat img_mask,img_mask_binary;
cv::resize(img_cur, img_cur, Size(img_orignal.cols, img_orignal.rows));
//计算img_orignal与img_cur的差
cv::subtract(img_orignal, img_cur, img_mask);
cvtColor(img_mask, img_mask_binary, CV_BGR2GRAY);
5 出现的bug
编译成功后,如果不是用的静态编译,很容易出现换一台电脑就不能用了。可以在.exe目录下放上一些需要的.dll文件。
貌似如果你用的是x64,在32位的Windows系统上面不能运行呢,我也没有继续解决这一部分。
6 总结
这次主要是在别人代码的基础上做的一些功能的增减,但是对我了解Qt还是挺有帮助的。实现这些功能的方法也都比较简单。
第一次写技术博客,没有经验,搞的不好。希望以后可以更好,哈哈~