0

I need to capture pictures on a Raspberry Pi (I'm using a Compute Module 3+) using a camera based on the OmniVision OV4689 image sensor.

The datasheet for this image sensor can be found here https://cdn.hackaday.io/files/19354828041536/OV4689-OmniVision.pdf

WHAT WORKS

  • The OV4689 camera is plugged in the Raspberry Pi CAM1 interface through a custom PCB adapter board
  • The I2C communication between the camera and the Raspberry Pi works (over I2C0)
  • I'm using a device driver adapted from the OV5645 driver (https://github.com/raspberrypi/linux/blob/rpi-5.4.y/drivers/media/i2c/ov5645.c). This driver makes the OV4689 camera work properly on another Linux-based computer than the Raspberry Pi
  • The driver's probe function executes without any error, and makes the following devices appear : /dev/media2, /dev/video0, /dev/video1 and /dev/v4l-subdev0.
  • v4l2-ctl -d /dev/video0 --list-formats-ext outputs the following :
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'pBAA' (10-bit Bayer BGBG/GRGR Packed)
                Size: Discrete 640x360
                Size: Discrete 1280x720
                Size: Discrete 1920x1080
        [1]: 'BG10' (10-bit Bayer BGBG/GRGR)
                Size: Discrete 640x360
                Size: Discrete 1280x720
                Size: Discrete 1920x1080

WHAT DOESN'T WORK

I am not able to capture an image from the OV4689 camera.

Note : I tried the following procedures with multiple cameras units.

  • I compiled and ran the following OpenCV code (my OpenCV version is 3.3.1) :
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>  // cv::Canny()
#include <iostream>

using namespace cv;
using std::cout; using std::cerr; using std::endl;

int main(int, char**)
{
    cout << "Opening camera..." << endl;
    VideoCapture capture(0); // try opening /dev/video0
    if (!capture.isOpened())
    {
        cerr << "ERROR: Can't initialize camera capture!" << endl;
        return 1;
    }
    else
        cout << "SUCCESS" << endl;
}

Which gave me the following output :

Opening camera...
VIDEOIO ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV
ERROR: Can't initialize camera capture!

So OpenCV seems to fail opening my camera device.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>    /* For O_RDWR */
#include <sys/ioctl.h>
#include <unistd.h>   /* For open(), creat() */
#include <sys/mman.h>

#include <linux/videodev2.h>

int set_format(int fd) {
    struct v4l2_format format = {0};
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = 640;
    format.fmt.pix.height = 360;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB10;  // V4L2_PIX_FMT_YUYV , V4L2_PIX_FMT_SRGGB10
    format.fmt.pix.field = V4L2_FIELD_NONE;
    int res = ioctl(fd, VIDIOC_S_FMT, &format);
    if(res == -1) {
        perror("Could not set format");
        exit(1);
    }
    else
        printf("set_format: ioctl returns : %d\n", res);
    return res;
}

int request_buffer(int fd, int count) {
    struct v4l2_requestbuffers req = {0};
    req.count = count;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    int res = ioctl(fd, VIDIOC_REQBUFS, &req);
    if (res == -1)
    {
        perror("Requesting Buffer");
        exit(1);
    }
    else
        printf("request_buffer: ioctl returns : %d\n", res);
    return 0;
}

int size;
u_int8_t* query_buffer(int fd) {
    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
    int res = ioctl(fd, VIDIOC_QUERYBUF, &buf);
    if(res == -1) {
        perror("Could not query buffer");
        exit(2);
    }
    else
        printf("query_buffer: ioctl returns : %d\n", res);
    
    u_int8_t* buffer = (u_int8_t*)mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
    size = buf.length;
    // return buf.length;
    return buffer;
}

int start_streaming(int fd) {
    unsigned int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    int res = ioctl(fd, VIDIOC_STREAMON, &type);
    if(res == -1){
        perror("VIDIOC_STREAMON");
        exit(1);
    }
    else
        printf("start_streaming: ioctl returns : %d\n", res);

    return res;
}

int queue_buffer(int fd) {
    struct v4l2_buffer bufd = {0};
    bufd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    bufd.memory = V4L2_MEMORY_MMAP;
    bufd.index = 0;
    int res = ioctl(fd, VIDIOC_QBUF, &bufd);
    if(res == -1)
    {
        perror("Queue Buffer");
        return 1;
    }
    else
        printf("queue_buffer: ioctl returns : %d\n", res);
    return bufd.bytesused;
}

void grab_frame(int camera, int size, u_int8_t* buffer) {
    queue_buffer(camera);
    //Wait for io operation
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(camera, &fds);
    struct timeval tv = {0};
    tv.tv_sec = 2; //set timeout to 2 second
    int r = select(camera+1, &fds, NULL, NULL, &tv);
    if(-1 == r){
        perror("Waiting for Frame");
        exit(1);
    }
    int file = open("/home/pi/OV4689_tests/v4l2_test/output_raw", O_WRONLY | O_CREAT, 0644);
    printf("grab_frame fd : %d\n", file);
    write(file, buffer, size); //size is obtained from the query_buffer function
    // dequeue_buffer(camera);
}

int main() {    
    int fd = open("/dev/video0", O_RDWR);
    printf("fd : %d\n\n", fd);

    set_format(fd);
    int count = 1;
    request_buffer(fd, count);

    u_int8_t* buffer = query_buffer(fd);
    start_streaming(fd);
    grab_frame(fd, size, buffer);

    return 0;
}

It gave me the following output :

fd : 3

set_format: ioctl returns : 0
request_buffer: ioctl returns : 0
query_buffer: ioctl returns : 0
start_streaming: ioctl returns : 0
queue_buffer: ioctl returns : 0
grab_frame fd : 4

So the program runs without any error and generates a non-empty file output_raw, supposed to contain raw image data from the camera's sensor. However, the tool http://rawpixels.net clearly shows that the data contained in my output_raw file is not relevant and doesn't reflect at all what one would expect that the camera should have output.

With the official Raspberry Pi Camera module, this program works fine and I am able to retrieve a relevant image.

So it seems that the OV4689 camera doesn't output any significant image data.

WHAT I WOULD LIKE TO KNOW

Has anyone ever tried to make the OV4689 camera work with a Raspberry Pi ?

Given that /dev/video0 exists, what could be wrong ?

My guess is that I am not using the correct pixel format.

In V4L2 API, what pixel format macro (e.g. V4L2_PIX_FMT_SRGGB10) corresponds to pBAA or BG10 ?

In OpenCV, how can I specify which pixel format to use when trying to open the camera device ? My guess is that OpenCV is trying to use pBAA, with which it fails, although if it were using BG10 it might not fail.

Any help will be appreciated

Thanks

  • One thing that questions me is that the supported pixel formats for my OV4689 camera according to "v4l2-ctl -d /dev/video0 --list-formats-ext" seem to be only pBAA and BG10, whereas with other cameras I tested, I always saw others such as YUYV. – Ramanewbie Oct 28 at 16:36
  • I would save time emotional frostration and buy one of the official rpi camera sensors – dafnahaktana Oct 28 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.