【问题标题】:"Segmentation Fault" while using std::list.back() on a non-empty std::list<int>在非空 std::list<int> 上使用 std::list.back() 时出现“分段错误”
【发布时间】:2019-04-02 14:55:18
【问题描述】:

(注意:对不起我的英语不好......)

大家好, 我的代码 (C++) 需要帮助:我需要使用 OpenCV 从灰度图像中标记区域。

为此,我将一个新矩阵初始化为零。

我搜索第一个 0(未标记的像素),获取坐标并开始递归: 我看看它的 8 个邻居。对于每个:如果像素存在(如果我当前使用的像素不在边缘上),那么如果当前像素与其邻居之间的“距离”低于阈值,则我将其放在同一区域(相同的标签)并将其列在一个列表中。

只要列表不为空,我就会从同一区域选择另一个像素并重新开始(列表中的像素)。

当一个区域不再有可使用的像素时,如果所有像素都没有标记,我会开始一个新区域,依此类推。

所以问题是,在几个像素之后,我得到了一个分段错误,根据 gdb,这是一个来自 std::list.back() 的问题,带有“无法访问内存地址 ...”。

我开始使用 std:list of pair。我现在只是使用带有 2 个 push_front 的 std::list 在列表中添加坐标,然后使用 2 个 back(后跟 pop_back)将它们取回。

我尝试了向量,但没有任何好的结果。

当我使用小图片 (64x64) 时,它可以正常工作。但是当涉及到更大的图片/非方形图片时,我总是会遇到分段错误(使用 gdb,它似乎在“int b = listePix.back()”处)。

谢谢。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <iostream>
#include <stdio.h>
#include <utility>
#include <list>

using namespace cv;
using namespace std;

void agregation(Mat src, Mat dst);
void expendReg(Mat src, Mat dst, int compteur);
pair<int,int> premiereOcc(Mat dst);

std::list <int> listePix;

int seuil = 20;

int main( int argc, char** argv )
{
    Mat image;
    image = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);

    Mat reg = Mat::zeros(image.rows, image.cols, 0);

    agregation(image,reg);

    cout << "WORKED" << endl;

    waitKey(0);
    return 0;
}

void agregation(Mat src, Mat dst){
    bool flag = 0;
    int compteur = 0;

    do{
      compteur++;

      pair<int,int> coord = premiereOcc(dst);

      if(coord.first == -1 || coord.second == -1){
        flag = 1;
      }
      else{
        int pm = coord.first;
        int pn = coord.second;

        dst.at<uchar>(pm,pn) = compteur;
        listePix.push_front(pn);
        listePix.push_front(pm);

        expendReg(src,dst,compteur);
        listePix.clear();
      }
    }while(!flag);
}

void expendReg(Mat src, Mat dst, int compteur){
    if(listePix.size()>=2){

      int b = listePix.back();
      listePix.pop_back();
      int a = listePix.back();
      listePix.pop_back();

      int dist;

      if((a+1)<dst.rows){
          dist = abs(src.at<uchar>(a,b) - src.at<uchar>(a+1,b));
          int temp = dst.at<uchar>(a+1,b);
          if((dist<=seuil) && (temp == 0)){
            dst.at<uchar>(a+1,b) = compteur;
            listePix.push_front(b);
            listePix.push_front(a+1);
          }
      }
      if((b+1)<dst.cols){
          dist = abs(src.at<uchar>(a,b) - src.at<uchar>(a,b+1));
          int temp = dst.at<uchar>(a,b+1);
          if((dist<=seuil) && (temp == 0)){
            dst.at<uchar>(a,b+1) = compteur;
            listePix.push_front(b+1);
            listePix.push_front(a);
          }
      }
      expendReg(src,dst,compteur);
    }
}

pair<int,int> premiereOcc(Mat dst){
  //Return the coord of the first pixel without region
  for(int i = 0; i<dst.rows; i++){
    for(int j = 0; j<dst.cols; j++){
      int tmp = dst.at<uchar>(i,j);
      if(tmp == 0){
        pair<int,int> coord = make_pair(i,j);
        return coord;
      }
    }
  }
  pair<int,int> coord = make_pair(-1,-1);
  return coord;
}

EDIT2:我正在使用的图像:https://www.bogotobogo.com/Matlab/images/MATLAB_DEMO_IMAGES/blobs.png

【问题讨论】:

  • 您执行 2 次调用以弹回,但您只确保大小不为零。如果它只有 1 会发生什么?
  • 如果listePix.size() 是奇数会怎样?您不可避免地会在某些时候得到size(),因此2 个back() 调用将不起作用。
  • 这听起来很奇怪。 minimal reproducible example可以给我们吗?
  • 那么我们需要一个minimal reproducible example。未定义的行为可以以各种方式表现出来,因此它甚至可能不是列表的问题。
  • @LoïcChambrion 你需要发布更少的代码,而不是更多,以获得帮助。这就是您看到Minimal, Complete, and Verifiable example 被请求的原因。 stackoverflow.com 在这里帮助您解决您发现的问题,而不是为您识别问题。在这里,您的问题是 expendReg 被调用 listePix 仅包含 1 个元素。我们无法帮助您从您放在这里的代码中找出原因,因为它不是 MCVE。

标签: c++


【解决方案1】:

我怀疑这里可能发生堆栈溢出,因为:

可能的修复

  • 避免递归并使用迭代方法
  • 限制递归深度

【讨论】:

  • 在“聚合”函数中使用了一段时间,并删除了递归。之后效果很好。现在我面临另一个问题,但这个问题现在已经解决了。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
  • 2014-11-25
相关资源
最近更新 更多