I want to extract gif frames to raw BGRA data, I used giflib to parse format. I've got first frame (I suppose it's like a key frame in video) that looks good and second (it's 15 frames actually, but let's simplify it) that looks like diff frame. Here is samples:
It seems to be simple to restore second full frame using diff data, but here is the problem: I have no idea what color index means "Not changed". Black pixels on diff frame is actually black – its index in color map is 255, which is rgb(0,0,0). I printed whole color table and didn't found any other black entries. It's here if interested. "BackgroundColor" index is 193, so it makes no sense either.
So, I can't separate "black" color from "no" color. What if second frame will really contain some new black pixels (it contains indeed because left eye moves on animation)? But program should handles it differently: get previous frame color for "no" color and get rgb(0,0,0) for "black" color.
UPD: here is my code. Subframes handling and memory cleanup is ommited. Here I supposed that "no" color index is last in colortable. It works actually for my test file, but I'm not sure it will work in general.
DGifSlurp(image);
int* master = malloc(image->SWidth * image->SHeight * sizeof(int));
for (int i = 0; i < image->ImageCount; i++) {
SavedImage* frame = &image->SavedImages[i];
ColorMapObject* cmap = frame->ImageDesc.ColorMap ? frame->ImageDesc.ColorMap : image->SColorMap;
int nocoloridx = cmap->ColorCount - 1;
IplImage* mat = cvCreateImage(cvSize(frame->ImageDesc.Width, frame->ImageDesc.Height), IPL_DEPTH_8U, 4);
mat->imageData = malloc(frame->ImageDesc.Width * frame->ImageDesc.Height * 4);
for (int y = 0; y < frame->ImageDesc.Height; y++)
for (int x = 0; x < frame->ImageDesc.Width; x++) {
int offset = y * frame->ImageDesc.Width + x;
int coloridx = frame->RasterBits[offset];
if (coloridx == nocoloridx) {
coloridx = master[offset];
} else {
master[offset] = coloridx;
}
GifColorType color = cmap->Colors[coloridx];
cvSetComponent(mat, x, y, 0, color.Blue);
cvSetComponent(mat, x, y, 1, color.Green);
cvSetComponent(mat, x, y, 2, color.Red);
cvSetComponent(mat, x, y, 3, 100);
}
cvNamedWindow("t", CV_WINDOW_AUTOSIZE);
cvShowImage("t", mat);
cvWaitKey(0);
}
Related
Can someone please help me rewrite this code to make the QRcode to use the whole display size (200x200)?
I'm using this display:
https://www.waveshare.com/1.54inch-e-paper-module.htm
Here is the libary which I use to create the QRCode:
https://github.com/ricmoo/qrcode/
Here is a picture of the current state:
click for picture
This is my code:
#include <SPI.h>
#include "epd1in54_V2.h"
#include "qrcode.h"
#include "epdpaint.h"
//set the pins of the ESP32
Epd epd(33, 25, 26, 27); // my Pins ESP32 (Reset, DC, CS, Busy)
unsigned char image[1024];
Paint paint(image, 0, 0);
QRCode qrcode;
#define BLACK 0
#define WHITE 1
void setup()
{
uint8_t qrcodeData[qrcode_getBufferSize(3)];
qrcode_initText(&qrcode, qrcodeData, 3, 0, "https://vinotes.app");
epd.LDirInit();
epd.Clear();
paint.SetWidth(45);
paint.SetHeight(45);
paint.Clear(WHITE);
for (int y = 0; y < qrcode.size; y++) {
for (int x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
paint.DrawPixel(x, y, BLACK);
}
}
}
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
epd.DisplayFrame();
epd.Sleep();
}
void loop()
{
}
Instead of iterating over the size of your QR code, iterate over the size of your display, and request QR modules using coordinates divided by the scaling factor.
There is a very good example in the TouchGFX documentation. (I know you're not using that, but the same principle applies.)
e.g. if you want to scale up your QR code by a factor of 4 (psuedo-ish code):
#define SCALE_FACTOR 4
for (int y = 0; y < HEIGHT; ++y)
{
for (int x = 0, x < WIDTH; ++x)
{
setPixel(x, y, getModule(x / SCALE_FACTOR, y / SCALE_FACTOR));
}
}
You'll want to figure out the maximum scaling factor that will fit, and maybe add some offsets to center the image.
Edit: To be clear, don't actually iterate over the literal width and height of your display, otherwise you won't get a square QR code. The upper bounds of both loops would be (qrcode.size * SCALING_FACTOR).
I'm trying to display number of players detected by Kinect sensor using an WPF application. In addition to displaying number of player I have also coloured the pixels based on their distance from the Kinect. Original goal was to measure the distance of the pixels and display the distance but I would also like to display how many people are in the frame. Here is the code snippets that I'm using now.
PS I have borrowed the idea from THIS tutorial and I'm using SDK 1.8 with XBOX 360 Kinect (1414)
private void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame==null)
{
return;
}
byte[] pixels = GenerateColoredBytes(depthFrame);
int stride = depthFrame.Width * 4;
image.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height,
96, 96, PixelFormats.Bgr32, null, pixels, stride);
}
}
private byte[] GenerateColoredBytes(DepthImageFrame depthFrame)
{
//get the raw data from kinect with the depth for every pixel
short[] rawDepthData = new short[depthFrame.PixelDataLength];
depthFrame.CopyPixelDataTo(rawDepthData);
/*
Use depthFrame to create the image to display on screen
depthFrame contains color information for all pixels in image
*/
//Height * Width *4 (Red, Green, Blue, Empty byte)
Byte[] pixels = new byte[depthFrame.Height * depthFrame.Width * 4];
//Hardcoded loactions for Blue, Green, Red (BGR) index positions
const int BlueIndex = 0;
const int GreenIndex = 1;
const int RedIndex = 2;
//Looping through all distances and picking a RGB colour based on distance
for (int depthIndex = 0, colorIndex = 0;
depthIndex < rawDepthData.Length &&
colorIndex<pixels.Length; depthIndex++, colorIndex+=4)
{
//Getting player
int player = rawDepthData[depthIndex] & DepthImageFrame.PlayerIndexBitmask;
//Getting depth value
int depth =rawDepthData[depthIndex]>>DepthImageFrame.PlayerIndexBitmaskWidth;
//.9M or 2.95'
if (depth <=900 )
{
//Close distance
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 255;
//textBox.Text = "Close Object";
}
//.9M - 2M OR 2.95' - 6.56'
else if (depth >900 && depth<2000)
{
//Bit further away
pixels[colorIndex + BlueIndex] = 255;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 0;
}
else if (depth > 2000)
{
//Far away
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 255;
pixels[colorIndex + RedIndex] = 0;
}
//Coloring all people in Gold
if (player > 0)
{
pixels[colorIndex + BlueIndex] = Colors.Gold.B;
pixels[colorIndex + GreenIndex] = Colors.Gold.G;
pixels[colorIndex + RedIndex] = Colors.Gold.R;
playersValue.Text = player.ToString();
}
}
return pixels;
}
Current goal is to--
Detect total number of players detected and display them in a textBox
Colour them according to the distance logic i.e depth <=900 is red.
With current code I can detect player and color them in Gold but as soon as a player is detected the image freezes and when the player is out of the frame the image unfreezes and acts normal. Is it because of the loop?
Ideas, guidance, recommendation and criticism all are welcome.
Thanks!
Screenshots:
Get a static variable inside your form code
Then set this variable using your video frame routine (dont define it there).
And then update the textbox view, probaply in your _sensor_AllFramesReady
As the arrival of new frames runs in a different thread
I dont see all code maybe to update call textbox.show
the main loop looks a bit strange though, too complex.
basicly you use it to color every pixel in your image.
as the kinect360 has 320x240 pixels so that makes a depth array of size 76800
You might simply create 2 for next loops loops for X and Y and then inside this loop have a variable increase to pick the proper depth value.
I'm trying to use ARtoolkit, but with a static image instead of a video stream. I need to be able to load an image, identify markers, and locate them. I'm using SDL for loading the image. I'm able to obtain the RGB values for each pixel from the loaded image, but I'm unsure how to format the data for ARToolkit to work with it.
ARToolkit stores its images as type ARUint8* (an unsigned char*). I'm confused as to how this format works. Right now I have this code inside the main loop that runs continuously as the program is executing. This code (should) print out the RGB values for each pixel in the frame.
ARUint8* dataPtr;
dataPtr = arVideoGetImage(); // Get a new frame from the webcam
int width, height;
if (arVideoInqSize(&width, &height) == 0) // if width and height could be obtained
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
printf("pixel %i, %i: %i, %i, %i\n", x, y, dataPtr[(y * 320) + x], dataPtr[(y * 320) + x + 1], dataPtr[(y * 320) + x + 2]);
}
}
}
Typical output:
pixel 5, 100: 0, 0, 0
pixel 6, 100: 178, 3, 0
pixel 7, 100: 0, 0, 177
etc...
It seems to be accessing the RGB values correctly, but I'm unsure how to copy over the image data (from SDL's format) into this new format.
Figured it out. Posting answer in case anyone else ever needs it.
On Windows, ARToolkit defaults to BGRA for the dataPtr array. The following function will load an image (using SDL) and return a pointer to a ARUint8 (that contains the image data).
ARUint8* loadImage(char* filename, int* w, int* h)
{
SDL_Surface* img = IMG_Load(filename);
if (!img)
{
printf("Image '%s' failed to load. Error: %s\n", filename, IMG_GetError());
return NULL;
}
*w = img->w; // Assign width and height to the given pointers
*h = img->h;
ARUint8* dataPtr = (ARUint8*)calloc(img->w * img->h * 4, sizeof(ARUint8)); // Allocate space for image data
// Write image data to the dataPtr variable
for (int y = 0; y < img->h; y++)
{
for (int x = 0; x < img->w; x++)
{
Uint8 r, g, b;
SDL_GetRGB(getpixel(img, x, y), img->format, &r, &g, &b); // Get the RGB values
int i = ((y * img->w) + x) * 4; // Figure out index in array
dataPtr[i] = b;
dataPtr[i + 1] = g;
dataPtr[i + 2] = r;
dataPtr[i + 3] = 0; // Alpha
}
}
SDL_FreeSurface(img);
return dataPtr;
}
The getpixel function is borrowed from here: http://sdl.beuc.net/sdl.wiki/Pixel_Access
This function allowed me to use a photograph instead of a video feed from a webcam.
Here's my situation. I'm using Processing 2.0, and I'm trying to make a grid of squares turned at a 45-degree angle. Each square will be filled with a color chosen randomly from a palette of five. My problem is this; for some reason, when I use COLORS[int(random(COLORS.length))] to get a color from my palette, I only get black! It's doubly weird because black is not one of the colors in my palette! I have tested my floodFill() function, and I can confirm that it works, as testing with a single color not pulled from an array works all right. Any tips? My code is as follows:
final int DX = 16, DY = DX;
final color DEFAULT_BG = color(50, 50, 50);
final color[] COLORS = {
color(#ff3333),
color(#4fff55),
color(#585eff),
color(#ebff55),
color(#FF55D5),
};
void setup() {
size(800, 480);
background(DEFAULT_BG);
noSmooth();
for (int x = 0; x < width; x += DX) {
for (int y = 0; y < height; y += DY) {
line(x, y, x + 16, y + 16);
line(x + 16, y, x, y + 16);
}
}
for (int x = 0; x < width; x += 4) {
for (int y = 0; y < height; y += 4) {
if (get(x, y) == DEFAULT_BG) {
color f = COLORS[int(random(COLORS.length))];
floodFill(x, y, DEFAULT_BG, color(f));
}
}
}
}
void floodFill(final int x, final int y, final color from, final color to) {
if (!(x < 0 || y < 0 || x >= width || y >= height || from == to || get(x, y) != from)) {
set(x, y, to);
floodFill(x, y + 1, from, to);
floodFill(x, y - 1, from, to);
floodFill(x + 1, y, from, to);
floodFill(x - 1, y, from, to);
}
}
When I replace the #rrggbb notation with 0xrrggbb, I get white instead. When I replace it with 0xrrggbbaa, I get black and white (not grayscale).
Now using the standard color(r, g, b) notation works fine. However, I'd still like to know what breaks the hexadecimal versions, so I'll leave this question open.
color() does not take hex values. It takes simple int values from 0 - 255. Try printing out the value of one of your color() calls with hex values in it and you'll get some crazy negative value.
Any negative value fed into the color() method will be interpreted as 0, which equals black. Try it in Processing if you'd like to see its affect.
Like you figured it out, use color(r,g,b) using values ranging from 0 - 255 for r, g, b respectively.
I need to draw raw pixel data to the Nintendo DS's "sub" screen, such as if I was drawing to the main screen in "framebuffer" mode or "Extended Rotation" mode. How can I do this with the current version of libnds (which seems to place restrictions on the use of VRAM_C)?
#include <nds.h>
int main(void)
{
int x, y;
//set the mode to allow for an extended rotation background
videoSetMode(MODE_5_2D);
videoSetModeSub(MODE_5_2D);
//allocate a vram bank for each display
vramSetBankA(VRAM_A_MAIN_BG);
vramSetBankC(VRAM_C_SUB_BG);
//create a background on each display
int bgMain = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0,0);
int bgSub = bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0,0);
u16* videoMemoryMain = bgGetGfxPtr(bgMain);
u16* videoMemorySub = bgGetGfxPtr(bgSub);
//initialize it with a color
for(x = 0; x < 256; x++)
for(y = 0; y < 256; y++)
{
videoMemoryMain[x + y * 256] = ARGB16(1, 31, 0, 0);
videoMemorySub[x + y * 256] = ARGB16(1, 0, 0, 31);
}
while(1)
{
swiWaitForVBlank();
}
}
Here is a simple example which creates a 16 bit frame buffer on the main and sub screens and fills each with either red or blue.