Beschädigte Bilder beim Erfassen von mehreren Kameras mit der V4L2-API

Ich möchte Bilder von mehreren Kameras unter Linux erfassen. Ich folgte dieser Präsentation , benutzte den Code und erweiterte ihn für meine Zwecke. Es funktioniert sehr gut für 1 Kamera.

Gespeichertes Bild aus dem Carema mit v4l2 und libpngSobald ich anfange, Bilder von mehreren Kameras (nacheinander) aufzunehmen, erhalte ich beschädigte Bilder. Beschädigtes Bild beim Erfassen von Bildern von mehreren KamerasJe mehr Kameras ich verklage, desto mehr Artefakte/Streifen erscheinen in den Bildern. Es macht keinen Unterschied, ob ich die Bilder mit einem anderen Code als BMP speichere. Ich gehe also davon aus, dass das Problem nichts mit der Speicherroutine zu tun hat. Die Auflösung stimmt auch (744*480).

Das Ergebnis ist auf zwei verschiedenen Computern mit Fedora und Debian dasselbe. Ich bin absolut ratlos und kann keine Ahnung finden, was falsch läuft. Könnte mir bitte jemand ein paar Tipps geben?

Hier ist mein Code

int main()
{
    /* #################### INIT #################### */

    int numOfCameras = 1;
    int xRes = 744;
    int yRes = 480;
    int exposure = 2000;
    unsigned int timeBetweenSnapshots = 2; // in sec
    char fileName[sizeof "./output/image 000 from camera 0.PNG"];

    static const char *devices[] = { "/dev/video0", "/dev/video1", "/dev/video2", "/dev/video3", "/dev/video4", "/dev/video5", "/dev/video6", "/dev/video7" };

    struct v4l2_capability cap[8];
    struct v4l2_control control[8];
    struct v4l2_format format[8];
    struct v4l2_requestbuffers req[8];
    struct v4l2_buffer buffer[8];

    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // had to declare the type here because of the loop

    unsigned int i;
    unsigned int j;
    unsigned int k;

    int fd[8];
    void **mem[8];

    /* #################### OPEN DEVICE #################### */

    for (j = 0; j < numOfCameras; ++j) {

        fd[j] = open(devices[j], O_RDWR);
        ioctl(fd[j], VIDIOC_QUERYCAP, &cap[j]);


        /* #################### CAM CONTROLL #################### */

        control[j].id = V4L2_CID_EXPOSURE_AUTO;
        control[j].value = V4L2_EXPOSURE_SHUTTER_PRIORITY;
        ioctl(fd[j], VIDIOC_S_CTRL, &control[j]);

        control[j].id = V4L2_CID_EXPOSURE_ABSOLUTE;
        control[j].value = exposure;
        ioctl(fd[j], VIDIOC_S_CTRL, &control[j]);

        /* #################### FORMAT #################### */

        ioctl(fd[j], VIDIOC_G_FMT, &format[j]);
        format[j].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        format[j].fmt.pix.width = xRes;
        format[j].fmt.pix.height = yRes;
        //format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        format[j].fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
        ioctl(fd[j], VIDIOC_S_FMT, &format[j]);

        /* #################### REQ BUF #################### */

        req[j].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req[j].count = 4;
        req[j].memory = V4L2_MEMORY_MMAP;
        ioctl(fd[j], VIDIOC_REQBUFS, &req[j]);
        mem[j] = malloc(req[j].count * sizeof(*mem));

        /* #################### MMAP #################### */

        for (i = 0; i < req[j].count; ++i) {
            buffer[j].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buffer[j].memory = V4L2_MEMORY_MMAP;
            buffer[j].index = i;
            ioctl(fd[j], VIDIOC_QUERYBUF, &buffer[j]);
            mem[j][i] = mmap(0, buffer[j].length,
                    PROT_READ|PROT_WRITE,
                    MAP_SHARED, fd[j], buffer[j].m.offset);
        }

        /* #################### CREATE QUEUE #################### */

        for (i = 0; i < req[j].count; ++i) {
            buffer[j].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buffer[j].memory = V4L2_MEMORY_MMAP;
            buffer[j].index = i;
            ioctl(fd[j], VIDIOC_QBUF, &buffer[j]);
        }

    } /* ### ### end of camera init ### ### */

    /* ##################### STREAM ON #################### */
    for (j = 0; j < numOfCameras; ++j) {

        ioctl(fd[j], VIDIOC_STREAMON, &type);
    }


    /* ##################### GET FRAME ##################### */

    k = 0;
    while (!kbhit()){
        k ++;

        for (j = 0; j < numOfCameras; j++) {

            buffer[j].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buffer[j].memory = V4L2_MEMORY_MMAP;
            usleep(100000);
            ioctl(fd[j], VIDIOC_DQBUF, &buffer[j]);

            // create filename
            sprintf(fileName, "./output/image %03d from camera %d.PNG", k, j);
            // save as PNG file
            saveToPng(mem[j][buffer[j].index], fileName, xRes, yRes);

            ioctl(fd[j], VIDIOC_QBUF, &buffer[j]);

            sleep(timeBetweenSnapshots);
        }
    }

    /* ##################### STREAM OFF ##################### */
    for (j = 0; j < numOfCameras; ++j) {

        ioctl(fd[j], VIDIOC_STREAMOFF, &type);
    }

    /* ##################### CLEANUP ##################### */

    for (j = 0; j < numOfCameras; ++j) {

        close(fd[j]);
        free(mem[j]);
    }

    return (0);
}
Dies ist eine sehr grenzwertige Frage für diese SE, alles, was mit der Programmierung zu tun hat, sollte stattdessen auf StackOverflow gestellt werden.
Sind Sie sicher, dass die Bildrate und die Bildabmessungen zwischen den Kameras einheitlich sind? Das sieht verdächtig nach einem falschen Zeilentiming aus, das aus einer falschen Höhe und Breite und/oder Bildrate resultieren würde.

Antworten (2)

Ihr Problem ist wahrscheinlich, dass Sie nicht genügend USB-Bandbreite zur Verfügung haben, wenn Ihre Webcams dies unterstützen, wechseln Sie zu MJPEG anstelle von unkomprimierten Frames. Normalerweise unterstützt jede Webcam die MJPEG-Codierung, um Frames an Ihren PC zu liefern.

Hier eine ähnliche Frage zu SO https://stackoverflow.com/questions/9781770/capturing-multiple-webcams-uvcvideo-with-opencv-on-linux

Ich bin mir ziemlich sicher, dass Sie die Korruption wegen usleep(100000) bekommen; - Dies basiert auf der Tatsache, dass ich eine ähnliche Beschädigung mit einer Webcam erreicht habe, indem ich usleep(100000) zu meinem Code hinzugefügt habe.

Mein Schlaf (100000); ist ein Ersatz für das Ausführen eines opencl-Kernels, was bedeutet, dass ich an diesem Punkt weiß, dass das Problem darin besteht, dass usleep (100000) die Bereitstellung von Videoframes in irgendeiner Weise beeinflusst (dies passiert in meinem Code, wenn ich den gesamten anderen Code entferne und nur die Frames speichere Festplatte als ppm-Dateien).

Was ich nicht weiß ist warum....

Ich kann den usleep irgendwo in meinen Code einfügen, der Effekt ist immer derselbe.

Vielleicht muss der Webcam-Code von video4linux in einem anderen pthread sein.