Click here to Skip to main content
15,940,550 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm working with bmp images, which I'm passing a a 2d array by reference to a function that opens the bmp and stores it using a struct. When the function exits, I have a reference to an address. I can add it to a new array to store the opened bmp, but as it is a reference all locations of the new array have the same reference.

see https://www.codeproject.com/Questions/5248639/Why-is-my-array-index-values-all-the-same as a reference to my original problem.

So I need to de-reference and only insert the 2d array values. How do I go about doing this.

C++
typedef struct pixel {
	uint8_t r;
	uint8_t g;
	uint8_t b;

} pixel;

//image_names = name of all images which have been sorted
//num_images = total number of images
//IMG_Y = 360
//IMG_X = 640

pixel** img;
struct pixel** images[num_images];

// Allocate image structure which will be used to load images
img = (pixel**)malloc (IMG_Y * sizeof (pixel*));
for (i = 0; i < IMG_Y; i++) 
{
		img[i] = (pixel*)malloc (IMG_X * sizeof (pixel));
}

for (i = 0; i < num_images; i++)
{
	// Open image and ensure it's successful. 
	if (open_bmp (*(image_names + i), img) == EXIT_FAILURE) 
    {
		return EXIT_FAILURE;
	}

	images[i] = img;
	}
}

int open_bmp (char * file_name, pixel** img) {
	// Variable declarations
	long offset = 0;
	unsigned char buff[100];
	int x = 0, y = 0;
	FILE *f = fopen (file_name, "rb"); // open file in binary mode

	// Read pixel data
	fseek (f, offset, SEEK_SET); // go to beginning of pixel data
	while ((fread (&buff, 3, 1, f) >= 1) && y < IMG_Y) // while not EOF (or done with image), read next pixel
	{
		img[y][x].r = buff[2];
		img[y][x].g = buff[1];
		img[y][x].b = buff[0];

		x++; // read next column
		if (x >= IMG_X) { // finished reading row, go to next row
			y++;
			x = 0;
		}
	}

	if (PRINTBMPDATA) {
		for (y = 0; y < IMG_Y; y++) {
			for (x = 0; x < IMG_X; x++) {
				printf ("%02x%02x%02x ", img[y][x].b, img[y][x].g, img[y][x].r);
			}
			printf ("\n");
		}
		printf ("\n");
	}

	// Close image file now that we have copied it to the img structure
	if (fclose (f)) {
		printf ("Unable to close image file\n");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}


What I have tried:

What I have attempted to do was de-reference. Which only inserted a single value of 0.

C++
images[i] = **img
the result was just a 1D array

Next I thought I should attempt to pass a 3D array, modify the open_bmp() and just do the same thing I'm doing now, but when passed to open_bmp() fill levels 2 and 3. here are the changes I made.
C++
pixel*** img;

	// Allocate image structure which will be used to load images
	img = (pixel***)malloc (num_images * sizeof (pixel**));
	for(i = 0; i < num_images; i++)
	{

		img[i] = (pixel**)malloc (IMG_Y * sizeof (pixel*));
		for (k = 0; k < IMG_Y; i++)
			img[i][k] = (pixel*)malloc (IMG_X * sizeof (pixel));
	}

for (i = 0; i < num_images; i++)
	{
	// Open image and ensure it's successful. Inefficent to load file everytime but fine at BeagleBone's low effective video framerates
		if (open_bmp (*(image_names + i), img, i) == EXIT_FAILURE) {
			return EXIT_FAILURE;
		}
	}

int open_bmp (char * file_name, pixel*** img, int idx) {

	printf ("Index: %d\n", idx);
	// Variable declarations
	long offset = 0;
	unsigned char buff[100];
	int x = 0, y = 0;
	FILE *f = fopen (file_name, "rb"); // open file in binary mode

	// Read pixel data
	fseek (f, offset, SEEK_SET); // go to beginning of pixel data
	while ((fread (&buff, 3, 1, f) >= 1) && y < IMG_Y) // while not EOF (or done with image), read next pixel
	{
		img[idx][y][x].r = buff[2];
		img[idx][y][x].g = buff[1];
		img[idx][y][x].b = buff[0];

		x++; // read next column
		if (x >= IMG_X) { // finished reading row, go to next row
			y++;
			x = 0;
		}
	}

	if (PRINTBMPDATA) {
		for (y = 0; y < IMG_Y; y++) {
			for (x = 0; x < IMG_X; x++) {
				printf ("%02x%02x%02x ", img[idx][y][x].b, img[idx][y][x].g, img[idx][y][x].r);
			}
			printf ("\n");
		}
		printf ("\n");
	}

	// Close image file now that we have copied it to the img structure
	if (fclose (f)) {
		printf ("Unable to close image file\n");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}
while I wrote a test case and it works fine, I've found a lot of references stating 3d+ arrays are a bad idea in this manner. The other issue, is the actual program doesn't execute.
Posted
Updated 18-Oct-19 7:30am
v3

I show you how to allocate (and release) memory.
The following code loads data from fixed sized (36x64x3 bytes) 'image' files named 'img00.bmp', 'img01.bmp', ..
Then prints the pixel contents (numbers) to the console.
Finally cleans up memory and exits.
You may use it as starting point (not if your images have not the same size then you should create an image struct containing the image width and height, together with actual pixel data).
C
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


typedef struct pixel
{
  uint8_t r;
  uint8_t g;
  uint8_t b;
} pixel;

#define IMG_Y  36
#define IMG_X  64

int open_bmp (pixel *** images, int image_no);
void dump_image( pixel ** image );

int main()
{
  size_t num_images;
  printf("please enter the number of images:\n");
  if ( scanf("%lu", &num_images ) != 1 || num_images > 16)
  {
    fprintf(stderr, "invalid input\n");
    return -1;
  }

  struct pixel ** images[num_images];

  // allocate memory
  for (size_t n=0; n<num_images; ++n)
  {
    images[n] = (pixel ** ) malloc (IMG_Y * sizeof( pixel * ));
    assert(images[n]); 
    for (size_t y = 0; y<IMG_Y; ++y)
    {
      images[n][y] = (pixel *) malloc( IMG_X * sizeof( pixel));
      assert(images[n][y]);
    }
    assert( ! open_bmp(  images, n )  );
  }

  // show the content of the images
  for (size_t n=0; n<num_images; ++n)
    dump_image(images[n]);

  // cleanup
  for (size_t n=0; n<num_images; ++n)
  { 
    for (size_t y = 0; y<IMG_Y; ++y)
      free( images[n][y] );
    free(images[n]);
  }
}

int open_bmp (pixel *** images, int image_no)
{

  char filename[] = "imgNN.bmp";
  sprintf(filename, "img%02d.bmp", image_no);
  FILE * fp = fopen(filename, "rb");
  if ( ! fp ) return -1;

  pixel ** image = images[image_no];

  for (size_t y = 0; y < IMG_Y; ++y)
  {
    pixel * row = image[y];
    for ( size_t x = 0; x < IMG_X; ++x)
    {
      uint8_t buf[3];
      if ( fread( &buf, 3, 1, fp ) != 1 )
        return -2;
      row[x].r = buf[2];
      row[x].g = buf[1];
      row[x].b = buf[0];
    }
  }
  fclose(fp);
  return 0;
}

void dump_image( pixel ** image )
{
  for (size_t y = 0; y < IMG_Y; ++y)
  {
    pixel * row = image[y];
    for ( size_t x = 0; x < IMG_X; ++x)
    {
      printf("{%03d, %03d, %03d}, ", row[x].r, row[x].g, row[x].b);
    }
    printf("\n");
  }
}
 
Share this answer
 
I am not sure I understand your problem, but you are processing the file incorrectly. A bitmap file is not a simple 2d array of pixels; see Bitmap Storage - Windows applications | Microsoft Docs[^]. Depending on what you are trying to do all you need to read the file, is allocate a buffer large enough to contain the entire content, and read the file direct into that buffer. You can then save the address of that buffer in a simple array or set of structs. You can then process the actual bitmap data in memory as required by your application.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900