由于数据具有保密性,这里就不贴效果图了,源代码是使用 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 版权协议,转载请附上原文出处链接和本声明。