【问题标题】:Segmentation Fault while using MPI and OpenCV together一起使用 MPI 和 OpenCV 时出现分段错误
【发布时间】:2015-05-01 05:17:38
【问题描述】:

我正在尝试学习 C++ 中的 MPI。我对 OpenCV 有一些了解,所以我尝试使用 MPI 和 OpenCV 编写程序。这听起来可能很愚蠢,但为了学习,我尝试在线程 0 上从网络摄像头捕获图像并将图像传递给线程 1 以转换为灰度并显示灰度图像。

这就是我编译代码的方式:
mpic++ opencv.cpp `pkg-config opencv --libs`

代码编译成功,但是当我运行可执行文件时,屏幕上会显示一小段时间,这就是我在终端上看到的内容

~/mpi$ mpirun -np 2 ./a.out
libv4l2: error setting pixformat: Device or resource busy
HIGHGUI ERROR: libv4l unable to ioctl S_FMT
libv4l2: error setting pixformat: Device or resource busy
libv4l1: error setting pixformat: Device or resource busy
HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT

[arch:09670] *** Process received signal *** 
[arch:09670] Signal: Segmentation fault (11)
[arch:09670] Signal code: Address not mapped (1) 
[arch:09670] Failing at address: 0x218ac50
[arch:09670] [ 0] /usr/lib/libpthread.so.0(+0x10740)[0x7f422fcac740]
[arch:09670] [ 1] /usr/lib/libopencv_core.so.2.4(_ZNK2cv11_InputArray6getMatEi+0x203)[0x7f4233c8c113]
[arch:09670] [ 2] /usr/lib/libopencv_imgproc.so.2.4(_ZN2cv8cvtColorERKNS_11_InputArrayERKNS_12_OutputArrayEii+0x50)[0x7f4232c25de0]
[arch:09670] [ 3] ./a.out[0x408f54]
[arch:09670] [ 4] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f422e9e9800]
[arch:09670] [ 5] ./a.out[0x408c19]
[arch:09670] *** End of error message *** 
--------------------------------------------------------------------------
mpirun noticed that process rank 1 with PID 9670 on node arch exited on signal 11 (Segmentation fault).
--------------------------------------------------------------------------

这是代码

#include <opencv2/opencv.hpp>
#include <mpi.h>

int main(int argc, char **argv) {
    cv::Mat_<uint> img(640,480);
    cv::Mat_<uint> gray(640,480);
    cv::VideoCapture cam(0);

    int rank, nproc, j=0;

    MPI_Status status;

    MPI_Init(&argc, &argv);

    // MPI datatype for 8UC3 image
    MPI_Datatype mat_8uc3;
    MPI_Type_contiguous(sizeof(img), MPI_BYTE, &mat_8uc3);
    MPI_Type_commit(&mat_8uc3);

    // MPI datatype for 8UC1 image
    MPI_Datatype mat_8uc1;
    MPI_Type_contiguous(sizeof(gray), MPI_BYTE, &mat_8uc1);
    MPI_Type_commit(&mat_8uc1);

    MPI_Comm_size(MPI_COMM_WORLD, &nproc); // number of processes
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);  // rank of the current process

    /*
     * Thread 0 captures the image from camera
     * and sends the image to process 1 for processing
     * thread 1 converts the image to grayscale and
     * displays the image
     */

    if (rank == 0) {
        // capture the image and send to thread 1
        while (1) { 
            cam >> img;
            cv::imshow("proc 0", img);
            MPI_Send(&img, 1, mat_8uc3, 1, j, MPI_COMM_WORLD);
            cv::waitKey(40);
            j++;
        }
    }
    else if (rank == 1) {
        // receive the image, convert to grayscale and display
        while (1) {
            MPI_Recv(&img, 1, mat_8uc3, 0, j, MPI_COMM_WORLD, &status);
            cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
            cv::imshow("proc 1", gray);
            cv::waitKey(20);
            j++;
        }
    }

    MPI_Finalize();

    return 0;
}

谁能指出我哪里错了

谢谢

编辑:(在 user0815 回答后)

在进行建议的更改时,问题Device or resource busy 已解决,但程序仍会出现段错误。

[arch:01080] *** Process received signal *** 
[arch:01080] Signal: Segmentation fault (11)
[arch:01080] Signal code: Address not mapped (1) 
[arch:01080] Failing at address: 0x16bbf80
[arch:01080] [ 0] /usr/lib/libpthread.so.0(+0x10740)[0x7fea97322740]
[arch:01080] [ 1] /usr/lib/libopencv_core.so.2.4(_ZNK2cv11_InputArray6getMatEi+0x203)[0x7fea9b302113]
[arch:01080] [ 2] /usr/lib/libopencv_imgproc.so.2.4(_ZN2cv8cvtColorERKNS_11_InputArrayERKNS_12_OutputArrayEii+0x50)[0x7fea9a29bde0]
[arch:01080] [ 3] ./a.out[0x408fc3]
[arch:01080] [ 4] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7fea9605f800]
[arch:01080] [ 5] ./a.out[0x408c79]
[arch:01080] *** End of error message *** 
--------------------------------------------------------------------------
mpirun noticed that process rank 1 with PID 1080 on node arch exited on signal 11 (Segmentation fault).
--------------------------------------------------------------------------

【问题讨论】:

  • 看起来其他进程锁定了摄像头。我认为应该有一种方法可以在 cam &gt;&gt; img 行之前验证您对相机的控制权。

标签: c++ opencv parallel-processing segmentation-fault mpi


【解决方案1】:

当前每个进程都试图打开相机。这很可能会导致问题。尝试将开口移动到根特定部分,如下所示:

int main(int argc, char **argv) {
  cv::Mat_<uint> img(640,480);
  cv::Mat_<uint> gray(640,480);
  cv::VideoCapture cam;

  /* ... */
  if (rank == 0) {
    cam.open(0);
    /* ... */
  }
  /* ... */
}

更新:

我认为您的代码的问题在于,您不能简单地使用MPI_Send 传输对象。 sizeof 运算符也对一般对象无效。如果要传输对象,则需要传输底层数据。

您可以通过发送大小为img.rows * img.cols * sizeof(uint)img.data 来实现此目的。然后你也可以使用 MPI_BYTE 作为数据类型,不需要自定义类型。

关于cv::Mat_内部结构的一些细节可以参考here

【讨论】:

    【解决方案2】:

    @user0851 注意到,在您的代码中,所有进程都尝试打开摄像头,而摄像头的打开可以由根进程单独执行。

    openCV 的Mat 对象相当复杂,定义对应的MPI_Datatype 也可能很复杂。相反,发送像素数组img.data 要容易得多。这是一小段代码,演示了它是如何完成的。由mpiCC main.cpp -o main -lopencv_highgui -lopencv_imgproc -lopencv_core编译,mpirun -np 2 main运行

    #include <opencv2/opencv.hpp>
    #include <mpi.h>
    
    using namespace cv;
    
    int main(int argc, char **argv) {
        Mat img;
        Mat gray;
    
    
        int rank, nproc, j=0;
    
        size_t total;
        size_t elemsize;
        int sizes[3];
    
        MPI_Status status;
    
        MPI_Init(&argc, &argv);
    
        MPI_Comm_size(MPI_COMM_WORLD, &nproc); // number of processes
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);  // rank of the current process
    
        /*
         * Thread 0 captures the image from camera
         * and sends the image to process 1 for processing
         * thread 1 converts the image to grayscale and
         * displays the image
         */
    
        if (rank == 0) {
            VideoCapture cam(0);
            if(!cam.isOpened()){
                fprintf(stderr,"unable to open camera.\n");
                exit(1);
            }
            // capture the image and send to thread 1
            while (1) { 
                cam >> img;
                cv::imshow("proc 0", img);
    
                if(j==0){
                    sizes[2]=img.elemSize();
                    Size s = img.size();
                    sizes[0] = s.height;
                    sizes[1] = s.width;
                    MPI_Send( sizes, 3, MPI_INT, 1,0,   MPI_COMM_WORLD);
                }
                MPI_Send( img.data, sizes[0]*sizes[1]*3, MPI_CHAR,1,1, MPI_COMM_WORLD);
                cv::waitKey(40);
                j++;
            }
        }
        else if (rank == 1) {
            // receive the image, convert to grayscale and display
            while (1) {
                if(j==0){
                    MPI_Recv( sizes,3, MPI_INT,0,0, MPI_COMM_WORLD,&status);
                    img.create(sizes[0],sizes[1],CV_8UC3);
                }
                MPI_Recv( img.data, sizes[0]*sizes[1]*3, MPI_CHAR,0,1, MPI_COMM_WORLD,&status);
                cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
                cv::imshow("proc 1", gray);
                cv::waitKey(20);
                j++;
            }
        }
    
        MPI_Finalize();
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      Mat 对象只是一个头结构,指向存储图像的内存。 所以你有一些问题: 首先,您创建一个大小为 640X640 的 Mat 对象,然后从相机读取该对象。但是Mat 只是一个标题它不是指向数据的指针,Mat 对象现在可以是任意宽度和高度。

      其次,sizeof(Mat) 不返回分配给图像的内存量,只返回 Mat 对象本身的内存量。图片所需的内存量为Mat.total()*Mat.elemSize()

      【讨论】:

        猜你喜欢
        • 2014-05-31
        • 2012-01-01
        • 2022-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多