Table of Contents

FPGA-Imageram and FPGA-Functions

This site contains a collection of C++ examples demonstrating the usage of the FPGA-ImageRAM and other FPGA-functions like 3×3-filtering, (Color-)JPEG compression, etc. In general all examples on this site are developed for the 640×480 camera, but can easily be adapted to work with the other sensor variants.

Global Definitions and Functions

The follwing source code is the common base for all subsequent examples. It contains:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>     /* close() */
#include <sys/types.h>  /* open() */
#include <sys/stat.h>   /* open() */
#include <fcntl.h>      /* open() */
#include <sys/ioctl.h>  /* ioctl() */
#include <errno.h>
#include <stdint.h>
#include <string.h>
 
#include "OCamera.h"    /* camera image acquisition API */
#include "jpconv.h"     /* additional jpeg functions */
 
#define WIDTH     256
#define HEIGHT    256
#define FRAMESIZE WIDTH*HEIGHT
 
#define IMGRAM_START_ADDR_1   0
#define IMGRAM_START_ADDR_2   IMGRAM_START_ADDR_1+FRAMESIZE
 
/* error check macro used for camera-api calls */
#define CHECK_ERROR(msg,value)  { if (value) { \
                                  printf("%s returned %d",msg, value); \
                                  goto error_exit; \
                                }}
 
 
OCameraImage img;
OCamera *pCamera;
 
 
/* 
 * The following function does the basic setup needed for operating the camera.
 * This includes:
 * - opening the driver's interface
 * - setting camera window, shuttertime, illumination behaviour, etc.
 * - The acquisition mode is set to stop.
 */
int init_camera() {
  int ret;
 
  /* creating and opening the camera interface
   * be sure to specify the correct sensor type here
   */
  pCamera = OCamera::CreateCameraInterface(OCamera::CAM_TYPE_MT9V403);
  if (!pCamera) {
     printf("sorry, cannot open the camera API");
     goto error_exit;
   }
 
   ret = pCamera->Open(FRAMESIZE*10); /* frame buffer = 10 images */
   CHECK_ERROR("Open()",ret);
 
   /* basic camera setup */
   ret = pCamera->SetCameraWindow(0,0,WIDTH,HEIGHT);
   CHECK_ERROR("SetCameraWindow()",ret);
 
   ret = pCamera->SetFrequency(OCamera::FREQU_60MHz);
   CHECK_ERROR("SetFrequency()",ret);
 
   ret = pCamera->SetShutterTime(1000); /* 10ms */
   CHECK_ERROR("SetShutterTime()",ret);
 
   ret = pCamera->SetGain(8);
   CHECK_ERROR("SetGain()",ret);
 
   ret = pCamera->SetFrameRate(20); /* 20 fps */
   CHECK_ERROR("SetFrameRate()",ret);
 
   ret = pCamera->SetIlluminationTiming(0,0);
   CHECK_ERROR("SetIlluminationTiming()",ret);
 
   ret = pCamera->SetIlluminationMode(OCamera::ILL_MODE_OFF);
   CHECK_ERROR("SetIlluminationMode()",ret);
 
   ret = pCamera->SetIlluminationModeExternal(OCamera::ILL_MODE_EXT_OFF);
   CHECK_ERROR("SetIlluminationModeExternal()",ret);
 
   ret = pCamera->SetTriggerSource(OCamera::TRIG_SRC_SOFTWARE);
   CHECK_ERROR("SetTriggerSource()",ret);
 
   ret = pCamera->SetTriggerDelay(0);
   CHECK_ERROR("SetTriggerDelay()",ret);
 
   ret = pCamera->SetReadTimeout(2000000);
   CHECK_ERROR("SetReadTimeout()",ret);
 
   ret = pCamera->SetCircularOverwrite(true);
   CHECK_ERROR("SetCircularOverwrite()",ret);
 
   /* starting image aquisition */
   ret = pCamera->SetAcquisitionMode(OCamera::ACQ_MODE_SINGLE_SHOT);
   CHECK_ERROR("SetAcquisitionMode()",ret);
 
 error_exit:
  return ret;
}
 
int deinit_camera() {
 
  int ret;
 
  /* stopping image aquisition */
  ret = pCamera->SetAcquisitionMode(OCamera::ACQ_MODE_STOP);
  CHECK_ERROR("SetAcquisitionMode()",ret);
 
  pCamera->Close();   /* close camera API */
  pCamera->Destroy(); /* destroy/free the interface */
 
 error_exit:
  return ret;
}
 
 
/* -------------------------------------------------------------------------
 * prints a given area of the pxa memorry to a file
 * -------------------------------------------------------------------------
 */
int file_write(unsigned char *startaddr, unsigned int bytes, char *filename) {
  unsigned char *runner, *endaddr;
 
  FILE *f = fopen(filename,"w+b");
  if (!f) return -1;
  runner = startaddr;
  endaddr = runner+bytes; 
 
  while (runner<endaddr) { 
    fwrite(runner,1,sizeof(char),f);  
    runner++;
  }
  fclose(f);
 
  return 0;
}
 
 
/* -------------------------------------------------------------------------
 * creates a test image in the user space memory
 * -------------------------------------------------------------------------
 */
int create_test_image(unsigned char *dst, int width, int height)
{
 
  for(int i=0;i<height;i++) {
    for(int j=0;j<width;j++) {
      if (j<width*9/9) { dst[i*width+j] = 255; };
      if (j<width*8/9) { dst[i*width+j] = 223; };
      if (j<width*7/9) { dst[i*width+j] = 191; };
      if (j<width*6/9) { dst[i*width+j] = 159; };
      if (j<width*5/9) { dst[i*width+j] = 127; };
      if (j<width*4/9) { dst[i*width+j] = 95;  };
      if (j<width*3/9) { dst[i*width+j] = 63;  };
      if (j<width*2/9) { dst[i*width+j] = 31;  };
      if (j<width*1/9) { dst[i*width+j] = 0;   };
    }
  }
  return 0;
}
 
 
/* -------------------------------------------------------------------------
 *
 * -------------------------------------------------------------------------
 */
int setup_hw_whitebalancing(OCamera *pCamera, OCamera::eBayerPattern ePattern)
{
  int ret;
  unsigned char pLut[768];
 
  /* building the whitebalancing factors based on the values stored on the camera 
   * (in /ffx/etc/wb.conf; they are written by webcam.cgi)
   * alternativly you can build the pLut[768] table by yourself. The three tables
   * in pLut are ordered GBR!
   */
  ret = OCameraTools::SetupHardwareWhitebalancingFactors(pLut);
  CHECK_ERROR("SetupHardwareWhitebalancingFactors()",ret);
 
  /* writing the tables to the FPGA. 
   * The tables can be reseted to linear values by calling SetWhiteBalance(ePattern, 0);
   */
  ret = pCamera->SetWhiteBalance(ePattern, pLut);
  CHECK_ERROR("SetWhiteBalance()",ret);
 
 error_exit:
  return ret;
}

FPGA-ImageRAM, Bayer2X and 3x3-Filter Example

This example works on color cameras only.

A define allows switching between sensor image and an artificial test image

 
int example1(int argc, char *argv[])
{
  int ret;
 
  unsigned char *src,   *dst; 
  unsigned char *src32, *dst32;
 
  printf("starting test:");
 
  /* creating 32 byte alligned buffers for source/destination of data transfers from/to the
   * FPGA-attached image-RAM. The allignmend is necessary for DMA transfers.
   */
  src = (unsigned char*) malloc((FRAMESIZE+32)*sizeof(unsigned char));
  if (src == 0) goto exit1;
  src32 = (unsigned char*) (src+32-(unsigned long)src%32);
 
  dst = (unsigned char*) malloc((FRAMESIZE+32)*sizeof(unsigned char));
  if (dst == 0) goto exit2;
  dst32 = (unsigned char*) (dst+32-(unsigned long)dst%32);
 
 
  if (init_camera() != 0) goto exit3;
 
  /* enabling the FPGA attached image-RAM */
  ret = pCamera->InitImageRAM();
  ret = pCamera->InitColor();
  CHECK_ERROR("InitImageRAM",ret);
 
#define SENSOR_IMG
#ifdef SENSOR_IMG
  /* Getting an image from the sensor to the ImageRAM */
  ret = pCamera->GetImageToImageRAM(IMGRAM_START_ADDR_1);
  CHECK_ERROR("GetImageToImageRAM()",ret);
#else
  /* alternatively an image can be created and transfered from the PXA-memory */
  create_test_image(src32, WIDTH, HEIGHT);
  CHECK_ERROR("create_test_image()",ret);
 
  ret = pCamera->WriteImageRAM(src32, IMGRAM_START_ADDR_1, FRAMESIZE);
  CHECK_ERROR("WriteImageRAM()",ret);
#endif
 
  /* transfering the image from one address to another one in the Image Ram.
   * hereby filtering is enabled.
   */
 
  /* when transfering data over a filter out of the image Ram, we must explicitly set the
     picture size */ 
  ret = pCamera->SetImageRAMPictureSize(WIDTH,HEIGHT);
  CHECK_ERROR("SetImageRAMPictureSize",ret);
 
  ret = pCamera->SetBayer2X(OCamera::BAYER_OUTPUT_R, OCamera::BAYER_PATTERN_GRGR);
  CHECK_ERROR("SetBayer2X()",ret);
 
  ret = pCamera->SetFilter(OCamera::FILTER_SOBEL); 
  CHECK_ERROR("SetFilter()",ret);
 
  ret = pCamera->ImageRAMToImageRAM(IMGRAM_START_ADDR_1, FRAMESIZE, IMGRAM_START_ADDR_2, FRAMESIZE);
  CHECK_ERROR("ImageRAMToImageRAM",ret);
 
  /* disabling the filter */
  ret = pCamera->SetBayer2X(OCamera::BAYER_OUTPUT_RAW, OCamera::BAYER_PATTERN_GRGR);
  CHECK_ERROR("SetBayer2X()",ret);
  ret = pCamera->SetFilter(OCamera::FILTER_OFF); 
  CHECK_ERROR("SetFilter",ret);
 
  ret = pCamera->SetImageRAMPictureSize(0,0);
  CHECK_ERROR("SetImageRAMPictureSize",ret);
 
  /* transfering the filtered image to the PXA memory */
  ret = pCamera->ReadImageRAM(dst32, IMGRAM_START_ADDR_2, FRAMESIZE);
  CHECK_ERROR("ReadImageRAM()",ret);
 
  /* storing the picture to a file */
  ret = file_write(dst32, FRAMESIZE, "output.raw");
  CHECK_ERROR("file_write",ret);
 
 error_exit:
  /* disabling the FPGA Image RAM */
  pCamera->DisableImageRAM();
 
 exit3: /* cleaning up and exiting */
  ret = deinit_camera();
  if (ret != 0) goto exit2;
 
 exit2:
  free(dst);
 exit1:
  free(src);
  printf("done.");
  return ret;
}

White Balancing and Color-JPEG Encoding Example

This example shows:

This sample only works on color cameras.

 
int example2(int argc, char *argv[])
{
  int ret;
 
  unsigned char *dst; 
  unsigned char *dst32;
 
  unsigned long jpeg_stream_size;
 
  printf("starting test:");
 
  /* creating 32 byte alligned buffers for source/destination of data transfers from/to the
   * FPGA-attached image-RAM. The allignmend is necessary for DMA transfers.
   */
  dst = (unsigned char*) malloc((FRAMESIZE+32)*sizeof(unsigned char));
  if (dst == 0) goto exit2;
  dst32 = (unsigned char*) (dst+32-(unsigned long)dst%32);
 
  if (init_camera() != 0) goto exit3;
 
  /* setting the driver into color mode. This must be done always when you program for a color camera! */
  ret = pCamera->InitColor();
  CHECK_ERROR("InitColor()",ret);
 
  /* enabling the FPGA attached image-RAM */
  ret = pCamera->InitImageRAM();
  CHECK_ERROR("InitImageRAM",ret);
 
  /* setting up FPGA-White balancing */
  ret= setup_hw_whitebalancing(pCamera, OCamera::BAYER_PATTERN_GRGR);
  CHECK_ERROR("setup_hw_whitebalancing()",ret);
 
  /* Getting an image from the sensor to the ImageRAM */
  ret = pCamera->GetImageToImageRAM(IMGRAM_START_ADDR_1);
  CHECK_ERROR("GetImageToImageRAM()",ret);
 
  /* setting up Color JPEG compression */
  ret = pCamera->SetJPEG(true,OCamera::JPEG_QUALITY_GOOD, true, OCamera::BAYER_PATTERN_GRGR, false);
  CHECK_ERROR("SetJPEG()",ret);
 
  /* compressing image and transfering it to the PXA memory */
  ret = pCamera->ReadImageRAMReducedData(dst32, IMGRAM_START_ADDR_1, FRAMESIZE, &jpeg_stream_size);
  CHECK_ERROR("ReadImageRAMReduecdDate()",ret);
 
  /* adding header to jpeg stream and and storing the picture to a file */
  ret =write_jpeg_file(dst32, jpeg_stream_size, "output.jpg", WIDTH, HEIGHT, QTAB_QUALITY_GOOD, true, true);
  CHECK_ERROR("write_jpeg_file",ret);
 
  /* disabling color jpeg encoder */
  ret = pCamera->SetJPEG(false);
  CHECK_ERROR("SetJPEG()",ret);
 
 error_exit:
  /* disabling the FPGA Image RAM */
  pCamera->DisableImageRAM();
 
 exit3: /* cleaning up and exiting */
  ret = deinit_camera();
  if (ret != 0) goto exit2;
 
 exit2:
  free(dst);
  printf("done.");
  return ret;
}

3x3-Filter and Binarization Example

The following source shows, how filtering and binarization can be used on greyscale or color cameras (this selection is done with help of a #define statement).

 
int example3(int argc, char *argv[])
{
  int ret;
 
  printf("starting test:");
 
  if (init_camera() != 0) goto exit2;
 
#define COLOR
#ifdef COLOR
  /* setting the driver into color mode. This must be done always when you program for a color camera! */
  ret = pCamera->InitColor();
  CHECK_ERROR("InitColor()",ret);
 
  /* setting up the Bayer2X unit for calculating one single color channel out of the sensor's RAW image */
  ret = pCamera->SetBayer2X(OCamera::BAYER_OUTPUT_I, OCamera::BAYER_PATTERN_GRGR);
  CHECK_ERROR("SetBayer2X()",ret);
#endif
 
  /* setting up the filter set this to FILTER_BINARIZE_ONLY if you only want binarization */
  ret = pCamera->SetFilter(OCamera::FILTER_SOBEL); 
  CHECK_ERROR("SetFilter()",ret);
 
  /* setting up the binarization.
     here we have to fill the parameter struct with the needed thresholds */
  OCamera::sBinarizationParamType binarizationparam;
  binarizationparam.bInvert = false;
  binarizationparam.nNumThreshold = 2;
  binarizationparam.nThreshold1 = 16;
  binarizationparam.nThreshold2 = 32;
  ret = pCamera->SetBinarization(true, &binarizationparam);
  CHECK_ERROR("SetBinarization()",ret);
 
 /* trigger camera and read an image to container */
  ret = pCamera->GetImage(&img);
  CHECK_ERROR("GetImage()",ret);
 
 /* disabling everything ... */
  ret = pCamera->SetBinarization(false); 
  CHECK_ERROR("SetBinarization()",ret);
 
  ret = pCamera->SetFilter(OCamera::FILTER_OFF); 
  CHECK_ERROR("SetFilter()",ret);
 
  ret = pCamera->SetBayer2X(OCamera::BAYER_OUTPUT_RAW, OCamera::BAYER_PATTERN_GRGR);
  CHECK_ERROR("SetBayer2X",ret);
 
  /* storing the picture to a file */
  ret = file_write(img.pData, FRAMESIZE, "output.raw");
  CHECK_ERROR("file_write",ret);
 
 /* trigger camera and read an image to container */
  ret = pCamera->ReleaseImage(&img);
  CHECK_ERROR("ReleaseImate",ret);
 
 error_exit:
  /* cleaning up and exiting */
  deinit_camera();
 
 exit2:
  printf("done.");
  return ret;
}

Image Correction Example

The following code demonstrates how the correction unit can be used.

In this sample the correction unit replaces the sensor image by an test image transfered to the FPGA-ImageRAM at the beginning. Works on color and greyscale cameras.

 
 
/* -------------------------------------------------------------------------
 * Using image correction unit!
 * Greyscale + Color Camera
 * -------------------------------------------------------------------------
 */
 
int example4(int argc, char *argv[])
{
  int ret;
  unsigned char *src, *src32;
 
  printf("starting test:");
 
 
  if (init_camera() != 0) goto exit3;
 
  /* creating 32 byte alligned buffers for source/destination of data transfers from/to the
   * FPGA-attached image-RAM. The allignmend is necessary for DMA transfers.
   */
  src = (unsigned char*) malloc((FRAMESIZE+32)*sizeof(unsigned char));
  if (src == 0) goto exit2;
  src32 = (unsigned char*) (src+32-(unsigned long)src%32);
 
 
  /* enabling the FPGA attached image-RAM */
  ret = pCamera->InitImageRAM();
  CHECK_ERROR("InitImageRAM()",ret);
 
  /* preparing correction data in image ram */
 
  create_test_image(src32, WIDTH, HEIGHT);
  CHECK_ERROR("create_test_image()",ret);
 
  ret = pCamera->WriteImageRAM(src32, IMGRAM_START_ADDR_1, FRAMESIZE);
  CHECK_ERROR("WriteImageRAM()",ret);
 
  /* setting up the image correction */
  ret = pCamera->SetupImageCorrection(true, OCamera::CORRECTION_REPLACE, IMGRAM_START_ADDR_1, 1);
  CHECK_ERROR("SetupImageCorrection()",ret);
 
  /* trigger camera and read an image to container */
  ret = pCamera->GetImage(&img);
  CHECK_ERROR("GetImage()",ret);
 
  /* disabling image correction unit */
  ret = pCamera->SetupImageCorrection(false, OCamera::CORRECTION_REPLACE, IMGRAM_START_ADDR_1, 1);
  CHECK_ERROR("SetupImageCorrection()",ret);
 
  /* storing the picture to a file */
  ret = file_write(img.pData, FRAMESIZE, "output_corr.raw");
  CHECK_ERROR("file_write()",ret);
 
 /* trigger camera and read an image to container */
  ret = pCamera->ReleaseImage(&img);
  CHECK_ERROR("ReleaseImage()",ret);
 
 error_exit:
  pCamera->DisableImageRAM();
 
  free(src); 
 
 exit3: /* cleaning up and exiting */
  ret = deinit_camera();
  if (ret != 0) goto exit2;
 
 exit2:
  printf("done.");
  return ret;
}

Data Splitting Example

The following example shows how FPGA data splitting can be used. The example works on greyscale and color cameras.

int example5(int argc, char *argv[])
{
  int ret;
 
  unsigned char *dst, *dst32;
  printf("starting test:");
 
  /* creating 32 byte alligned buffers for source/destination of data transfers from/to the
   * FPGA-attached image-RAM. The allignmend is necessary for DMA transfers.
   */
  dst = (unsigned char*) malloc((FRAMESIZE+32)*sizeof(unsigned char));
  if (dst == 0) goto exit2;
  dst32 = (unsigned char*) (dst+32-(unsigned long)dst%32);
 
 
  if (init_camera() != 0) goto exit3;
 
  /* enabling the FPGA attached image-RAM */
  ret = pCamera->InitImageRAM();  CHECK_ERROR("InitImageRAM()",ret);
 
  ret = pCamera->SetupImageSplitting(OCamera::SPLIT_RAW, IMGRAM_START_ADDR_1, FRAMESIZE);
  CHECK_ERROR("SetupImageSplitting()",ret);
 
  ret = pCamera->SetFilter(OCamera::FILTER_MEDIAN);
  CHECK_ERROR("SetFilter()",ret);
 
  ret = pCamera->GetImage(&img);
  CHECK_ERROR("GetImage()",ret);
 
  ret = pCamera->SetupSplitting(OCamera::SPLIT_OFF, IMGRAM_START_ADDR_1, FRAMESIZE);
  CHECK_ERROR("SetupImageSplitting()",ret);
 
  // reading image from SDRAM and write it to a file
  ret = pCamera->SetFilter(OCamera::FILTER_OFF);
  CHECK_ERROR("SetFilter()",ret);
 
  printf("saving raw pxa picture");
 
  ret = file_write(img.pData,img.nSize, "output_pxa.raw");
  CHECK_ERROR("file_write()",ret);
 
  pCamera->ReleaseImage(&img);
  CHECK_ERROR("ReleaseImage",ret);
 
  ret = pCamera->ReadImageRAM(dst32, IMGRAM_START_ADDR_1, FRAMESIZE);
  CHECK_ERROR("ReadImageRAM",ret);
 
  printf("saving sdram picture");
 
  ret = file_write(dst32, FRAMESIZE, "output_sdram.raw");
  CHECK_ERROR("SetFilter()",ret);
 
 
 error_exit:
  ret = pCamera->DisableImageRAM();
 exit3: /* cleaning up and exiting */
  ret = deinit_camera();
  if (ret != 0) goto exit2;
 
 exit2:
  free(dst);
  printf("done.");
  return ret;
}