libpixyusb uses a middleware called “chirp” to communicate over USB. Chirp can look at the message size coming from Pixy and allocate its buffer memory accordingly.
You’ll lose the frame data once another chirp message comes in, so it’s up to you to copy the data — but if you stop pixy’s program and you don’t issue any more commands, no messages will come in and your data will remain intact.
Rich,
Thanks very much for your help! Everything seems to be working well. For future reference, here is a working bit of code to grab a 1280x40 block. No doubt it could be improved. Next stop: spectral data acquisition.
//example of using libpixyusb to grab a 1280x40 block (maximum camera resolution)
#include
#include
#include
#include
#include
#include "pixy.h"
void handle_SIGINT(int unused)
{
// On CTRL+C - abort //
printf("\nBye!\n");
exit(0);
}
int main(int argc, char * argv[])
{
int pixy_init_status;
// Catch CTRL+C (SIGINT) signals //
signal(SIGINT, handle_SIGINT);
// Connect to Pixy //
pixy_init_status = pixy_init();
printf("initialized Pixy - %d\n", pixy_init_status);
if(pixy_init_status != 0)
{
// Error initializing Pixy
pixy_error(pixy_init_status);
return pixy_init_status;
}
// getFrame Example //
{ //local
unsigned char current_frame[72000]; // ~largest possible given current hardware
unsigned char *pixels; //returned pointer to video frame buffer
int32_t response, fourcc;
int8_t renderflags;
int return_value, res;
uint16_t width, height;
uint32_t numPixels;
// stop blob processing
return_value = pixy_command("stop", END_OUT_ARGS, &response, END_IN_ARGS);
printf("STOP returned %d response %d\n", return_value, response);
response = 0;
return_value = pixy_command("cam_getFrame", // String id for remote procedure
0x01, 0x00, // mode 0 = 1280x800 25 fps
0x02, 0, // xoffset
0x02, 0, // yoffset
0x02, 1280, // width
0x02, 40, // height (56 max @ 1280 w)
0, // separator
&response, // pointer to mem address for return value
&fourcc, //contrary to docs, the next 5 args are needed
&renderflags,
&width,
&height,
&numPixels,
&pixels, // pointer to mem address for returned frame
0);
printf("getFrame returned %d response %d\n", return_value, response);
printf("returned w %d h %d npix %d\n",width,height,numPixels);
// quit now if not successful:
if(return_value != 0) return return_value;
// save this block
memcpy(¤t_frame, pixels,numPixels);
// display average and 8x8 pixel dump
unsigned int i,j,ind,start;
unsigned long avg=0;
for(i=0; i<numPixels; i++) avg += current_frame[i];
avg = avg/numPixels;
printf("average pixel value %d\n",avg);
// dump a few raw pixels
start=(height/2)*width+width/2; //roughly in middle of frame
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
ind = i*width + j + start;
printf(" %02x",current_frame[ind]);
}
printf("\n");
}
// Sleep for 1/10 sec //
while(1) usleep(100000); //(exit on ^C)
} //end local
}
You can grab and then write out a raw frame and, using imagemagick, convert that into a “pseudo-gray” .PNG file.
It won’t be proper RGB format. To do that, the frame needs to be Bayer-interpolated in the proper way. I started working on that and got distracted by other projects, so if anyone wants to take up the challenge, others (including me) would appreciate it! Look into the PixyMon source code for the Bayer interpolation procedure.
The imagemagick command to convert a raw 320x200 frame to .PNG format is:
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?
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?
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.
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:
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.
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.
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?
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.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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 < 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;
}