2010-10-11 14 views
0

Je veux partager entre deux processus linux un objet CvMat (une matrice dans la bibliothèque OpenCV), pour cela j'utilise la mémoire partagée. Un processus (serveur) capture une image (matrice) de la webcam, la convertit en échelle de gris, la partage à l'aide de la mémoire partagée et affiche le cadre sur l'écran. L'autre processus (client) lira le cadre partagé et effectuera certaines opérations. Voir le code ci-dessous.matrice opencv dans la mémoire partagée

Le problème semble être que le client ne lit pas les informations car les lignes 'et' cols 'sont nulles (ou le serveur n'écrit pas dans la mémoire partagée). De toute façon, je ne reçois aucun message d'erreur et je ne sais pas ce que je fais mal. Une idée?

Merci beaucoup!


Voici le code du serveur:

#include <iostream> 
#include <cv.h> 
#include <highgui.h> 
using namespace std; 

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 

#include "2cam.h" 

int sizeofmat(CvMat *mat) { 
    return mat->rows * mat->cols * CV_ELEM_SIZE(mat->type); 
} 

int main() { 
    int shmid; 
    key_t key = 5678; 

    CvMat *vdisp = cvCreateMat(240, 320, CV_8U); 
    const size_t vdispsize = sizeofmat(vdisp); 
    CvMat *s = cvCreateMat(240, 320, CV_8U); 
    CvMat stub; 
    CvSize imageSize = cvSize(320, 240); 

    IplImage *color = cvCreateImage(imageSize, 8, 3); 
    IplImage *gray = cvCreateImage(imageSize, 8, 1); 

    /* Create the segment */ 
    if ((shmid = shmget(key, vdispsize, IPC_CREAT | 0666)) < 0) { 
     perror("shmget"); 
     exit(1); 
    } 

    /* Attach the segment to our data space */ 
    if ((vdisp = (CvMat *)shmat(shmid, NULL, 0)) == (CvMat *)-1) { 
     perror("shmat"); 
     exit(1); 
    } 

    /* Put CvMat into the memory to be read for other processes */ 
    s = vdisp; 

    /* Create camera */ 
    Camera c("/dev/video0", 320, 240, 30); 

    while (1) { 
     /* Get one frame */ 
     c.Update(); 
     c.toIplImage(color); 

     /* Convert color frame to grayscale */ 
     cvCvtColor(color, gray, CV_BGR2GRAY); 

     /* Get matrix from the gray frame and write the matrix in shared memory*/ 
     s = cvGetMat(gray, &stub, 0, 0); 

     /* Show frame */ 
     cvNamedWindow("result", CV_WINDOW_AUTOSIZE); 
     cvShowImage("result", s); 

     /* Wait for escape key */ 
     if ((cvWaitKey(10) & 255) == 27) 
      break; 
    } 

    /* free memory */ 
    cvDestroyWindow("result"); 
    cvReleaseImage(&color); 
    cvReleaseImage(&gray); 
    //cvReleaseMat(&vdisp); 
    //cvReleaseMat(&s); 

    return 0; 
} 

Et voici le code du client:

#include <iostream> 
#include <cv.h> 
#include <highgui.h> 
using namespace std; 

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 

int sizeofmat(CvMat *mat) { 
    return mat->rows * mat->cols * CV_ELEM_SIZE(mat->type); 
} 

int main() { 
    int shmid; 
    key_t key = 5678; 

    CvMat *vdisp = cvCreateMat(240, 320, CV_8U); 
    const size_t vdispsize = sizeofmat(vdisp); 
    CvMat *s = cvCreateMat(240, 320, CV_8U); 

    /* Locate the segment */ 
    if ((shmid = shmget(key, vdispsize, 0666)) < 0) { 
     perror("shmget"); 
     exit(1); 
    } 

    /* Now we attach the segment to our data space */ 
    if ((vdisp = (CvMat *)shmat(shmid, NULL, 0)) == (CvMat *) -1) { 
     perror("shmat"); 
     exit(1); 
    } 

    s = vdisp; 

    cout << "rows: " << s->rows << endl; 
    cout << "cols: " << s->cols << endl; 

    return 0; 
} 
+0

Vous ne pouvez pas utiliser des threads à la place? – karlphillip

+0

ouais! pas de problème, mais c'est un projet personnel, j'ai donc décidé d'utiliser la mémoire partagée pour apprendre comment ça fonctionne. Merci pour la suggestion en passant. –

+0

Si vous le voulez fonctionnel et rapide, utilisez simplement 'shmsrc' et' shmsink' de gstreamer (exemple OpenCV: https://github.com/tik0/mat2gstreamer) – Tik0

Répondre

1

Merci à larsmans, qu'il m'a orienté dans la bonne direction. De toute façon, je me suis répondu juste au cas où quelqu'un aurait besoin de la même solution.


Ici, il est le code du serveur:

#include <iostream> 
#include <cv.h> 
#include <highgui.h> 
using namespace std; 

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 

#include "2cam.h" 

int sizeofmat(CvMat *mat) { 
    return mat->rows * mat->step; 
} 

int main() { 
    int shmid; 
    key_t key = 5678; 

    uchar *vdisp; 
    CvMat *s = cvCreateMat(240, 320, CV_8U); 
    CvMat *tmp = cvCreateMat(240, 320, CV_8U); 
    const size_t vdispsize = sizeofmat(s); 
    CvMat stub; 
    CvSize imageSize = cvSize(320, 240); 

    IplImage *color = cvCreateImage(imageSize, 8, 3); 
    IplImage *gray = cvCreateImage(imageSize, 8, 1); 

    /* Create the segment */ 
    if ((shmid = shmget(key, vdispsize, IPC_CREAT | 0666)) < 0) { 
     perror("shmget"); 
     exit(1); 
    } 

    /* Attach the segment to our data space */ 
    if ((vdisp = (uchar *) shmat(shmid, NULL, 0)) == (uchar *) -1) { 
     perror("shmat"); 
     exit(1); 
    } 

    s->data.ptr = vdisp; 

    /* Create camera */ 
    Camera c("/dev/video0", 320, 240, 30); 

    while (1) { 
     /* Get one frame */ 
     c.Update(); 
     c.toIplImage(color); 

     /* Convert color frame to grayscale */ 
     cvCvtColor(color, gray, CV_BGR2GRAY); 

     /* Get matrix from the gray frame and write the matrix in shared memory*/ 
     tmp = cvGetMat(gray, &stub, 0, 0); 

     for (int row = 0; row < tmp->rows; row++) { 
      const uchar* ptr = (const uchar*) (tmp->data.ptr + row * tmp->step); 
      memcpy((uchar*)(s->data.ptr + row * s->step), ptr, tmp->step); 
     } 

     /* Show frame */ 
     cvNamedWindow("result", CV_WINDOW_AUTOSIZE); 
     cvShowImage("result", s); 

     /* Wait for escape key */ 
     if ((cvWaitKey(10) & 255) == 27) 
      break; 
    } 

    /* free memory */ 
    cvDestroyWindow("result"); 
    cvReleaseImage(&color); 
    cvReleaseImage(&gray); 

    return 0; 
} 

Voici le code du client:

#include <iostream> 
#include <cv.h> 
#include <highgui.h> 
using namespace std; 

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 

int sizeofmat(CvMat *mat) { 
    return mat->rows * mat->step; 
} 

int main() { 
    int shmid; 
    key_t key = 5678; 

    uchar *vdisp; 
    CvMat *s = cvCreateMat(240, 320, CV_8U); 
    const size_t vdispsize = sizeofmat(s); 

    /* Locate the segment */ 
    if ((shmid = shmget(key, vdispsize, 0666)) < 0) { 
     perror("shmget"); 
     exit(1); 
    } 

    /* Now we attach the segment to our data space */ 
    if ((vdisp = (uchar *)shmat(shmid, NULL, 0)) == (uchar *) -1) { 
     perror("shmat"); 
     exit(1); 
    } 

    s->data.ptr = vdisp; 

    cvNamedWindow("result", CV_WINDOW_AUTOSIZE); 
    cvShowImage("result", s); 

    cvWaitKey(10000); 

    cvDestroyWindow("result"); 

    return 0; 
} 
+0

OK, mais en cas d'envoi d'une image à 3 canaux (pas grise image), comment pouvez-vous le faire? – user1098761

0

Il devrait être comme ça, si vous utilisez Boost Interprocess.

if(argv[1] = SERVER){ 

    struct shm_remove{ 
    shm_remove() {shared_memory_object::remove("SharedMemoryForCvMat"); } 
    ~shm_remove(){shared_memory_object::remove("SharedMemoryForCvMat"); } 
    }remover; 

    shared_memory_object shm (create_only,"SharedMemoryForCvMat",read_write); 
    shm.truncate(widht*height*channel); 
    mapped_region region(shm, read_write); 

    cv::VideoCapture cap(0); 
    cv::Mat frame; 

    while(everything_is_ok_for_server){ 
    cap >> frame; 
    memcpy(region.get_address(), frame.data, width*height*channel); 
    } 
} 

else if(argv[1] == CLIENT){ 

    shared_memory_object shm (open_only, "SharedMemoryForCvMat", read_only); 
    mapped_region region(shm, read_only); 

    while(everything_is_ok_for_client){ 

     cv::Mat frame(cv::Size(width, height), 
         CV_8UC3, 
         region.get_address(), 
         cv::Mat::AUTO_STEP); 
     cv::imshow("unimportant_string",frame); 
     cv::waitKey(2); 
    } 
}