【变化检测】多时相遥感影像变化检测 Qt界面可视化 / 实现卷帘功能(附有完整代码)

  • Post author:
  • Post category:其他



由于数据具有保密性,这里就不贴效果图了,源代码是使用 c++ 实现的;


卷帘功能版本3源代码链接:

多时相遥感影像变化检测卷帘功能.zip-C++文档类资源-CSDN下载

1、卷帘功能版本1,实现效果如下:


输入的两张图片并行显示,通过拉杆,使一张图片移动,移动到两张图片完全重合时,显示变化检测效果;

2、卷帘功能版本2,实现效果如下:


输入的两张图片重叠显示,通过拉杆,边拉边显示变化检测效果;

3、卷帘功能版本3,实现效果如下:


版本3和版本2效果类似;


版本3相比版本2的优点:


(1)版本3大大压缩了代码量;


(2)在拉动拉杆显示变化检测效果时,效率上大大提高,版本2显示时略有延迟;


(3)版本3优化了版本2中的一些 bug;


4、下面给出版本2的代码


(1)myPullcurtain.h 文件

#pragma once
#pragma execution_character_set("utf-8")	//防止界面中中文显示乱码

#include "ui_myPullcurtain.h"


#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include "opencv2\imgproc\types_c.h"

#include <gdal_priv.h>
#include <gdal.h>
#include <QGraphicsView>
#include <QWidget>
#include <QVector>
#include <QLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QFileInfo>
#include <QFile>
#include <QSlider>
#include <QSpinBox>
#include <QComboBox>
#include <QLabel>
#include <QPixmap>
#include <QProgressBar>
#include <QDebug>
#include <cstring>
#include <QTimer>
#include <iostream>
#include <fstream>
#include <QBrush>
#include <QLineEdit>
#include <QFrame>

const int IMAGE_ROW = 800;
const int IMAGE_COL = 800;

using namespace std;
using namespace cv;


class myPullcurtain : public QWidget
{
	Q_OBJECT

public:
	myPullcurtain(QWidget* parent = Q_NULLPTR);
	~myPullcurtain();

	//版本2

    //初始化UI
	void initUI_1();	

    //初始化信号槽				            				
	void initSignalSlots_1();	

    //输入旧影像						
	void addOldImage_1();

    //输入新影像
	void addNewImage_1();

    //拖动滑条槽函数
	void pullCurttainSliderChanged_1();

    //点击按钮槽函数
	void pullCurttainSpinBoxChanged_1(double value);

    //移动图像
	void imagePropotionChanged_1(double value);	

    //重置图像		
	void pullCurttainReset_1();
	

private:

	Ui::myPullcurtain ui;

	//界面内容
	QVBoxLayout* VLayout;
	QHBoxLayout* HLayout_1;
	QHBoxLayout* HLayout_2;
	QHBoxLayout* HLayout_3;
	QHBoxLayout* HLayout_4;
	QHBoxLayout* HLayout_5;
	QHBoxLayout* HLayout_6;

	//图像部分
	QLabel* imageLabel_1;						//文字说明
	QLabel* imageLabel_2;						//文字说明

	QLineEdit* oldImageLine;
	QLineEdit* newImageLine;

	//QComboBox* imageComboBox;
	QPushButton* addOldImagePushButton;			//添加新影像
	QPushButton* addNewImagePushButton;			//添加旧影像

	QLabel* label_1;
	QLabel* label_2;
	QString imagePath_1;
	QString imagePath_2;

	Mat image2;									//变化检测结果
	Mat image_1, image_1_1;						//图像处理
	Mat image_2, image_2_2;

	//图例
	QLabel* line_1;								//用于显示变化检测后道路提示
	QLabel* line_2;
	QLabel* line_3;

	QLabel* lineLabel_1;
	QLabel* lineLabel_2;
	QLabel* lineLabel_3;


	//拉杆部分
	QLabel* pullCurttainLabel;
	QSlider* pullCurttainSlider;
	QSpinBox* pullCurttainSpinBox;
	QPushButton* pullCurttainResetPushButton;
};


(2)myPullcurtain.cpp 文件

#include "myPullcurtain.h" 

using namespace std;
using namespace cv;


myPullcurtain::myPullcurtain(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	this->setWindowTitle("拉帘子");

	//版本2
	this->resize(1600, 950);
	initUI_1();
	initSignalSlots_1();
}


/***************************变换检测显示版本2*************************/

//初始化UI版本2
void myPullcurtain::initUI_1()
{
	//图像部分
	imageLabel_1 = new QLabel(tr("输入旧影像"), this);

	imageLabel_1->setFixedHeight(30);
	imageLabel_1->setFixedWidth(120);

	//imageComboBox = new QComboBox(this);
	oldImageLine = new QLineEdit(this);
	oldImageLine->setDisabled(true);			//使路径栏中的内容无法修改

	addOldImagePushButton = new QPushButton(tr("&添加影像"), this);

	addOldImagePushButton->setFixedHeight(30);
	addOldImagePushButton->setFixedWidth(120);


	//设置控件的位置,从(0,0)位置开始(即为最左上角的点),显示一个(宽,高)的界面
	imageLabel_1->setGeometry(50, 20, 120, 30);
	oldImageLine->setGeometry(170, 20, 480, 30);
	addOldImagePushButton->setGeometry(670, 20, 120, 30);

	//imageComboBox->setGeometry(170, 20, 1240, 30);


	imageLabel_2 = new QLabel(tr("输入新影像"), this);
	imageLabel_2->setFixedHeight(30);
	imageLabel_2->setFixedWidth(120);

	newImageLine = new QLineEdit(this);
	newImageLine->setDisabled(true);

	addNewImagePushButton = new QPushButton(tr("&添加影像"), this);
	addNewImagePushButton->setFixedHeight(30);
	addNewImagePushButton->setFixedWidth(120);

	//设置控件的位置,从(0,0)位置开始(即为最左上角的点),显示一个(宽,高)的界面
	imageLabel_2->setGeometry(810, 20, 120, 30);
	newImageLine->setGeometry(930, 20, 480, 30);
	addNewImagePushButton->setGeometry(1430, 20, 120, 30);


	//添加 QLabel 存放图片
	label_1 = new QLabel(this);
	label_1->setGeometry(416, 66, 768, 768);
	label_2 = new QLabel(this);
	label_2->setGeometry(416, 66, 768, 768);


	//添加图例
	QLabel* label_1 = new QLabel(this);
	QLabel* label_2 = new QLabel(this);
	QLabel* label_3 = new QLabel(this);

	label_1->setFrameStyle(QFrame::HLine | QFrame::Raised);
	label_1->setFixedWidth(100);
	label_1->setFixedHeight(5);
	label_1->setStyleSheet("background-color:green");
	label_1->move(1300, 90);

	label_2->setFrameStyle(QFrame::HLine | QFrame::Raised);
	label_2->setFixedWidth(100);
	label_2->setFixedHeight(5);
	label_2->setStyleSheet("background-color:red");
	label_2->move(1300, 130);

	label_3->setFrameStyle(QFrame::HLine | QFrame::Raised);
	label_3->setFixedWidth(100);
	label_3->setFixedHeight(5);
	label_3->setStyleSheet("background-color:yellow");
	label_3->move(1300, 170);

	/*line_1->setGeometry(1300, 80, 100, 2);
	line_2->setGeometry(1300, 120, 100, 2);
	line_3->setGeometry(1300, 160, 100, 2);*/


	//添加注释
	lineLabel_1 = new QLabel(tr("未变化道路"), this);
	lineLabel_2 = new QLabel(tr("拆除道路"), this);
	lineLabel_3 = new QLabel(tr("新增道路"), this);
	lineLabel_1->setGeometry(1410, 80, 120, 30);
	lineLabel_2->setGeometry(1410, 120, 120, 30);
	lineLabel_3->setGeometry(1410, 160, 120, 30);


	//拉杆部分
	pullCurttainLabel = new QLabel(tr("修改比例"), this);
	pullCurttainLabel->setFixedWidth(120);

	pullCurttainSlider = new QSlider(this);
	pullCurttainSlider->setOrientation(Qt::Orientation::Horizontal);	//设置滑条方向
	pullCurttainSlider->setMinimum(0);
	pullCurttainSlider->setMaximum(10000);
	pullCurttainSlider->setSingleStep(1);			//鼠标拖动时的步长

	//pullCurttainSpinBox = new QDoubleSpinBox(this);
	pullCurttainSpinBox = new QSpinBox(this);
	pullCurttainSpinBox->setMinimum(0);
	pullCurttainSpinBox->setMaximum(100);
	pullCurttainSpinBox->setSingleStep(1);		//点击按钮时的步长

	pullCurttainResetPushButton = new QPushButton(tr("&重置图像"), this);
	pullCurttainResetPushButton->setFixedWidth(120);

	pullCurttainLabel->setGeometry(50, 850, 120, 30);
	pullCurttainSlider->setGeometry(170, 850, 1110, 30);
	pullCurttainSpinBox->setGeometry(1310, 850, 100, 30);
	pullCurttainResetPushButton->setGeometry(1430, 850, 120, 30);

}


//初始化信号槽版本2
void myPullcurtain::initSignalSlots_1()
{
	connect(addOldImagePushButton, &QPushButton::clicked, this, &myPullcurtain::addOldImage_1);
	connect(addNewImagePushButton, &QPushButton::clicked, this, &myPullcurtain::addNewImage_1);

	//声明区分重载函数
	void (QSpinBox:: * funSignal)(int) = &QSpinBox::valueChanged;
	//void (QDoubleSpinBox:: * funSignal)(double) = &QDoubleSpinBox::valueChanged;
	//void (*valueChangedSignal)(double) = &QDoubleSpinBox::valueChanged;

	connect(pullCurttainSlider, &QSlider::sliderReleased, this, &myPullcurtain::pullCurttainSliderChanged_1);
	connect(pullCurttainSpinBox, funSignal, this, &myPullcurtain::pullCurttainSpinBoxChanged_1);
	connect(pullCurttainResetPushButton, &QPushButton::clicked, this, &myPullcurtain::pullCurttainReset_1);
}


//添加旧图像版本2
void myPullcurtain::addOldImage_1()
{
	//返回的绝对路径中的就是反斜线
	QString fileUrl = QFileDialog::getOpenFileName(this, "选择图片", "",
		tr("Images(*.png *.bmp *.jpg *.tif *.GIF)"));

	imagePath_1 = fileUrl;	//复制旧影像的绝对路径,在后面使用

	if (fileUrl.isEmpty())
		return;
	else
	{
		//imageComboBox->addItem(fileUrl);				//添加下拉项
		oldImageLine->setText(fileUrl);

		string str_1 = fileUrl.toStdString();			//将fileUrl转变为string类型	

		image_1 = imread(str_1);

		cvtColor(image_1, image_1, CV_BGR2RGB);			//转换色彩空间,把RGB转为BGR

		cv::resize(image_1, image_1_1, Size(768, 768));	//重新设置图片尺寸

		//把 Mat 转换成 QImage
		QImage img_1 = QImage((const unsigned char*)(image_1_1.data), image_1_1.cols, image_1_1.rows, QImage::Format_RGB888);

		label_1->setPixmap(QPixmap::fromImage(img_1));

		//设定 Label 尺寸
		label_1->resize(QSize(img_1.width(), img_1.height()));
	}
}


//添加新图像版本2
void myPullcurtain::addNewImage_1()
{
	//返回的绝对路径中的就是反斜线
	QString fileUrl = QFileDialog::getOpenFileName(this, "选择图片", "",
		tr("Images(*.png *.bmp *.jpg *.tif *.GIF)"));

	imagePath_2 = fileUrl;	//复制新影像的绝对路径,在后面使用

	if (fileUrl.isEmpty())
		return;
	else
	{
		//imageComboBox->addItem(fileUrl);				//添加下拉项
		newImageLine->setText(fileUrl);

		string str_1 = fileUrl.toStdString();			//将fileUrl转变为string类型	

		image_2 = imread(str_1);

		cv::resize(image_2, image_2_2, Size(768, 768));	//重新设置图片尺寸

		cvtColor(image_2_2, image_2_2, CV_BGR2RGB);			//转换色彩空间,把RGB转为BGR

		//把 Mat 转换成 QImage
		QImage img_1 = QImage((const unsigned char*)(image_2_2.data), image_2_2.cols, image_2_2.rows, QImage::Format_RGB888);

		label_2->setPixmap(QPixmap::fromImage(img_1));

		//设定 Label 尺寸
		label_2->resize(QSize(img_1.width(), img_1.height()));
	}
}


//拖动滑条触发槽函数版本2
void myPullcurtain::pullCurttainSliderChanged_1()
{
	//滑动滑条更新按钮框的数据
	int value = pullCurttainSlider->value();		//滑杆数据
	pullCurttainSpinBox->setValue(((double)value) / 100.0);

	imagePropotionChanged_1(((double)value) / 10000.0);
}


//点击按钮触发槽函数版本2
void myPullcurtain::pullCurttainSpinBoxChanged_1(double value)
{
	//点击按钮更新滑条进度
	pullCurttainSlider->setValue((int)(value * 100));

	imagePropotionChanged_1(value / 100.0);
}


//移动图像版本2
void myPullcurtain::imagePropotionChanged_1(double value)
{
	double length = 416 + value * 768;		 //移动后的左上角位置

	if (imagePath_2.isEmpty())
		return;
	else
	{	
		label_2->setPixmap(QPixmap(""));			 // QLabel 中的图像清空
		label_2->update();							 //更新 label 

		string str_2 = imagePath_2.toStdString();	 // 将fileUrl转变为string类型;

		Mat img_2 = imread(str_2);

		cvtColor(img_2, img_2, CV_BGR2RGB);			 //转换色彩空间

		Mat image_1;

		cv::resize(img_2, image_1, Size(768, 768));

		//对修改尺寸后的图片进行裁剪,索引为左闭右开
		//此处存在 Bug ,value * 768 不能够进行取整,否则无法和拉杆比例保持一致,导致报错
		//解决办法 把图片的尺寸设法使value * 768为整数即可
		Mat image_2 = image_1(Range(0, image_1.rows), Range(value * 768, image_1.cols));

		label_2->setGeometry(length, 66, image_2.cols, image_2.rows);		//设置图片的位置

		imwrite("..//myChangedetection//Picture1.png", image_2);

		Mat image_3 = imread("..//myChangedetection//Picture1.png");

		// QLabel image_2.cols * image_2.channels() 是为了去除 4 字节对其限制
		QImage imgs = QImage((const unsigned char*)(image_3.data), image_3.cols, image_3.rows, image_3.cols * image_3.channels(), QImage::Format_RGB888);

		label_2->setPixmap(QPixmap::fromImage(imgs));
		label_2->resize(QSize(imgs.width(), imgs.height()));
	}
	     
	if (imagePath_1.isEmpty())
		return;
	else
	{
		label_1->update();								//更新 label 中的图像数据

		string str = imagePath_1.toStdString();			// 将fileUrl转变为string类型;	

		Mat image1 = imread(str);

		Mat image2 = imread("..\\myChangedetection\\image_save\\final_all.png");

		//把变化检测的结果写在原图中,CV_8UC3
		for (int i = 0; i < image2.rows; i++)
		{
			Vec3b* image1_1 = image1.ptr<Vec3b>(i);
			Vec3b* image2_2 = image2.ptr<Vec3b>(i);

			for (int j = 0; j < length; j++)
			{
				//变化检测结果中只要有一个通道的像素值不为零,其肯定是道路
				if (image2_2[j][0] != 0 || image2_2[j][1] != 0 || image2_2[j][2] != 0)
				{
					image1_1[j][0] = image2_2[j][0];
					image1_1[j][1] = image2_2[j][1];
					image1_1[j][2] = image2_2[j][2];
				}
			}
		}

		cvtColor(image1, image1, CV_BGR2RGB);

		Mat images;

		cv::resize(image1, images, Size(768, 768));

		QImage img = QImage((const unsigned char*)(images.data), images.cols, images.rows, QImage::Format_RGB888);

		label_1->setPixmap(QPixmap::fromImage(img));

		label_1->resize(QSize(length, img.height()));
	}
}


//重置图像
void myPullcurtain::pullCurttainReset_1()
{
	label_2->move(416, 66);							//把图像移动到原来的位置

	string str = imagePath_1.toStdString();			// 将fileUrl转变为string类型;	

	Mat image1 = imread(str);

	cvtColor(image1, image1, CV_BGR2RGB);

	Mat images;

	cv::resize(image1, images, Size(768, 768));

	QImage img = QImage((const unsigned char*)(images.data), images.cols, images.rows, QImage::Format_RGB888);

	label_1->setPixmap(QPixmap::fromImage(img));

	label_1->resize(QSize(img.width(), img.height()));

	pullCurttainSlider->setValue(0);		//滑条置零
	pullCurttainSpinBox->setValue(0);		//按钮框置零
}


myPullcurtain::~myPullcurtain()
{
}


注意:


(1)上述新建的是 Add QT Class 类;


(2)上述版本2中的个别路径需要读者自行修改;



版权声明:本文为weixin_47156401原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。