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

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

由于数据具有保密性,这里就不贴效果图了,源代码是使用 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中的个别路径需要读者自行修改;

相关文章
|
4月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
108 0
|
5月前
|
存储 算法 C++
【Qt应用开发】复刻经典:基于Qt实现Windows风格计算器(加减乘除、删除、归零功能全解析)
在Qt中,"栈"的概念主要体现在两个层面:一是程序设计中的数据结构——栈(Stack),二是用户界面管理中的QStackedWidget控件。下面我将分别简要介绍这两个方面:
164 4
|
2月前
|
编译器
【项目开发】QT简单练习之QQ登录界面模仿
为了进一步加深对QT开发的理解,在学习完基础操作之后要进行一个简单的练习。
|
4月前
|
XML Linux 程序员
【Qt】项目代码
【Qt】项目代码
|
7月前
|
编解码 C++
Qt第一课 第一个ui界面
Qt第一课 第一个ui界面
96 2
|
7月前
|
区块链
【qt】最快的开发界面效率——混合编程3
【qt】最快的开发界面效率——混合编程
110 1
|
7月前
【qt】最快的开发界面效率——混合编程2
【qt】最快的开发界面效率——混合编程
85 1
|
7月前
【qt】设计器实现界面
【qt】设计器实现界面
54 1
|
7月前
|
搜索推荐
【qt】自定义界面类
【qt】自定义界面类
66 0
|
7月前
|
数据可视化 开发工具 C++
Qt Creator 界面
Qt Creator 界面