2015-02-28 3 views
1

Я пытаюсь изучить MPI в C++. У меня есть некоторые знания OpenCV, поэтому я попытался написать программу, используя как MPI, так и OpenCV. Это может показаться глупым, но с целью обучения я попытался захватить изображение с веб-камеры на потоке 0 и передал изображение в поток 1 для преобразования в оттенки серого и отображения изображения в градациях серого.Ошибка сегментации при использовании MPI и OpenCV вместе

Это, как я скомпилировать код:
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; 
} 

Может кто-то отметить порога е я буду неправильно

Благодарности

EDIT: (после ответа user0815 в)

О внесении предлагаемых изменений проблема Device or resource busy будет решена, но программа все еще дает Segfault.

[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). 
-------------------------------------------------------------------------- 
+1

Похоже, что какой-либо другой процесс имеет замок на камере. Я думаю, что должен быть способ проверить, что вы контролируете камеру перед линией 'cam >> img'. –

ответ

2

В настоящее время каждый процесс пытается открыть камеру. Это может вызвать проблемы. Попробуйте переместить отверстие в конкретной секции корня следующим образом:

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); 
    /* ... */ 
    } 
    /* ... */ 
} 

Update:

Я думаю, что проблема с вашим кодом в том, что вы не можете просто передать объекты с MPI_Send. Также оператор sizeof не действует на объекты вообще. Если вы хотите перенести объект, вам необходимо передать базовые данные.

Вы можете добиться этого в своем случае, отправив img.data размером img.rows * img.cols * sizeof(uint). Затем вы также можете использовать MPI_BYTE в качестве типа данных, и не требуется никаких настраиваемых типов.

Некоторые детали о внутренней структуре cv::Mat_ можно найти here.

0

Как заметил @ user0851, в вашем коде все процессы пытаются открыть камеру, и открытие камеры может выполняться только корневым процессом.

Объект openCV довольно сложный, и определение соответствующего 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; 
} 
0

объекта Мат является только структура заголовка, который указывает на память, которая хранит изображение. Итак, у вас есть некоторые проблемы: Во-первых, вы создаете объект Mat размером 640X640 и чем вы читаете с камеры на этот объект.Но Mat - это просто заголовок, который не является указателем на данные, объект Mat может быть теперь любой ширины и высоты.

Во-вторых, sizeof(Mat) не возвращает объем памяти, выделенный изображению, а только объем памяти сам объект Mat. Объем памяти, необходимый для изображения, равен Mat.total()*Mat.elemSize()

Смежные вопросы