先在QT中编译opencvhttps://blog.csdn.net/yx868yx/article/details/105708554
界面效果如下:
1、用QPainter 画背景图
2、QPushButton(本地上传和检测),当点击本地上传时打开本地文件夹选择要检测的图片;点击检测按钮时才会检测图片
3、label显示,显示上传的图片和检测后的图片
4、textEdit,显示检测后的精度,更换图片就清空
1、在.pro中加入opencv编译库
DEFINES += QT_DEPRECATED_WARNINGS
INCLUDEPATH += D:/opencv/build/install/include
LIBS += D:/opencv/build/install/x86/mingw/bin/libopencv_*.dll
2、.h文件
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QImage *image = NULL;
QImage *myImage;
bool flag = 0; //标识位
void paintEvent(QPaintEvent *);//用于画背景
void detector();//用于检测
cv::Mat QImage2Mat(const QImage& qimage);//用于QImage转换成Mat形式
PS:用opencv处理数据的形式是Mat和QT不一样,需要转化
3、功能实现的.cpp文件主要代码:
//实现本地上传按钮功能,加载本地路径
connect(ui->pushButton_2,&QPushButton::clicked,[=](){
QString path = QFileDialog::getOpenFileName(this,"打开图片",".", "图片 (*.bmp *.jpg *.pbm *.pgm *.png *.ppm *.xbm *.xpm);所有文件(*.*)");
if (path != "")
{
flag = 1;
if(image->load(path))
{
ui->label->setPixmap(QPixmap::fromImage((*image).scaled(ui->label->size(), Qt::KeepAspectRatio)));
flag = 1;
ui->textEdit->setText("");
}
else
{
QMessageBox::information(this,"打开图像失败","打开图像失败!");
return;
}
}
else
flag = 0;
});
this->myImage = image;
//实现检测按钮功能,按下检测按钮实现检测功能
connect(ui->pushButton,&QPushButton::clicked,[=](){
if(flag)
{
detector();
}
else
{
QMessageBox::information(this,"选择图片","请先上传图片!");
return;
}
});
//QImage转化成Mat形式
Mat MainWindow::QImage2Mat(const QImage& qimage)
{
Mat mat = Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
Mat mat2 = Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
return mat2;
}
//画家功能实现,加载图片
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pix;
pix.load(":/res/bg.jpg");
painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
//SSD检测过程
void MainWindow::detector(){
clock_t start, finish;
double totaltime;
Mat frame;
String weights = "./ssd_mobilenet_v1_coco_11_06_2017/frozen_inference_graph.pb";
String prototxt = "./ssd_mobilenet_v1_coco_11_06_2017/ssd_mobilenet_v1_coco.pbtxt";
dnn::Net net = cv::dnn::readNetFromTensorflow(weights, prototxt);
frame = QImage2Mat(*myImage);
start = clock();
Size frame_size = frame.size();
Size cropSize;
if (frame_size.width / (float)frame_size.height > WHRatio)
{
cropSize = Size(static_cast<int>(frame_size.height * WHRatio),
frame_size.height);
}
else
{
cropSize = Size(frame_size.width,
static_cast<int>(frame_size.width / WHRatio));
}
Rect crop(Point((frame_size.width - cropSize.width) / 2,
(frame_size.height - cropSize.height) / 2),
cropSize);
cv::Mat blob = cv::dnn::blobFromImage(frame, 1. / 255, Size(300, 300));
//blobFromImage主要是用来对图片进行预处理。包含两个主要过程:
//整体像素值减去平均值(mean)
//通过缩放系数(scalefactor)对图片像素值进行缩放
// 1*3*300*300
cout << "blob size: " << blob.size << endl;
net.setInput(blob);
Mat output = net.forward();
// 1*1*100*7
cout << "output size: " << output.size << endl;
Mat detectionMat(output.size[2], output.size[3], CV_32F, output.ptr<float>());
frame = frame(crop);
float confidenceThreshold = 0.60;
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at<float>(i, 2);
if (confidence > confidenceThreshold)
{
size_t objectClass = (size_t)(detectionMat.at<float>(i, 1));
int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);
int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);
int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);
int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);
ostringstream ss;
ss << confidence;
String conf(ss.str());
Rect object((int)xLeftBottom, (int)yLeftBottom,
(int)(xRightTop - xLeftBottom),
(int)(yRightTop - yLeftBottom));
rectangle(frame, object, Scalar(0, 255, 0), 1);
cout << "objectClass:" << objectClass << endl;
String label = String(classNames[objectClass]) + ": " + conf;
cout << "label"<<label << endl;
//重定义标准输出流
QTextStream stream (stdout);
QString str ;
//把string类型转化为QString
str = QString::fromStdString(label);
stream << str<<endl;
ui->textEdit->append(str +"\n");
//QString转化成string
//label = str.toStdString();
int baseLine = 0;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),
Size(labelSize.width, labelSize.height + baseLine)),
Scalar(0, 255, 0), CV_FILLED);
putText(frame, label, Point(xLeftBottom, yLeftBottom),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));
}
}
finish = clock();
totaltime = finish - start;
cout << "Recognition time " << totaltime <<"ms"<< endl;
// namedWindow("result", 0);
//imshow("result", frame);
//将SSD处理后的mat格式转化成QImage形式
cvtColor(frame, frame, COLOR_BGR2RGB);
int width=frame.cols;
int height=frame.rows;
int i,j;
QImage *Image = new QImage(width,height,QImage::Format_RGB888);
for(i=0;i<height;i++)
{
unsigned char *ptr = frame.ptr<unsigned char>(i);
//unsigned char *ptr = img.ptr<unsigned char>(i)[0];
for(j=0;j<width*3;j+=3)
{
Image->bits()[(Image->bytesPerLine()*i)+(j+2)] = ptr[j+2];
Image->bits()[(Image->bytesPerLine()*i)+(j+1)] = ptr[j+1];
Image->bits()[(Image->bytesPerLine()*i)+(j)] = ptr[j];
}
}
// cvtColor(frame, frame, COLOR_BGR2RGB);//图像格式转换
// QImage disImage = QImage((const unsigned char*)(frame.data),frame.cols,frame.rows,QImage::Format_RGB888); 不管用
//ui->label->setAlignment(Qt::AlignHCenter);
ui->label->setPixmap(QPixmap::fromImage((*Image).scaled(ui->label->size(), Qt::KeepAspectRatio)));//显示图像
github地址:https://github.com/yx868868/QT_Object_Detection
之前有看过一个QT显示opencv边缘检测的项目:
博客连接为:https://blog.csdn.net/weixin_38334320/article/details/70184272
下载其源代码,有闪退的情况,对其进行修改:声明对象时,使用new对对象进行实例化,更改后项目地址:
https://github.com/yx868868/QT_Canny