【变化检测】多时相影像变化检测精度评价(附有完整代码)

简介: 【变化检测】多时相影像变化检测精度评价(附有完整代码)

对多时相影像进行精度评估,通常都是使用混淆矩阵求其精确率、漏检率和虚警率;但是要想使用混淆矩阵求上述指标一般都需要知道参考图,也就是在变化检测前知道变化部分和未变化部分,然后用其和变化检测后的结果进行对比,最后求出上述指标;


       道路变化检测使用的往往是矢量数据,即如果想使用变化检测结果和参考图进行对比求变化检测精度指标的话,参考图的生成也必须使用矢量数据;难点在于,道路二值图在进行矢量化时,矢量化结果受道路拓扑结构的影响,从而带来一系列问题,即得到的精度指标和真实情况相差较远;亲测过,在使用道路二值图矢量化结果生成参考图时,未变化部分无法完全重合!!!


       退而求其次,先用道路二值图生成参考图,然后再对参考图进行细化、矢量化操作;此举有原因有二:


(1)生成的参考图相当于把原始道路分为了变化部分和未变化部分两张影像,降低了道路拓扑结构对道路二值图矢量化的影像,使其结果更接近真实情况;


(2)多时相影像中未变化的道路占很大比例,所以针对生成的参考图进行细化、矢量化时,其结果更接近真实情况;


1、生成参考图


(1)制作标签


  我使用的是 labelme 进行打样,标签制作流如下:


       A.在对两幅多时相影像进行打样时,任意挑选其中的一幅影像旧影像(或新影像),对比两幅影像,然后针对未变化部分对旧影像(新影像)进行打样,打样完成后生成的是文件;


       B.对另一幅影像随意打样(随便打两条线即可),目标是为了生成文件;


       C.打开和文件,打开方式选择 vs/记事本 都可以,然后把第一个 .json 文件中的打样数据复制到第二个 .json 中(注意:在复制之前需要把第二个 .json 中的打样数据删掉),并保存;


       D.最后用 labelme 分别打开两个 .json 文件,然后对剩余部分进行打样即可;


       说明:上面做法的目的是,使得两幅多时相影像中未变化部分,使用相同的打样数据,以便后面获取参考图像;


下面举例说明:


下面是使用上述方法生成的多时相影像的道路二值图;

991a58ac622a4bde9811462500f12aee.png


(2)生成参考图


A.生成参考图核心代码

//生成参考图
void myReference::outputImage()
{
  //变化、未变化部分图像,change_images、unchange_images是全局变量
  change_images = Mat::zeros(oldImage.rows, oldImage.cols, CV_8UC3);
  unchange_images = Mat::zeros(oldImage.rows, oldImage.cols, CV_8UC3);
  //把输入的影像读到矩阵中以便显示
  for (int i = 0; i < change_images.rows; i++)
  {
    Vec3b* image1_1 = change_images.ptr<Vec3b>(i);      //变化部分图像
    Vec3b* image2_2 = unchange_images.ptr<Vec3b>(i);    //未变化部分图像
    Vec3b* image3_3 = oldImage.ptr<Vec3b>(i);       //旧影像二值图
    Vec3b* image4_4 = newImage.ptr<Vec3b>(i);       //新影像二值图
    for (int j = 0; j < change_images.cols; j++)
    {
      //变化部分图像
      if ((image4_4[j][0] == 0 && image4_4[j][1] == 0 && image4_4[j][2] == 0) &&
        (image3_3[j][0] != 0 && image3_3[j][1] != 0 && image3_3[j][2] != 0))
      {
        image1_1[j][0] = image3_3[j][0];
        image1_1[j][1] = image3_3[j][1];
        image1_1[j][2] = image3_3[j][2];
      }
      else if ((image4_4[j][0] != 0 && image4_4[j][1] != 0 && image4_4[j][2] != 0) &&
        (image3_3[j][0] == 0 && image3_3[j][1] == 0 && image3_3[j][2] == 0))
      {
        image1_1[j][0] = image4_4[j][0];
        image1_1[j][1] = image4_4[j][1];
        image1_1[j][2] = image4_4[j][2];
      }
      //未变化部分图像
      else if ((image4_4[j][0] != 0 && image4_4[j][1] != 0 && image4_4[j][2] != 0) &&
        (image3_3[j][0] != 0 && image3_3[j][1] != 0 && image3_3[j][2] != 0))
      {
        image2_2[j][0] = image4_4[j][0];
        image2_2[j][1] = image4_4[j][1];
        image2_2[j][2] = image4_4[j][2];
      }
    }
  }
  cv::imwrite("..\\myChangedetection\\image_save\\change_reference.png", change_images);    //保存变化部分
  cv::imwrite("..\\myChangedetection\\image_save\\unchange_reference.png", unchange_images);  //保存未变化部分
    //下面代码主要功能是把结果显示在QT界面中
  cv::resize(change_images, change_images, Size(SIZE_ROW, SIZE_COL));
  cv::resize(unchange_images, unchange_images, Size(SIZE_ROW, SIZE_COL));
  QImage change_img = QImage((const unsigned char*)(change_images.data), change_images.cols, change_images.rows, QImage::Format_RGB888);
  QImage unchange_img = QImage((const unsigned char*)(unchange_images.data), unchange_images.cols, unchange_images.rows, QImage::Format_RGB888);
  label_1->setPixmap(QPixmap::fromImage(change_img));
  label_1->resize(QSize(change_img.width(), change_img.height()));
  label_2->setPixmap(QPixmap::fromImage(unchange_img));
  label_2->resize(QSize(unchange_img.width(), unchange_img.height()));
  /**************** 精度评估 ***************/
  accuracyAssess();
}

B.参考图结果

5ca0328294044090a8cf0aebe12c9b59.png

注:左图是变化部分,有图是未变化部分;

C.参考图矢量化结果

fefb64cda8e340529a9b93a2b5a545d4.png

注:左图是变化部分,有图是未变化部分;

       说明:在生成了参考图后,然后对其进行细化、矢量化操作,最后使用该结果去进行变化检测精度评估;上面给的代码是生成参考图的核心代码,我在实现时使用 QT 将其封装成独立的模块了,如有需要可留言!!!


2、精度评价


根据上述生成的参考图矢量化结果和自己变化检测算法得到的结果进而求变化检测精度评价指标;


(1)精度评估核心代码


//把输入的道路数据细化、矢量化
void myReference::dealImage(QString str1, QString str2)
{
  process.createVectorFromFile(str1, "old_Thin_reference.png");  //旧时相影像栅格数据矢量化
  process.createVectorFromFile(str2, "new_Thin_reference.png");  //新时相影像栅格数据矢量化
  process.simplifyVector(0);    //简化旧影像矢量化结果
  process.simplifyVector(1);    //简化新影像矢量化结果
  //输出简化后的矢量道路数据
  oldImageoutputResult = process.outputBinaryResult(0, "change_Vector_reference.png", ".\\old_vector_result.txt");
  newImageoutputResult = process.outputBinaryResult(1, "unchange_Vector_reference.png", ".\\new_vector_result.txt");
  //注:此时 oldImageoutputResult 中存放的矢量化化结果是单通道矩阵
}
//精度评估
void myReference::accuracyAssess()
{
  //读取变化和未变化部分参考图
  QString str1 = QString::fromStdString("..\\myChangedetection\\image_save\\change_reference.png");
  QString str2 = QString::fromStdString("..\\myChangedetection\\image_save\\unchange_reference.png");
  //参考图像道路数据矢量化
  dealImage(str1, str2);
  Mat old_images, new_images;
  //参考图矢量化结果
  Mat change_image = imread("..\\myChangedetection\\image_save\\change_Vector_reference.png");
  Mat unchange_image = imread("..\\myChangedetection\\image_save\\unchange_Vector_reference.png");
  int accuracy = 0;     //精确率
  int miss_detection = 0;   //漏检率
  int false_alarm = 0;    //虚警率
  int all_roads = 0;      //所有道路
  //读取变化检测结果
  Mat outputResult = imread("..\\myChangedetection\\image_save\\final_all.png");
  for (int i = 0; i < outputResult.rows; i++)
  {
    Vec3b* image1_1 = outputResult.ptr<Vec3b>(i);     //变化检测结果
    Vec3b* image2_2 = change_image.ptr<Vec3b>(i);     //参考图变化部分
    Vec3b* image3_3 = unchange_image.ptr<Vec3b>(i);     //参考图未变化部分
    for (int j = 0; j < outputResult.cols; j++)
    {
      //红色(0, 0, 255)、黄色(0, 255, 255)、绿色(0, 255, 0)
      //正确率—变化部分
      if (((image1_1[j][0] == 0 && image1_1[j][1] == 0 && image1_1[j][2] == 255) || (image1_1[j][0] == 0 && image1_1[j][1] == 255 && image1_1[j][2] == 255)) &&
        (image2_2[j][0] == 255 && image2_2[j][1] == 255 && image2_2[j][2] == 255))
      {
        accuracy++;
        all_roads++;
      }
      //正确率—未变化部分
      else if ((image1_1[j][0] == 0 && image1_1[j][1] == 255 && image1_1[j][2] == 0) &&
        (image3_3[j][0] == 255 && image3_3[j][1] == 255 && image3_3[j][2] == 255))
      {
        accuracy++;
        all_roads++;
      }
      //虚警率
      else if (((image1_1[j][0] == 0 && image1_1[j][1] == 0 && image1_1[j][2] == 255) || (image1_1[j][0] == 0 && image1_1[j][1] == 255 && image1_1[j][2] == 255)) &&
        (image3_3[j][0] == 255 && image3_3[j][1] == 255 && image3_3[j][2] == 255))
      {
        false_alarm++;
        all_roads++;
      }
      //漏检率
      else if ((image1_1[j][0] == 0 && image1_1[j][1] == 255 && image1_1[j][2] == 0) &&
        (image2_2[j][0] == 255 && image2_2[j][1] == 255 && image2_2[j][2] == 255))
      {
        miss_detection++;
        all_roads++;
      }
    }
  }
  double accuracy_rate = (double)accuracy / all_roads;            //精确率
  double miss_detection_rate = (double)false_alarm / all_roads;       //漏检率
  double false_alarm_rate = 1 - accuracy_rate - miss_detection_rate;      //虚警率
  qDebug() << u8"变化检测精确率为:" << accuracy_rate << endl;
  qDebug() << u8"变化检测虚警率为:" << miss_detection_rate / all_roads << endl;
  qDebug() << u8"变化检测漏检率为:" << false_alarm_rate / all_roads << endl;
}

说明:上述代码第一个函数中 :createVectorFromFile、simplifyVector、outputBinaryResult 分别是自己的道路二值图矢量化、矢量化简化、输出矢量化结果函数;


(2)变化检测结果


00067453b35b4706a8ead9687fc2b5f5.png

说明:红色为拆除部分、黄色为新增部分、绿色为未变化部分;


(3)精度评价结果


ac05d5730fa549e6bc08644bb629410f.png

     因为研究内容偏工程,所以基本上所有的内容都使用 VS + QT 封装成独立的模块,由上面给出的代码和显示结果也可以看出; 如果您仅仅需要求变化检测结果,针对上述代码微调足以(主要是路径);


如需要完整代码模块请移步:https://download.csdn.net/download/weixin_47156401/72310899

相关文章
|
6天前
|
机器学习/深度学习 数据可视化 数据库
R语言广义线性模型索赔频率预测:过度分散、风险暴露数和树状图可视化
R语言广义线性模型索赔频率预测:过度分散、风险暴露数和树状图可视化
15 0
|
8月前
|
机器学习/深度学习 传感器 算法
用于准确量化颅面对称性和面部生长的 3D 头影测量方案(Matlab代码实现)
用于准确量化颅面对称性和面部生长的 3D 头影测量方案(Matlab代码实现)
|
3月前
|
算法 数据挖掘
R语言——AVOCADO“(异常植被变化检测)算法(1990-2015数据分析)监测森林干扰和再生(含GEE影像下载代码)
R语言——AVOCADO“(异常植被变化检测)算法(1990-2015数据分析)监测森林干扰和再生(含GEE影像下载代码)
43 1
|
8天前
|
机器学习/深度学习 搜索推荐 数据挖掘
回归树模型分析纪录片播放量影响因素|数据分享
回归树模型分析纪录片播放量影响因素|数据分享
25 9
|
15天前
R语言如何用潜类别混合效应模型(LCMM)分析抑郁症状
R语言如何用潜类别混合效应模型(LCMM)分析抑郁症状
19 0
|
15天前
R语言估计多元标记的潜过程混合效应模型(lcmm)分析心理测试的认知过程
R语言估计多元标记的潜过程混合效应模型(lcmm)分析心理测试的认知过程
33 0
|
16天前
R语言逐步多元回归模型分析长鼻鱼密度影响因素
R语言逐步多元回归模型分析长鼻鱼密度影响因素
21 0
|
6月前
典型偏差和非典型偏差练习
典型偏差和非典型偏差练习
43 5
|
6月前
|
项目管理
典型偏差和非典型偏差
典型偏差和非典型偏差。
83 2
|
8月前
|
机器学习/深度学习 传感器 算法
垂直腔表面发射激光器极化噪声的建模与分析论文复现
垂直腔表面发射激光器极化噪声的建模与分析论文复现