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

16 篇文章 10 订阅
10 篇文章 9 订阅

fishing-panhttps://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_OBJECT

public:
	explicit ShowWidget(QWidget *parent = 0);
	QImage img;

	QLabel *originLabel;     //label1
	QLabel *binaryLabel;     //label2
	QLabel *imageLabel1;     //label3
	QLabel *imageLabel2;     //label4

	QWidget *Widget1;        //存放label1与label3的widget
	QWidget *Widget2;        //存放label2与label5的widget


signals:
	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_OBJECT

public:
	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;           //label5
	QLabel *maxVauleLabel;           //label6

	QToolBar *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));

		//-------初始的二值化阈值为80
		threshold(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的中心部件。

 

已完;


  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值