【图像处理】Qt+OpenCV自制mini软件——图像二值化器

 2023-09-07 阅读 12 评论 0

摘要:【fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】 前言 前段时间杂事很多,这几天突然觉得自己有段时间没有碰Qt了,手有点生了。心血来潮,花了两个小时(是真的手生了),利用Qt和OpenCV写了个用于图像二值

fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】

前言

       前段时间杂事很多,这几天突然觉得自己有段时间没有碰Qt了,手有点生了。心血来潮,花了两个小时(是真的手生了),利用Qt和OpenCV写了个用于图像二值化的程序。由于我个人习惯的原因,我是在VS2013中直接写代码进行编译的,不是在Qt中写的代码。好了话不多说,开始吧!

软件工具:VS2013+ Qt5.5.1 +OpenCV3.0+Win7(X64)

工程配置

       在VS2013中首先新建一个Qt项目,然后将OpenCV的包含目录、库目录以及库名添加到项目属性中(这一步,我就不多讲了,怎么配置工程环境,大家应该都清楚)。因为要使用工具栏,所以创建项目时,基类使用的是QMainWindow。

软件界面

opencv二值化,      为了方便讲解,这里先把软件界面展示给大家,图中详细标注了我所放置的控件。

      

界面分析

      上图左上角的读入、保存按键是用以读入原始图像和保存二值化的结果图的,图中公有6个label。label1和label2用来标注下方图像为原始图与二值化图像,label3和label4 用于显示图像,label5和label6分别标注滑条的最大值与最小值。此外还有一个微调框和滑条用以控制图像二值化阈值。

软件操作

       视频转换成gif搞了半天还是不清晰,大家凑合看吧!意思是那个个意思,打开图片,调节阈值,选取合适的阈值,输出二值化后的结果图。

代码

       照例先贴出代码;

      需要说明,我将软件界面中心的四个label单独在一个类中实现了,这需要右键项目属性添加类,并且选择Qt5Class,基类选择的是QWidget,类名为ShowWidget,同时自动生成了一个头文件一个源文件,代码如下,十分简单,不做讲解。

showwidgets.h

//--------showwidgets.h
//--------潘正宇 2018.04.02#pragma once
#include <QWidget>
#include <QLabel>
#include <QImage>#pragma execution_character_set("utf-8")
class ShowWidget :public QWidget
{Q_OBJECTpublic:explicit ShowWidget(QWidget *parent = 0);QImage img;QLabel *originLabel;     //label1QLabel *binaryLabel;     //label2QLabel *imageLabel1;     //label3QLabel *imageLabel2;     //label4QWidget *Widget1;        //存放label1与label3的widgetQWidget *Widget2;        //存放label2与label5的widgetsignals:public slots :private:};     

showwidgets.cpp 

//--------showwidgets.cpp
//--------潘正宇 2018.04.02#include "showwidgets.h"
#include <QBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>using namespace std;
using namespace cv;ShowWidget::ShowWidget(QWidget *parent) :QWidget(parent)
{originLabel = new QLabel;originLabel->setText(QStringLiteral("原始图像"));binaryLabel = new QLabel;binaryLabel->setText(QStringLiteral("二值化的图像"));imageLabel1 = new QLabel;imageLabel1->setFixedSize(400, 400);           //固定label的大小;imageLabel1->setScaledContents(true);          //按比例自动调整图像大小以在label中显示imageLabel2 = new QLabel;imageLabel2->setFixedSize(400, 400);imageLabel2->setScaledContents(true);if (img.load("white.jpg")){imageLabel1->setPixmap(QPixmap::fromImage(img));imageLabel2->setPixmap(QPixmap::fromImage(img));}Widget1 = new QWidget;Widget2 = new QWidget;QVBoxLayout *originLayout = new QVBoxLayout(Widget1);originLayout->addWidget(originLabel);originLayout->addWidget(imageLabel1);QVBoxLayout *binaryLayout = new QVBoxLayout(Widget2);binaryLayout->addWidget(binaryLabel);binaryLayout->addWidget(imageLabel2);QHBoxLayout  *mainLayout = new QHBoxLayout(this);mainLayout->addWidget(Widget1);mainLayout->addWidget(Widget2);mainLayout->setSpacing(5);                           //在各个区域之间设置间隔。
}

      主窗口实现的头文件及源文件如下;

qt_threshold.h

//--------qt_threshold.h
//--------潘正宇 2018.04.02#ifndef QT_THRESHOLD_H
#define QT_THRESHOLD_H#include "showwidgets.h"
#include <QtWidgets/QMainWindow>
#include <QPixmap>
#include <QSlider>
#include <QFileDialog>
#include <QMessageBox>
#include <QAction>
#include <QToolBar>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QLabel>
#include <QSpinBox>
#include <QImage>using namespace cv;class Qt_threshold : public QMainWindow
{Q_OBJECTpublic:Qt_threshold(QWidget *parent = 0);~Qt_threshold();private:QImage originImg;                //存储原始图像QImage binaryImg;                //存储二值化后的图像ShowWidget *showwidget;          //定义一个ShowWidget对象QWidget *mainWidget;             //中心部件窗体QWidget *Change;                 //放置滑条、微调框、label5、label6的窗体QSlider *slider;                 //滑条QSpinBox *pSpinBox;              //微调框QLabel *minVauleLabel;           //label5QLabel *maxVauleLabel;           //label6QToolBar *fileTool;              //工具栏QString fileName;Mat originImage;Mat binaryImage;void createAction();             //创建工具栏的函数void createChanges();            //创建滑条和微调框的函数signals://--------------槽函数public slots :void SaveFile();                //保存文件的槽函数void OpenFile();                //打开文件的槽函数void SpinBoxChangeImageshow();  //spinBox改变时触发的槽函数void SliderChangeImageshow();   //slider改变时触发的槽函数
};#endif // QT_THRESHOLD_H    

qt_threshold.cpp

//--------qt_threshold.cpp
//--------潘正宇 2018.04.02#include "qt_threshold.h"
#include <QToolBar>
#include <QHBoxLayout>
#include <QSpinBox>
#include <QSlider>
#include <string>
#include "showwidgets.h"
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;Qt_threshold::Qt_threshold(QWidget *parent): QMainWindow(parent)
{setWindowTitle(QStringLiteral("自制图像二值化mini程序"));createAction();showwidget = new ShowWidget(this);                     // 创建一个ShowWidget类型的区域,用于展示载入的图片mainWidget = new QWidget;                              // 创建中心部件区域Change = new QWidget;createChanges();QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget);  //在mainWidget内构件一个垂直的布局,放入mainLayout->addWidget(showwidget);mainLayout->addWidget(Change);setCentralWidget(mainWidget);                          //将mainWidget置于MainWindow的中心区域	}Qt_threshold::~Qt_threshold()
{}void Qt_threshold::createChanges()
{slider = new QSlider;slider->setOrientation(Qt::Horizontal);  // 水平方向slider->setMinimum(0);  // 最小值slider->setMaximum(255);  // 最大值slider->setSingleStep(1);  // 步长slider->setValue(80);    //初始值pSpinBox = new QSpinBox(this);pSpinBox->setMinimum(0);  pSpinBox->setMaximum(255);  pSpinBox->setSingleStep(1);pSpinBox->setValue(80);minVauleLabel = new QLabel;maxVauleLabel = new QLabel;minVauleLabel->setText("0");       //滑条两端的label,放置最大值以及最小值;maxVauleLabel->setText("255");QHBoxLayout *HLayout = new QHBoxLayout(Change);HLayout->addWidget(pSpinBox);             //水平布局HLayout->addWidget(minVauleLabel);HLayout->addWidget(slider);HLayout->addWidget(maxVauleLabel);///--------------信号槽连接;connect(slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChangeImageshow()));connect(pSpinBox, SIGNAL(valueChanged(int)), this, SLOT(SpinBoxChangeImageshow()));
}void Qt_threshold::createAction()
{QAction *openFileAction = new QAction(QIcon("open.png"), tr("open file"), this);    //设置打开文件的动作openFileAction->setShortcut(tr("Ctrl+O"));openFileAction->setStatusTip(tr("open a tiff picture"));QAction *saveFileAction = new QAction(QIcon("save.png"), tr("save file"), this);    //设置保存文件的动作saveFileAction->setShortcut(tr("Ctrl+S"));saveFileAction->setStatusTip(tr("save the result picture"));fileTool = addToolBar("File");                                           //利用QMainWindow的addToolBar()函数增加工具条fileTool->addAction(openFileAction);fileTool->addAction(saveFileAction);fileTool->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);             //限定文件工具条出现的位置,并且不能移动fileTool->setMovable(false);connect(openFileAction, SIGNAL(triggered()), this, SLOT(OpenFile()));connect(saveFileAction, SIGNAL(triggered()), this, SLOT(SaveFile()));
}///----------------------------槽函数//----打开图像---
void Qt_threshold::OpenFile()
{fileName = QFileDialog::getOpenFileName(this, tr("Select Tiff picture"), ".", tr("Image Files(*.tif *.jpg *.bmp)"));if (!fileName.isEmpty()){//-------将QString转换成const char[];string trans = fileName.toLocal8Bit().toStdString();   const char *FileName = trans.c_str();//------使用OpenCV读图originImage = imread(FileName);                  //-----如果图像是彩色图,转为灰度图if (originImage.channels()== 3){QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("图像为彩色图,将转换为灰度图像显示"));cvtColor(originImage, originImage, CV_RGB2GRAY);}if (originImage.depth()!=CV_8U){QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("图像不是8bit图像,本软件只接受8bit图像"));return;}//------将Mat格式的图像传递到QImage的图像中;QImage originImg = QImage((const unsigned char*)(originImage.data),originImage.cols, originImage.rows, QImage::Format_Grayscale8);//------传递原始灰度图显示showwidget->imageLabel1->setPixmap(QPixmap::fromImage(originImg));//-------初始的二值化阈值为80threshold(originImage, binaryImage, 80, 255.0, CV_THRESH_BINARY);QImage binaryImg = QImage((const unsigned char*)(binaryImage.data),binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);//-------传递二值化图像显示showwidget->imageLabel2->setPixmap(QPixmap::fromImage(binaryImg));}else{QMessageBox::information(NULL, tr("Path"), QStringLiteral("未选中任何图像"));          //提示未选中任何路径}}//----------保存图像------//
void Qt_threshold::SaveFile()
{QString savePath = QFileDialog::getSaveFileName(this, tr("Select picture save path"), ".", tr("Image Files(*.bmp)"));if (savePath.isEmpty()){QMessageBox::information(NULL, tr("Path"), tr("You have not select any path."));}string trans = savePath.toLocal8Bit().toStdString();const char *path = trans.c_str();if (imwrite(path, this->binaryImage)){QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("图像写出完毕"));}}//----------spinBox改变时触发的槽函数-----
void Qt_threshold::SpinBoxChangeImageshow()
{int thres = pSpinBox->value();slider->setValue(thres);                  //slider值与spinbox值同步threshold(originImage, binaryImage, thres, 255.0, CV_THRESH_BINARY);//------修改imageLabel2中的图像;QImage binaryImg = QImage((const unsigned char*)(binaryImage.data),binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);showwidget->imageLabel2->setPixmap(QPixmap::fromImage(binaryImg));
}//----------slider改变时触发的槽函数-----
void Qt_threshold::SliderChangeImageshow()
{int thres = slider->value();pSpinBox->setValue(thres);              //slider值与spinbox值同步threshold(originImage, binaryImage, thres, 255.0, CV_THRESH_BINARY);//------修改imageLabel2中的图像;QImage binaryImg = QImage((const unsigned char*)(binaryImage.data),binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);showwidget->imageLabel2->setPixmap(QPixmap::fromImage(binaryImg));
}

main.cpp

//--------main.cpp
//--------潘正宇 2018.04.02#include "qt_threshold.h"
#include <QtWidgets/QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Qt_threshold w;w.show();return a.exec();
}

代码分析

     因为代码标注的非常清楚,很容易理解,我这里就不多讲解了,主要说一下主窗口实现的构造函数。一行一行的来看;

  1. 第一行代码,设置了主窗口的标题;
  2. 第二行代码,调用createAction()函数,在主窗口上添加了工具栏;
  3. 第三行代码,新建一个ShowWidget类动态对象showwidget,这时候调用ShowWidget类的构造函数。动态对象指向的是一个窗体,这个窗体包含四个label;
  4. 第四行代码,构建一个动态窗体对象,用于指向主窗口的中心部件。
  5. 第五行代码,构建一个动态窗体对象,指向包含滑条等部件的窗体。
  6. 第六行代码,调用createChanges()函数,将滑条、微调框等部件放入Change所指的窗体中。
  7. 第七至九行代码,利用垂直布局,将Change和showwidget放置到mainWidget。
  8. 第十行代码,将mainWidget设置为MainWindow的中心部件。

 

已完;


版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/12655.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息