Snapshot with libpixyusb?

Added by Jim Remington over 2 years ago

It has been stated in the forum that libpixyusb API allows one to obtain a still image from the camera, but I can't find anything in the libpixyusb API reference documentation that indicates how that might be done. Can someone provide or post a simple example, along the lines of hello_pixy?

Second question: can one set the exposure time? If not, what are the meaning and effects of the two parameters (gain and compensation) in the set_exposure_compensation call in the libpixyusb API?

Thanks in advance! Jim Remington


Replies (41)

RE: Snapshot with libpixyusb? - Added by Hemanand Ramasamy about 2 years ago

I have done the Bayer Interpolation based on the code used in PixyMon and this the result I got. The colors are not identifiable.

img.bmp (250.1 kB)

RE: Snapshot with libpixyusb? - Added by Jim Remington about 2 years ago

It looks like the interpolation was not done correctly. Post the code.

RE: Snapshot with libpixyusb? - Added by Hemanand Ramasamy about 2 years ago

#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <iostream>
#include "pixy.h" 

void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b);

void handle_SIGINT(int unused)
{
    printf("\nBye!\n");
  exit(0);
}

int main(int argc, char * argv[])
{
  int      index;
  int      blocks_copied;
  int      pixy_init_status;

  signal(SIGINT, handle_SIGINT);

  pixy_init_status = pixy_init();
  printf("initialized Pixy - %d\n", pixy_init_status);

  if(!pixy_init_status == 0)
  {
    printf("pixy_init(): ");
    pixy_error(pixy_init_status);
    return pixy_init_status;
  }

  {
    unsigned char *pixels;
    uint32_t frame[200][320];
    uint32_t r[200][320];
    uint32_t g[200][320];
    uint32_t b[200][320];
    char rgb[200][320];
    int32_t response, fourcc;
    int8_t renderflags;
    int return_value, res;
    uint16_t width, height;
    uint32_t  numPixels;
    unsigned char current_frame[72000];

     uint8_t gain;
    uint16_t compensation;

    uint8_t* pgain;
    uint16_t* pcomp;

    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);   
    printf(" STOP returned %d response %d\n", return_value, response);

    return_value = pixy_cam_get_exposure_compensation(&gain, &compensation);
    printf("getECV returned %d values: 0, 0x%02x, 0x%04x\n",return_value,gain, compensation);

    pixy_command("cam_setAEC", UINT8(0x01), END_OUT_ARGS,  &response, END_IN_ARGS);
    printf("response %d",response);
    pixy_command("cam_setAWB", UINT8(0x01), END_OUT_ARGS,  &response, END_IN_ARGS);
    printf("response %d",response);

    response = 0;
    return_value = pixy_command("cam_getFrame",  // String id for remote procedure
                                 0x01, 0x21,      // mode
                                 0x02,   0,        // xoffset
                                 0x02,   0,         // yoffset
                                 0x02, 320,       // width
                                 0x02, 200,       // height
                                 0,              // separator
                                 &response,      // pointer to mem address for return value
                                &fourcc,  //for some reason these 5 args are needed, contrary to the docs
                                &renderflags,
                                &width,
                                &height,
                                &numPixels,
                                 &pixels,        // pointer to mem address for returned frame
                                 0);

    fprintf(stderr,"getFrame return value %d response %d\n", return_value, response);
    printf("returned w %d h %d npix %d \n",width,height,numPixels);

    if(return_value != 0) return return_value;

    return_value = pixy_cam_get_exposure_compensation(&gain, &compensation);
    printf("getECV returned %d values: 0, 0x%02x, 0x%04x\n",return_value,gain, compensation);

   unsigned int i,j,ind,start;

   unsigned long avg=0;
   for(i=0; i<numPixels; i++) avg += pixels[i];
   avg = avg/numPixels;
   printf(" average pixel value %d \n",avg);

   for (i=0; i<8; i++) {
        for (j=0; j<8; j++) {
        ind=i*width+j;
        printf(" %02x",pixels[ind]);
        }
    printf("\n"); 
    }

    memcpy(&current_frame, pixels,numPixels);

   FILE *fp;
  for (i=0; i<200; i++) {
      for(j=0; j<320; j++){
        ind = i * 320 + j;
        frame[i][j] = pixels[ind];
      }
    }

    for(i=0; i<200; i++){
      r[i][0] = r[i][319] = b[i][0] = b[i][319] = b[i][0] = b[i][319] = 0 ;
    }

    for(j=0; j<320; j++){
      r[0][j] = r[119][j] = b[0][j] = b[119][j] = b[0][j] = b[119][j] = 0 ;
    }

    uint32_t rx, gx, bx;
    for (i=1; i<199; i++) {
      pixels++;
      for(j=1; j<319; j++, pixels++){
          interpolateBayer(320, j, i, pixels, rx, gx, bx);
          r[i][j] = rx;
          g[i][j] = gx;
          b[i][j] = bx;
      }
      pixels++;
    }

    FILE *r_file;
    FILE *g_file;
    FILE *b_file;
    FILE *x_file;

    r_file =fopen("r.txt", "w");
    g_file =fopen("g.txt", "w");
    b_file =fopen("b.txt", "w");
    x_file =fopen("z.txt", "w");

    for (i=0; i<200; i++) {
      fprintf(r_file,"{");
      fprintf(g_file,"{");
      fprintf(b_file,"{");

      for(j=0; j<320; j++){
        if(j == 319){
          fprintf(r_file, "%d", r[i][j]);
          fprintf(g_file, "%d", g[i][j]);
          fprintf(b_file, "%d", b[i][j]);
        }else{
          fprintf(r_file, "%d ,", r[i][j]);
          fprintf(g_file, "%d ,", g[i][j]);
          fprintf(b_file, "%d ,", b[i][j]);
        }
        ind = i * 320 + j;
        fprintf(x_file, "%d,", frame[i][j] );

      }

      fprintf(r_file,"},");
      fprintf(g_file,"},");
      fprintf(b_file,"},");
    }  

    fclose(r_file);
    fclose(g_file);
    fclose(b_file);
    fclose(x_file);

    fp=fopen("/home/pi/dump.img","w");
        if(fp != NULL) {
        fwrite(bgrOutputDat, 1, numPixels, fp);
        fclose(fp);
        printf("wrote dump.img\n Done!\n");
        }
        else perror("file allocation failure");

  }

   exit(0);

}

void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b)
{
  if (y & 1)
  {
    if (x & 1)
    {
      r = *pixel;
      g = (*(pixel - 1) + *(pixel + 1) + *(pixel + width) + *(pixel - width)) >> 2;
      b = (*(pixel - width - 1) + *(pixel - width + 1) + *(pixel + width - 1) + *(pixel + width + 1)) >> 2;
    }
    else
    {
      r = (*(pixel - 1) + *(pixel + 1)) >> 1;
      g = *pixel;
      b = (*(pixel - width) + *(pixel + width)) >> 1;
    }
  }
  else
  {
    if (x & 1)
    {
      r = (*(pixel - width) + *(pixel + width)) >> 1;
      g = *pixel;
      b = (*(pixel - 1) + *(pixel + 1)) >> 1;
    }
    else
    {
      r = (*(pixel - width - 1) + *(pixel - width + 1) + *(pixel + width - 1) + *(pixel + width + 1)) >> 2;
      g = (*(pixel - 1) + *(pixel + 1) + *(pixel + width) + *(pixel - width)) >> 2;
      b = *pixel;
    }
  }
}

I took those RGB arrays and used

            Bitmap bmp = new Bitmap(width, height);

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {

                    System.Drawing.Color color = System.Drawing.Color.FromArgb(rx[y, x],gx[y, x],bx[y, x]);

                    bmp.SetPixel(x, y, color);

                }
            }

RE: Snapshot with libpixyusb? - Added by Jim Remington about 2 years ago

I believe you are on the right track. I got as far as you did with the interpolation, but did not try to write an RGB file. It appeared there was an indexing error, (as it does in the .bmp file you posted). If you are off by 1 in either direction, the result is hopeless.

I suggest to take a snapshot of a white card through a red, green or blue filter and check the indexing by printing out some raw pixel values, before and after interpolation.

On posting code, the "pre" (preformatted) button to encapsulate the code seems to work best. The "Inline Code" button does not work. Note that the posted code in the previous post has some characters reinterpreted as html. Can you edit it to change that?

RE: Snapshot with libpixyusb? - Added by Hemanand Ramasamy about 2 years ago

Sorry about the code my first time.. Alright I ll work on the part you told me .

RE: Snapshot with libpixyusb? - Added by Hemanand Ramasamy over 1 year ago

I am sorry for such a delay I resolved the issue and everything works perfectly I have added with this the working code.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <math.h>  
#include "pixy.h" 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <ctime>

using namespace cv;
using namespace std;

void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b);
Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
Mat getImage();

int main(int argc, char * argv[])
{
    int pixy_init_status;
    int return_value;
    int32_t response;

    pixy_init_status = pixy_init();

    if(!pixy_init_status == 0)
    {
        printf("pixy_init(): ");
        pixy_error(pixy_init_status);
        return pixy_init_status;
    }

    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS); 
    return_value = pixy_rcs_set_position(1, 900);
    return_value = pixy_rcs_set_position(0, 500);

    Mat image = getImage();
}

Mat getImage()
{
    unsigned char *pixels;
    int32_t response, fourcc;
    int8_t renderflags;
    int return_value, res;
    uint16_t rwidth, rheight;
    uint32_t  numPixels;
    uint16_t height,width;
    uint16_t mode;

    return_value = pixy_command("run", END_OUT_ARGS, &response, END_IN_ARGS);   
    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);

    return_value = pixy_command("cam_getFrame",  // String id for remote procedure
                                 0x01, 0x21,      // mode
                                 0x02,   0,        // xoffset
                                 0x02,   0,         // yoffset
                                 0x02, 320,       // width
                                 0x02, 200,       // height
                                 0,            // separator
                                 &response, &fourcc, &renderflags, &rwidth, &rheight, &numPixels, &pixels, 0);

    return renderBA81(renderflags,rwidth,rheight,numPixels,pixels);
}

inline void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pixel, uint8_t* r, uint8_t* g, uint8_t* b)
{
    if (y&1)
    {
        if (x&1)
        {
            *r = *pixel;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
        }
        else
        {
            *r = (*(pixel-1)+*(pixel+1))>>1;
            *g = *pixel;
            *b = (*(pixel-width)+*(pixel+width))>>1;
        }
    }
    else
    {
        if (x&1)
        {
            *r = (*(pixel-width)+*(pixel+width))>>1;
            *g = *pixel;
            *b = (*(pixel-1)+*(pixel+1))>>1;
        }
        else
        {
            *r = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = *pixel;
        }
    }

}

Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
{
    uint16_t x, y;
    uint8_t r, g, b;
    Mat imageRGB;

    frame += width;
    uchar data[3*((height-2)*(width-2))];

    uint m = 0;
    for (y=1; y<height-1; y++)
    {
        frame++;
        for (x=1; x<width-1; x++, frame++)
        {
            interpolateBayer(width, x, y, frame, &r, &g, &b);
            data[m++] = b;
            data[m++] = g;
            data[m++] = r;
        }
        frame++;
    }

    imageRGB =  Mat(height - 2,width -2, CV_8UC3, data);

    return imageRGB;
}

RE: Snapshot with libpixyusb? - Added by Elia Schoen 5 months ago

Hi all!
I know that this post is an old discussion, but I'd like to know where I have to write this code to try it.
I read that a program is needed (QT Project, I think) to compile libpixyusb and other. It is the program to use?

RE: Snapshot with libpixyusb? - Added by Edward Getz 5 months ago

Hello Elia,
This page explains how to get started with libpixyusb (it's what's being used in this topic discussion.)

http://cmucam.org/projects/cmucam5/wiki/Building_the_libpixyusb_example_on_Linux

Hope this helps!

Edward

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

Hi guys!

First of all I want to thank all the people posting in this thread, you really helped me.
I am working on a small application in order to get pictures from the Pixy. The goal is to use these picture to get the calibration matrix of the camera using the openCV library.
To do so I took Hemanand Ramasamy's code (thanks a lot for this work). Took me a while to understand how to compile it ("g++ -I/usr/include/libusb-1.0/ -I/usr/local/include -L/usr/local/lib/ `pkg-config --cflags --libs opencv` snapshot.cpp -o snapshot -Wall -lpixyusb -lusb-1.0 -lboost_system -lboost_thread -lboost_date_time -lboost_chrono" if can help someone).
However I get some weird things inside my image. Anyone having an idea of why this is happening? Am I missing something big? Can it be related to the camera mode? Or its software revision?
As you will see, the image is not complete as if the program was not able to recover the whole picture.
I also add the code allowing me to save the image.

Thanks for your consideration and help.

Maxime

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <math.h>  
#include <pixy.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <ctime>

using namespace cv;
using namespace std;

void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b);
Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
Mat getImage();

int main(int argc, char * argv[])
{
    int pixy_init_status;
    int return_value;
    int32_t response;

    pixy_init_status = pixy_init();

    if(!pixy_init_status == 0)
    {
        printf("pixy_init(): ");
        pixy_error(pixy_init_status);
        return pixy_init_status;
    }

    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS); 
    //return_value = pixy_rcs_set_position(1, 900);
    //return_value = pixy_rcs_set_position(0, 500);

    Mat image = getImage();

    // Display and save the image
    namedWindow( "Snapshot", WINDOW_AUTOSIZE );
    imshow("Snapshot", image);
    waitKey(0);
    imwrite("/home/pi/pixy/calib/snapshot.jpg", image);
}

Mat getImage()
{
    unsigned char *pixels;
    int32_t response, fourcc;
    int8_t renderflags;
    //int return_value, res;
    int return_value;
    uint16_t rwidth, rheight;
    uint32_t  numPixels;
    //uint16_t height,width;
    //uint16_t mode;

    return_value = pixy_command("run", END_OUT_ARGS, &response, END_IN_ARGS);
    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);

    return_value = pixy_command("cam_getFrame",  // String id for remote procedure
                                 0x01, 0x21,      // mode
                                 0x02,   0,        // xoffset
                                 0x02,   0,         // yoffset
                                 0x02, 320,       // width
                                 0x02, 200,       // height
                                 0,            // separator
                                 &response, &fourcc, &renderflags, &rwidth, &rheight, &numPixels, &pixels, 0);

    return renderBA81(renderflags,rwidth,rheight,numPixels,pixels);
}

inline void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pixel, uint8_t* r, uint8_t* g, uint8_t* b)
{
    if (y&1)
    {
        if (x&1)
        {
            *r = *pixel;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
        }
        else
        {
            *r = (*(pixel-1)+*(pixel+1))>>1;
            *g = *pixel;
            *b = (*(pixel-width)+*(pixel+width))>>1;
        }
    }
    else
    {
        if (x&1)
        {
            *r = (*(pixel-width)+*(pixel+width))>>1;
            *g = *pixel;
            *b = (*(pixel-1)+*(pixel+1))>>1;
        }
        else
        {
            *r = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = *pixel;
        }
    }

}

Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
{
    uint16_t x, y;
    uint8_t r, g, b;
    Mat imageRGB;

    frame += width;
    uchar data[3*((height-2)*(width-2))];

    uint m = 0;
    for (y=1; y<height-1; y++)
    {
        frame++;
        for (x=1; x<width-1; x++, frame++)
        {
            interpolateBayer(width, x, y, frame, &r, &g, &b);
            data[m++] = b;
            data[m++] = g;
            data[m++] = r;
        }
        frame++;
    }

    imageRGB =  Mat(height - 2,width -2, CV_8UC3, data);

    return imageRGB;
}

snapshot.jpg (19.3 kB)

RE: Snapshot with libpixyusb? - Added by Edward Getz 4 months ago

Hello Maxime,
Hmm, that's odd. Does PixyMon seem to work fine on this machine with the USB cable you are using? Also, I'm not sure if it's the acquisition of the image that's the problem or the JPEG encoding. (although I suspect the acquisition.)

It might be that Pixy is stepping on your frame. Pixy runs the color connected components algorithm by default, and I assume it's running it while you are trying to grab a frame. You should stop the program on Pixy by calling the stop() command on Pixy:

return_value = pixy_command("stop", END_OUT_ARGS, &chirp_response, END_IN_ARGS);

When you're done grabbing frames you can start the program again by running:

return_value = pixy_command("start", END_OUT_ARGS, &chirp_response, END_IN_ARGS);

Hope this helps!

Edward

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

Hello Edward,

The camera is working perfectly when I use PixyMon. The function "Save Image" is also working as expected.
I'll check what you said about stoping the camera and starting it when grabbing the frame but, if I'm not wrong, it is already done in the code I gave in my post.

Thanks a lot for your help.

Maxime

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

I forgot to mention that this program is running on a RPI3 via USB. I have no idea if it can be the origin of the problem. But I guess it is not because the PixyMon program using the same libraries as my program, is working correctly.

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

Also, what's weird is that the deformation pattern seems to be exactly the same on every picture that I take with my code. Does it mean that the problem is in my code?

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

Hello,

I managed to find the origin of the problem. It is a memory issue.
If I convert the image from BGR to RGB before returning it, then it works (I don't get the right colors but at least I do not have this loss of pixels).

If anyone has an idea of how I could solve this issue.

Here is a link of a thread on another forum. The guy has the same issue while converting an image from Qimage to cv::Mat.
http://stackoverflow.com/questions/17127762/cvmat-to-qimage-and-back

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <math.h>  
#include <pixy.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <ctime>
#include <iostream>

using namespace cv;
using namespace std;

void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b);
Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
Mat getImage();

int main(int argc, char * argv[])
{
    int pixy_init_status;
    int return_value;
    int32_t response;
    cv::Mat image;

    pixy_init_status = pixy_init();

    if(!pixy_init_status == 0)
    {
        printf("pixy_init(): ");
        pixy_error(pixy_init_status);
        return pixy_init_status;
    }
    cout << "Init Pixy..." << endl;

    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS); 
    cout << "Stop1 Pixy: " << return_value << endl;

    image = getImage();

    // Display and save the image
    namedWindow( "Snapshot", WINDOW_AUTOSIZE );
    imshow("Snapshot", image);
    waitKey(0);

    try {
        imwrite("/home/pi/pixy/calib/snapshot.png", image);
    }
    catch (runtime_error& ex) {
        fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
        return 1;
    }

    cout << "Saved PNG file." << endl;

    return 0;
}

Mat getImage()
{
    unsigned char *pixels;
    int32_t response, fourcc;
    int8_t renderflags;
    //int return_value, res;
    int return_value;
    uint16_t rwidth, rheight;
    uint32_t  numPixels;
    //uint16_t height,width;
    //uint16_t mode;
    Mat image;

    return_value = pixy_command("run", END_OUT_ARGS, &response, END_IN_ARGS);
    cout << "Run1 Pixy: " << return_value << endl;

    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
    cout << "Stop2 Pixy: " << return_value << endl;

    return_value = pixy_command("cam_getFrame",  // String id for remote procedure
                                 /* Mx, or "mode x" where x is either:
                                    0: full resolution mode (1280x800) at 25 frames/sec
                                    1: quarter resolution mode (640x400) at 50 frames/sec -- the imager bins/averages the pixels

                                    Ry, or "resolution y" where y is either:
                                    0: 1280x800 resolution no pixel binning/averaging
                                    1: 640x400 resolution no pixel binning/averaging (only available in mode 1)
                                    2: 320x200 resolution with pixel binning/averaging (also only available in mode 1) */
                                 // mode: CAM_GRAB_M0R0 (0x00), CAM_GRAB_M1R1 (0x11), CAM_GRAB_M1R2 (0x21)
                                 0x01, 0x11,
                                 0x02, 155,        // xoffset
                                 0x02, 90,         // yoffset
                                 // Memory size = 73728 bytes (72K) so width * height must be lower or equel to this
                                 0x02, 330,       // width
                                 0x02, 220,       // height
                                 0,            // separator
                                 &response, &fourcc, &renderflags, &rwidth, &rheight, &numPixels, &pixels, 0);

    cout << "Cam_GetFrame1 Pixy: " << return_value << endl;
    cout << "Pixy returned response : " << response << ", fourcc : " << fourcc << ", renderflags : " << renderflags << ", width : " << rwidth << ", height : " << rheight << ", numPixels : " << numPixels << endl; 

    // Render frame sent by Pixy
    image = renderBA81(renderflags,rwidth,rheight,numPixels,pixels);

    return image;
}

inline void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pixel, uint8_t* r, uint8_t* g, uint8_t* b)
{
    // Smear the pixel depending on parity regarding abscissa and ordinate (parity gives color -> see Bayer matrix for more info about it)
    if (y&1)
    {
        if (x&1)
        {
            *r = *pixel;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
        }
        else
        {
            *r = (*(pixel-1)+*(pixel+1))>>1;
            *g = *pixel;
            *b = (*(pixel-width)+*(pixel+width))>>1;
        }
    }
    else
    {
        if (x&1)
        {
            *r = (*(pixel-width)+*(pixel+width))>>1;
            *g = *pixel;
            *b = (*(pixel-1)+*(pixel+1))>>1;
        }
        else
        {
            *r = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = *pixel;
        }
    }

}

Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
{
    uint16_t x, y;
    uint8_t r, g, b;
    Mat imageRGB;
    Mat imageBGR;

    // Skip first line
    frame += width;
    uchar data[3*((height-2)*(width-2))];

    uint m = 0;

    for (y=1; y<height-1; y++)
    {
        frame++;
        for (x=1; x<width-1; x++, frame++)
        {
            interpolateBayer(width, x, y, frame, &r, &g, &b);
            data[m++] = b;
            data[m++] = g;
            data[m++] = r;
        }
        frame++;
    }

    imageBGR =  Mat(height - 2,width -2, CV_8UC3, data);

    cvtColor (imageBGR,imageRGB,CV_BGR2RGB);

    return imageBGR;
}

RE: Snapshot with libpixyusb? - Added by Edward Getz 4 months ago

Hello Maxime,
Hmm, I'm not sure what's going on. As an experiment, if you take the data in the pixels array and copy it into new memory, does this fix the issue?

Edward

RE: Snapshot with libpixyusb? - Added by Maxime Torrelli 4 months ago

Hello,

I did not tried this. It can be the solution. Or maybe to copy the cv::Mat image inside another cv::Mat.

I managed to find a solution that works: I save the pixels into "data" in RGB order and then convert it to RGB (it is default format used by openCV from what I understood).
I link the final commented code. If someone manage to fix the problem in a more elegant way, please let me know, I would be very interested to know how to fix it.

Good luck buddies.

Maxime

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <math.h>  
#include <pixy.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <ctime>
#include <iostream>
#include <sstream>
#include <cerrno>
// I put this include because I saw some guy telling to use this lib for the management of 
// argv[2] but during my tests I found that it is actually not needed. I leave it here
// in case my tests where not complete enough.
#if 0
    #include <limits>
#endif

// Maximum number of pictures to be taken
#define NB_PICT_MAX 30

// INSTRUCTION TO COMPILE AFTER INSTALLING OPENCV AND PIXY AS EXPLAINED ON THE WEBSITES OF THESE LIBRARIES:
// g++ -I/usr/include/libusb-1.0/  -I/usr/local/include -L/usr/local/lib/ `pkg-config --cflags --libs opencv` snapshot.cpp -o snapshot -Wall -lpixyusb -lusb-1.0 -lboost_system -lboost_thread -lboost_date_time -lboost_chrono
// The program has been compiled in the following folder. Modifications might be required if you want to compile it in another folder.
// /home/pi/pixy/src/host

// SYSTEM INFO
// g++ --version
// g++ (Raspbian 4.9.2-10) 4.9.2

// Libraries openCV and Pixy installed from my home folder
// /home/pi/opencv
// /home/pi/pixy

// COMMAND TO LAUNCH THE PROGRAM
// sudo ./snapshot genericNameForPictures nbOfPicturesToBeTaken

using namespace cv;
using namespace std;

// Not very clean to declare prototypes like this. Improvements to be done: seperate the main from the other functions and include the corresponsind ".hpp" file
void interpolateBayer(unsigned int width, unsigned int x, unsigned int y, unsigned char *pixel, unsigned int &r, unsigned int &g, unsigned int &b);
Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame);
Mat getImage();

int main(int argc, char * argv[])
{
    int pixy_init_status;
    int return_value;
    int i;
    int nbPict;
    long conv;
    char *p;
    int32_t response;
    Mat image;
    string fileName;
    // Path where to save images
    string path("/home/pi/pixy/calib/");
    // Extension to use to save images (check openCV imwrite() function to learn more)
    string fileExtension(".png");
    string genericName;
    stringstream number;

    errno = 0;

    // Check that there are the right number of arguments (1 generic name to save the pictures and the number of pictures to take)
    if (argc < 3) 
    {

        // Display an error message and stop the program
        cout << "Not enough input arguments. First argument is the generic name of the pictures (without parth or extension) and the second argument is the number of pictures to be taken." << endl;
        return 1;

    } else 
    {
        // Store the arguments into variables
        genericName = argv[1];
        conv = strtol(argv[2], &p, 10);

    }

    // Check for errors: e.g., the string is not empty or the integer is larger than NB_PICT_MAX
    if (errno != 0 || *p != '\0' || conv > NB_PICT_MAX || conv == 0)
    {

        // Display error message
        cout << "Second argument must be an integer between 1 and " << NB_PICT_MAX << endl;
        return 2;

    } else 
    {

        // No error: save number of pictures to take inside an integer (nbPict)
        nbPict = conv;
        cout << "The program will take and save " << nbPict << " pictures." << endl;

    }

    // Initilize Pixy
    pixy_init_status = pixy_init();

    if(!pixy_init_status == 0)
    {

        printf("pixy_init(): ");
        pixy_error(pixy_init_status);
        return pixy_init_status;

    }
    cout << "Init Pixy..." << endl;

    // Stop the Pixy
    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
    if(return_value != 0)
    {
        cout << "Can not stop Pixy" << endl;
        return return_value;
    }
    //cout << "Stop Pixy: " << return_value << endl;

    // Loop from 1 to nbPict
    for(i=1; i<=nbPict; i++)
    {
        // Generate the name for the picture to be taken and then saved
        number.str("");
        number << i;
        fileName = path + genericName + number.str() + fileExtension;

        // Take a picture with Pixy and put it in the required form to be displayed/saved
        image = getImage();

        // Check that Pixy actually sent an image
        if( image.empty() == 1)
        {

            cout << "No image received from Pixy" << endl;
            return 3;

        }

        // Display the image and wait for the user to press any key
        namedWindow( "Snapshot", WINDOW_AUTOSIZE );
        imshow("Snapshot", image);
        waitKey(0);

        // Save the image
        try
        {

            imwrite(fileName, image);

        }
        catch (runtime_error& ex)
        {

            fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
            return 4;

        }

        // Message to tell the user that the picture has been saved
        cout << "Successfully saved " << fileName << " file." << endl;

    }

    return 0;
}

Mat getImage()
{
    // Asks Pixy to send an image and gives this image to renderBA81
    unsigned char *pixels;
    int32_t response, fourcc;
    int8_t renderflags;
    int return_value;
    uint16_t rwidth, rheight;
    uint32_t  numPixels;
    Mat image;
    char fourcc_code[5];

    // Runs the Pixy to make it put a frame inside its video buffer
    return_value = pixy_command("run", END_OUT_ARGS, &response, END_IN_ARGS);
    if(return_value != 0)
    {

        cout << "Can run stop Pixy. Returned value : " << return_value << endl;
        return image;

    }
    //cout << "Run Pixy getImage: " << return_value << endl;

    // Stops the Pixy before asking it to send the frame stored inside its video buffer
    return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
    if(return_value != 0)
    {

        cout << "Can not stop Pixy. Returned value : " << return_value << endl;
        return image;

    }
    //cout << "Stop Pixy getImage: " << return_value << endl;

    // Asks the Pixy to send a frame
    return_value = pixy_command("cam_getFrame",  // String id for remote procedure
                                 /* Mx, or "mode x" where x is either:
                                    0: full resolution mode (1280x800) at 25 frames/sec
                                    1: quarter resolution mode (640x400) at 50 frames/sec -- the imager bins/averages the pixels

                                    Ry, or "resolution y" where y is either:
                                    0: 1280x800 resolution no pixel binning/averaging
                                    1: 640x400 resolution no pixel binning/averaging (only available in mode 1)
                                    2: 320x200 resolution with pixel binning/averaging (also only available in mode 1) */
                                 // mode: CAM_GRAB_M0R0 (0x00), CAM_GRAB_M1R1 (0x11), CAM_GRAB_M1R2 (0x21)
                                 0x01, 0x11,
                                 0x02, 155,        // xoffset
                                 0x02, 90,         // yoffset
                                 // Memory size = 73728 bytes (72K) so width * height must be lower or equel to this
                                 0x02, 330,       // width
                                 0x02, 220,       // height
                                 0,            // separator
                                 &response, &fourcc, &renderflags, &rwidth, &rheight, &numPixels, &pixels, 0);

    // Check that the Pixy successfully returned a frame
    if(return_value != 0)
    {

        cout << "Can not get frame from Pixy. Returned value : " << return_value << endl;
        return image;

    }

    // Convert fourcc code into string
    fourcc_code[0] = fourcc & 0xff;
    fourcc_code[1] = (fourcc >> 8) & 0xff;
    fourcc_code[2] = (fourcc >> 16) & 0xff;
    fourcc_code[3] = (fourcc >> 24) & 0xff;
    fourcc_code[4] = '\0';

    // Display the different values returned by the Pixy
    //cout << "Cam_GetFrame Pixy: " << return_value << endl;
    cout << "Response returned by Pixy : " << response << ", fourcc : " << fourcc_code << ", renderflags : " << renderflags << ", width : " << rwidth << ", height : " << rheight << ", numPixels : " << numPixels << endl;

    // Render frame sent by Pixy
    image = renderBA81(renderflags,rwidth,rheight,numPixels,pixels);

    return image;
}

inline void interpolateBayer(uint16_t width, uint16_t x, uint16_t y, uint8_t *pixel, uint8_t* r, uint8_t* g, uint8_t* b)
{
    // Smear the pixel depending on parity on abscissa and ordinate (parity gives color -> see Bayer matrix for more info about it)
    if (y&1)
    {
        if (x&1)
        {
            *r = *pixel;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
        }
        else
        {
            *r = (*(pixel-1)+*(pixel+1))>>1;
            *g = *pixel;
            *b = (*(pixel-width)+*(pixel+width))>>1;
        }
    }
    else
    {
        if (x&1)
        {
            *r = (*(pixel-width)+*(pixel+width))>>1;
            *g = *pixel;
            *b = (*(pixel-1)+*(pixel+1))>>1;
        }
        else
        {
            *r = (*(pixel-width-1)+*(pixel-width+1)+*(pixel+width-1)+*(pixel+width+1))>>2;
            *g = (*(pixel-1)+*(pixel+1)+*(pixel+width)+*(pixel-width))>>2;
            *b = *pixel;
        }
    }

}

Mat renderBA81(uint8_t renderFlags, uint16_t width, uint16_t height, uint32_t frameLen, uint8_t *frame)
{
    // Receives a frame, call the interpolateBayer function on every pixel of the frame expect for the pixels on the borders (left, right, top and bottom).
    // Data as the folling size : frame_width-2 x frame_height-2
    uint16_t x, y;
    uint8_t r, g, b;
    Mat imageRGB;
    Mat imageBGR;
    uchar data[3*((height-2)*(width-2))];
    uint m = 0;

    // Skip first line
    frame += width;

    // Take each pixel of the frame and perform on it the Bayer interpolation and save the obtained Red, Blue and Green pixels into data.
    for (y=1; y<height-1; y++)
    {

        frame++;
        for (x=1; x<width-1; x++, frame++)
        {

            interpolateBayer(width, x, y, frame, &r, &g, &b);
            // RGB order and conversion to BGR because of memory corruption if directly wrote into BGR and returned. Can't fix the problem in another way.
            // N.B.: BGR because it is default format for openCV
            data[m++] = r;
            data[m++] = g;
            data[m++] = b;

        }

        frame++;

    }

    // "Cast" data to cv::Mat
    imageRGB =  Mat(height - 2,width -2, CV_8UC3, data);

    // Convert matrix from RGB to BGR
    cvtColor (imageRGB,imageBGR,CV_RGB2BGR);

    return imageBGR;
}

« Previous 1 2 (26-41/41)