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

前言

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

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

工程配置

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

软件界面

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

界面分析

上图左上角的读入、保存按键是用以读入原始图像和保存二值化的结果图的,图中公有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的中心部件。

已完;

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

  1. opencv 图像分割 阈值分割 图像二值化 灰度图

    # -*- coding: utf-8 -*- """ @File : 191213_测试_阈值分割.py @Time : 2019/12/13 15:14 @Autho ...

  2. 【医学图像处理】 2 灰度直方图、图像二值化(阈值分割)

    文章目录 1 灰度直方图 1.1 直方图理解 1.2 直方图计算 1.3 直方图均衡化 1.3.1 全局均衡化 1.3.2 自适应(局部)均值化 2 图像二值化(阈值分割) 2.1 二值化理解 2.2 ...

  3. 【OpenCV 4开发详解】图像二值化

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  4. python opencv二值化图像_python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘...

    python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘 python opencv 1,读取图像 2,图像变矩阵 3,图像转灰度图像 4,彩色图像是3D数组 5,灰度图像是2 ...

  5. OpenCV删除面积小的区域 实现图像二值化分割 标记连通区域

    OpenCV删除面积小的区域 实现图像二值化分割 标记连通区域    [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/781 ...

  6. OpenCV+python:图像二值化

    1,图像二值化概念及方法 一个像素点的颜色是由RGB三个值来表现的,所以一个像素点矩阵对应三个颜色向量矩阵,分别是R矩阵,G矩阵,B矩阵,它们也都是同样大小的矩阵. 在图像处理中,用RGB三个分量(R ...

  7. Python使用openCV把原始彩色图像转化为灰度图、使用OpenCV把图像二值化(仅仅包含黑色和白色的简化版本)、基于自适应阈值预处理(adaptive thresholding)方法

    Python使用openCV把原始彩色图像转化为灰度图.使用OpenCV把图像二值化(仅仅包含黑色和白色的简化版本).基于自适应阈值预处理(adaptive thresholding)方法 目录

  8. opencv进阶学习9:图像阈值大全,图像二值化,超大图像二值化

    基础版笔记链接: python3+opencv学习笔记汇总目录(适合基础入门学习) 进阶版笔记目录链接: python+opencv进阶版学习笔记目录(适合有一定基础) 基础版二值化讲解 opencv ...

  9. 用python怎么样实现图像二值化_使用Python+OpenCV如何实现图像二值化

    使用Python+OpenCV如何实现图像二值化 发布时间:2020-10-26 14:15:52 来源:亿速云 阅读:77 作者:蛋片鸡 这篇文章运用简单易懂的例子给大家介绍使用Python+Ope ...

最新文章

  1. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?...
  2. 【NLP】Prompt-Tuning这么好用?
  3. 2005年的最后一天
  4. asp.net 返回上一页的实现方法小集
  5. asyncexec_如何安全使用SWT的显示器asyncExec
  6. 《TCP/IP详解》学习笔记(六):UDP 协议
  7. 九章算法 | Facebook 面试题 : Backpack VI 背包算法
  8. linux+date+命令+作业,Linux date命令
  9. 好记性不如烂笔头——.NET运行原理
  10. 神经网络工具箱——nn.funtional、初始化策略
  11. 计算机网络中的mac全称,计算机网络中MAC地址与IP地址
  12. linux内核程序运行在哪里,linux内核 – 设备驱动程序代码在哪里执行?内核空间还是用户空间?...
  13. 开启智慧新生活 新余市智慧城市建设全省率先
  14. 使用Java的MessageDigest实现MD5加密算法
  15. fft和freqz的区别
  16. 打开其他软件时,老是弹出Xftp6安装的问题
  17. sql server order by 的一些高级用法
  18. win10系统mysql重新配置密码
  19. 如何通过Android日历api插入日程(事件)和提醒(通知)
  20. 经典网络结构 (八):轻量化网络 (SqueezeNet, MobileNet, ShuffleNet)

热门文章

  1. 一个Python练习
  2. 一句话讲明白 WebAssembly、微前端等技术背后的核心
  3. TypeScript BigInt
  4. 使用 lsof 代替 Mac OS X 中的 netstat 查看占用端口的程序
  5. 【熊猫多模式站群开发日志】流程总览
  6. Q#–一个新年愿望清单
  7. C#LeetCode刷题之#453-最小移动次数使数组元素相等(Minimum Moves to Equal Array Elements)
  8. C#LeetCode刷题之#217-存在重复元素(Contains Duplicate)
  9. angular 模块构建_如何通过11个简单的步骤从头开始构建Angular 8应用
  10. 如何使用Bootstrap Modal和jQuery AJAX创建登录功能