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