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.
Sobald ich anfange, Bilder von mehreren Kameras (nacheinander) aufzunehmen, erhalte ich beschädigte Bilder. Je 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);
}
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.
Timonku
A. J. Henderson