C: Best way to make a buffer copy of an Image Map - c

I have a struct that basically has these contents:
typedef struct {
unsigned int width, height;
float *r, *g, *b;
} image;
Using the FreeImage.h library I am able to open a certain image and associate the pixels with its RGB colours. So the code is as follows:
imagem open_image(char *name_of_file) {
FIBITMAP *bitmapIn;
int x, y;
RGBQUAD color;
image I;
bitmapIn = FreeImage_Load(FIF_JPEG, name_of_file, 0);
if (bitmapIn == 0) {
printf("Error! File not found - %s\n", name_of_file);
} else {
printf("File found!\n");
}
x = FreeImage_GetWidth(bitmapIn);
y = FreeImage_GetHeight(bitmapIn);
I.width = x;
I.height = y;
I.r = malloc(sizeof(float) * x * y);
I.g = malloc(sizeof(float) * x * y);
I.b = malloc(sizeof(float) * x * y);
for (int i=0; i<x; i++) {
for (int j=0; j <y; j++) {
int idx;
FreeImage_GetPixelColor(bitmapIn, i, j, &color);
idx = i + (j*x);
I.r[idx] = color.rgbRed;
I.g[idx] = color.rgbGreen;
I.b[idx] = color.rgbBlue;
}
}
return I;
}
So now when I call the function in my main file like:
image img = open_image("file_name");
I have my image "map" in my reference named img.
Basically what I want to know is what is the best way to make a copy of this img so that I can apply a filter in this buffer img, for exemple a blur filter. That way when I get the surrounding pixels values to write to the central one, it is always the original pixels so get the pixels from "img" and write them with the filter to the "img_buffer".
I guess I could just make another reference named img_buff and call the open_image function again but that takes to much real and user time.
So how would you suggest I made the copy? From my research I found that memcpy() maybe won't do the trick since it gives me a shallow copy but not to sure about it.
Any suggestion that won't take to much more real/user time is welcome!

If you want to improve performances,you should try to avoid copies which are time-consuming specially for large arrays.
But I assume you can't, so there is a solution :
Image imgCopy;
imgCopy.width = img.width
imgCopy.height = img.height
In a first time you allocate memory :
imgCopy.r = (float*)malloc(sizeof(float) * imgCopy.width * imgCopy.height );
imgCopy.g = (float*)malloc(sizeof(float) * imgCopy.width * imgCopy.height );
imgCopy.b = (float*)malloc(sizeof(float) * imgCopy.width * imgCopy.height );
Then you can copy the pointer's content :
*(imgCopy.r) = *(img.r);
*(imgCopy.g) = *(img.r);
*(imgCopy.b) = *(img.r);

Related

Nested boxes: what am I missing?

I have to create an efficient program in C(99) where I have n boxes and I can insert one of them into another one (of the same n boxes), like a matryoshka. The goal is to find the maximum number of boxes that can be insereted and list them from the outside one to the most inside one (including the outside one). So, given x (width), y (height) and z (depth), all >= 0, a box can be inserted into another if x[i] < x[j] and y[i] < y[j] and z[i] < z[j] where i and j are the indexes (starting from 0) of two boxes. Boxes can't be rotated!.
The input file has this structure:
x[0] y[0] z[0]
…
x[n-1] y[n-1] z[n-1]
This is what I could achieve in some days of work:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Array Boxes;
struct Array {
unsigned int count;
struct Box **elements;
};
struct Box {
int id;
double x;
double y;
double z;
struct Array inside;
};
int n;
/**
* Pretty print the boxes, according to the resulting output format
*
* #param boxes
*/
void print_boxes(Boxes boxes) {
printf("%d boxes\n", boxes.count);
for (int i = 0; i < boxes.count; ++i) {
struct Box box = *(boxes.elements[i]);
printf("box %d: %f %f %f - How many inside? %d\n", box.id, box.x, box.y, box.z, box.inside.count);
}
}
/**
* Append a box to an array
*
* #param arr
* #param box
* #param mem_alloc if true, memory will be allocated before appending the new box
*/
void array_append(struct Array *arr, struct Box *box, bool mem_alloc) {
if (mem_alloc) {
if (arr->count == 0) {
arr->elements = malloc(sizeof(struct Box *));
} else {
arr->elements = reallocarray(arr->elements, arr->count + 1, sizeof(struct Box *));
}
}
arr->elements[arr->count] = box;
arr->count += 1;
}
struct Array find_inside_boxes(Boxes boxes, struct Box *box) {
struct Array boxes_inside = {0, malloc(boxes.count * sizeof(struct Box *))};
for (int i = 0; i < boxes.count; ++i) {
struct Box *b = boxes.elements[i];
if (b->x < box->x && b->y < box->y && b->z < box->z) {
array_append(&boxes_inside, b, false);
}
}
return boxes_inside;
}
struct Box *find_best_box(Boxes boxes) {
struct Box *max = boxes.elements[0];
for (int i = 1; i < boxes.count; ++i) {
struct Box *box = boxes.elements[i];
if (box->inside.count > max->inside.count) {
max = box;
}
}
return max;
}
void print_inside_boxes(struct Box *box) {
Boxes boxes = {0, NULL};
array_append(&boxes, box, true);
while (box->inside.count > 0) {
box = find_best_box(box->inside);
array_append(&boxes, box, true);
}
print_boxes(boxes);
}
int main(int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
if (!file) {
printf("No input or can't open the input file");
return EXIT_FAILURE;
}
fscanf(file, "%d\n", &n);
double x, y, z;
Boxes boxes = {n, malloc(n * sizeof(struct Box))};
for (int i = 0; fscanf(file, "%lf%lf%lf", &x, &y, &z) != EOF; i++) {
struct Box *box = malloc(sizeof(struct Box));
box->id = i;
box->x = x;
box->y = y;
box->z = z;
boxes.elements[i] = box;
}
fclose(file);
for (int i = 0; i < boxes.count; ++i) {
struct Box *box = boxes.elements[i];
box->inside = find_inside_boxes(boxes, box);
}
struct Box *best = find_best_box(boxes);
print_inside_boxes(best);
return EXIT_SUCCESS;
}
Basically, it gets the maximum box by its volume and it repeats this until there are no more boxes. Boxes are deleted from the boxes array if their dimensions (x, y, z) are incompatible with the latest box found.
This code mostly works. The issue is that it doesn't work with the last test file I have. I have these test files (.in files are input files, where .out are the expected outputs):
Sample 1: Input - Output
Sample 2: Input - Output
Sample 3: Input - Output
The program works with samples 1 and 2 (the first sample output differs for one line which is fine if the number of the boxes is valid and listed boxes follow the inserting condition). What doesn't work is sample 3: the program finds less boxes than the expected ones (my program finds the first board as 730 while the expected output is 714). What am I missing or what is wrong in my code? Can you help me to fix it, since I have little time left to deliver this.
Thanks to anyone who tries to help me!

Syntax not clear about pointers and matrix

i am coding in C and i have to work with png images, so i work with libpng library. In my project i use this structure:
png_bytep *row_pointers; /* <-- to declare the pointer that will contain the image
and this to initialize the pointer to contain the image. */
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for(int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
}
My problem is: after this piece of code my image is copyed in row_pointers and i want to copy it in a png_byte map[x][y] so i can work easly pixel for pixel.
Someone can help me?
Thanks
Ok. That is pointer to pointer!
png_bytep = pointer to png_byte
If you eliminate png_bytep and just use png_byte your code will look like this.
int height = 10;
int width = 20;
png_byte **row_pointers;
row_pointers = (png_byte**)malloc(sizeof(png_byte*) * height); <-- This is basically your number of rows.. ie height of your matrix.
for(int y = 0; y < height; y++)
{
row_pointers[y] = (png_byte*)malloc(sizeof(png_byte)*width); <-- This is representing number of elements in each row.. so width.
}
Assuming your structure have two ints x and y. you must be filing data as below..
for(int i=0;i< height;i++)
{
for (int j=0;j<width;j++)
{
row_pointers[i][j].x = i*j;
row_pointers[i][j].y = i*j;
}
}
Assuming your map also have similar structure. This is how you copy data..
for(int i=0;i< height;i++)
{
for (int j=0;j<width;j++)
{
map[i][j].x = row_pointers[i][j].x;
map[i][j].y = row_pointers[i][j].y;
}
}
Have a look at pnm2png.c in libpng's contrib/pngminus directory.
In this code, "png_pixels" is a simple array that holds all the pixels, and row_pointers is an array of pointers that point to the beginning of each row within png_pixels:
/* row_bytes is the width x number of channels x (bit-depth / 8) */
row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))
/* set the individual row_pointers to point at the correct offsets */
for (i = 0; i < (height); i++)
row_pointers[i] = png_pixels + i * row_bytes;
/* now we can go ahead and just read the whole image */
png_read_image (png_ptr, row_pointers);
Once png_read_image completes, you can easily work with your pixels in the png_pixels array.
Notice that there is only one "malloc", which allocates png_pixels. Instead of doing a separate "malloc" for each row, this code calculates the values of the row_pointers.

Crop an image from a byte array

I have an image (which is a Sprite) that I store it in a byte array.
I would like to extract only the bytes that relate to a specific place and size within this byte array so that I can create a new image, basically a crop.
I am using C# and compact cf. I could use get pixel and save each value to a byte array and then 'read' the portion i am interested back. I know I can use LockBitmap() to make this quicker. I would normally use Aforge and/or Emgu but as I say I am using the compact cf framework 2.
I would be interested in any known ways to do this.
Thanks
Additional.
Following on the link below I would like to know whether there is an alternative (like a buffer copy) to this iterative piece of code?
//Iterate the selected area of the original image, and the full area of the new image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width * BPP; j += BPP)
{
int origIndex = (startX * rawOriginal.Stride) + (i * rawOriginal.Stride) + (startY * BPP) + (j);
int croppedIndex = (i * width * BPP) + (j);
//copy data: once for each channel
for (int k = 0; k < BPP; k++)
{
croppedBytes[croppedIndex + k] = origBytes[origIndex + k];
}
}
}
I understand that this is an old question, but here's my take on it:
public static byte[] CropImageArray(byte[] pixels, int sourceWidth, int bitsPerPixel, Int32Rect rect)
{
var blockSize = bitsPerPixel / 8;
var outputPixels = new byte[rect.Width * rect.Height * blockSize];
//Create the array of bytes.
for (var line = 0; line <= rect.Height - 1; line++)
{
var sourceIndex = ((rect.Y + line) * sourceWidth + rect.X) * blockSize;
var destinationIndex = line * rect.Width * blockSize;
Array.Copy(pixels, sourceIndex, outputPixels, destinationIndex, rect.Width * blockSize);
}
return outputPixels;
}
You'll need to know the bits per pixel and the width. You'll be using one for instead of two.
I have some more links for you
Try out if you find you solution or it helps you in any way
1)http://www.codeproject.com/Articles/33838/Image-Processing-using-C
2)http://codenicely.blogspot.in/2012/03/how-to-crop-image-in-c.html

Float / Array error reading from CSV

I'm missing something fundamental here but I can't seem to find out what from all my research.
I have imported a csv file, split the string into floats, and now wish to connect all points to all other points with a line. My code is as follows:
String [] data;
void setup () {
size(300, 300);
background(255);
data = loadStrings("points.csv");
for (int i = 0; i < data.length; i++) {
String [] fields = split(data[i], ',');
float t = float(fields[0]);
float n = float(fields[1]);
float x = float(fields[2]);
float y = float(fields[3]);
ellipse(x, y, 10, 10);
line(x, y, x[i], y[i]);
}
}
The error message is "The type of expression must be an array type but it resolved to float"
I'm sure this is extremely basic but, I dont understand why x[i] or y[i] are not seen as an array type.
I would really appreciate any help with this. Many thanks in advance.
Sam
*UPDATE***
An exract from the points.csv file is as follows:
219185750 rabih_takkoush 20.88521 19.49821
219185716 MoustaphaAjram 100.870896 59.515259
219185709 jinanejghosh 56.886441 35.489087
219185557 MoustaphaAjram 34.870904 78.515243
219185555 Mohammad8Itani 12.8946 49.48179
What I am trying to accomplish is plotting the various geolocations (whereby col 3 = x, col 4 = y) and then connecting all points with all other points with a line.
The following script works plotting all locations specified in the array within the script:
float[] x = { 50, 100, 150, 200,20,20 };
float[] y = { 10, 30, 20, 250,20,90 };
void setup () {
size(300, 300);
background(255);
}
void draw() {
for (int i = 0; i < x.length; i++) {
ellipse(x[i], y[i], 10, 10);
for (int j = 0; j < x.length; j++) {
line(x[j], y[j], x[i], y[i]);
}
}
}
What I wish to do is do the same, but reading columns 3 and 4 of the csv file.
You're splitting your data into iteration-scoped floats, then you try to access them as if they're both floats as well as arrays in your line() call. Try this:
String[] data;
float[] x, y, t, n;
void setup () {
size(300, 300);
data = loadStrings("points.csv");
int len = data.length;
x = new float[len];
x = new float[len];
t = new float[len];
n = new float[len];
for (int i=0; i<len; i++) {
String line = data[i];
String[] fields = split(line, ',');
t[i] = float(fields[0]),
n[i] = float(fields[1]),
x[i] = float(fields[2]),
y[i] = float(fields[3]);
}
// don't put draw instructions in setup,
// put them in draw. if you want to run once,
// issue a noLoop() so that happens.
noLoop();
}
void draw() {
float prevx = x[0], prevy = y[0];
for (int i=0, last=x.length; i<last; i++) {
ellipse(x[i], y[i], 10, 10);
line(prevx,prevy, x[i],y[i]);
prevx=x[i];
prevy=y[i];
}
}
Now we're storing the data from CVS in linked arrays that we can access throughout the sketch, rather than throwing them away after setup().
ok so if you go with the first code you made, you only need to change a few things, here is what you can do:
float[] x;
float[] y;
string[] data;
void setup () {
size(300, 300);
background(255);
data = loadStrings("points.csv");
x = new float[data.length];
y = new float[data.length];
for (int i = 0; i < data.length; i++) {
String [] fields = split(data[i], ',');
float t = float(fields[0]);
float n = float(fields[1]);
float x = float(fields[2]);
float y = float(fields[3]);
}
}
void draw() {
for (int i = 0; i < x.length; i++) {
ellipse(x[i], y[i], 10, 10);
for (int j = 0; j < x.length; j++) {
line(x[j], y[j], x[i], y[i]);
}
}
}
As you can see nothing really new, it's a mix between your initial code and the one you made for the csv.
And actually you mainly needed to declare your x and y variables as float[] instead of just float. But also there were some changes to make in the loop.
In this code you load the data in your arrays first (exactly like you did by declaring array's values in your code, but this time you read these values from your file), and then call your draw method as before.
hope it works now

Take screenshot with openGL and save it as png

I'm trying to take a screenshot of full screen and save it as a png. I found a code here and modified it a bit. For the screenshot I use openGL and Glut and for the saving in png the gd library for c. All I'm getting is a black png and I can't figure out why. I searched in stackoverflow and found some posts, but unfortunately they didn't help. One of them was to use glReadBuffer( GL_FRONT); instead of glReadBuffer(GL_BACK); I tryed with both of them with no success. Here is my code:
int SVimage2file(char *filename){
int width = glutGet(GLUT_SCREEN_WIDTH);
int height = glutGet( GLUT_SCREEN_HEIGHT);
FILE *png;
GLubyte *OpenGLimage, *p;
gdImagePtr image;
unsigned int r, g, b;
int i,j,rgb;
png = fopen(filename, "wb");
if (png == NULL) {
printf("*** warning: unable to write to %s\n",filename);
return 1;
}
OpenGLimage = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3);
if(OpenGLimage == NULL){
printf("error allocating image:%s\n",filename);
exit(1);
}
printf("Saving to: %s .\n",filename);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadBuffer( GL_FRONT);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, OpenGLimage);
p = OpenGLimage;
image = gdImageCreateTrueColor(width,height);
for (i = height-1 ; i>=0; i--) {
for(j=0;j<width;j++){
r=*p++; g=*p++; b=*p++;
rgb = (r<<16)|(g<<8)|b;
//printf("the rgb color %d\n", rgb );
gdImageSetPixel(image,j,i,rgb);
}
}
gdImagePng(image,png);
fclose(png);
gdImageDestroy(image);
}
What is it that I'm missing?
You could use the devil image library and take a screeshot with:
void takeScreenshot(const char* screenshotFile)
{
ILuint imageID = ilGenImage();
ilBindImage(imageID);
ilutGLScreen();
ilEnable(IL_FILE_OVERWRITE);
ilSaveImage(screenshotFile);
ilDeleteImage(imageID);
printf("Screenshot saved to: %s\n", screenshotFile);
}
takeScreenshot("screenshot.png");
If you don't reject to use C++ library, you should try PNGwriter! It write the picture pixel by pixel and their RGB values. Since the PNGwriter start form left-up corner while the glReadPixels() start from left-bottom, your code while like:
GLfloat* OpenGLimage = new GLfloat[nPixels];
glReadPixels(0.0, 0.0, width, height,GL_RGB, GL_FLOAT, OpenGLimage);
pngwriter PNG(width, height, 1.0, fileName);
size_t x = 1; // start the top and leftmost point of the window
size_t y = 1;
double R, G, B;
for(size_t i=0; i<npixels; i++)
{
switch(i%3) //the OpenGLimage array look like [R1, G1, B1, R2, G2, B2,...]
{
case 2:
B = (double) pixels[i]; break;
case 1:
G = (double) pixels[i]; break;
case 0:
R = (double) pixels[i];
PNG.plot(x, y, R, G, B);
if( x == width )
{
x=1;
y++;
}
else
{ x++; }
break;
}
}
PNG.close();
PS. I had also try libgd, but it seems only convert one image file (in the hard disk or in memory) to another format of image. But I think it still useful while you want to convert many PNG file to GIF format to create a GIF animate.

Resources