GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #31  
Old 05-Nov-2007, 10:57
Soundzz Soundzz is offline
Awaiting Email Confirmation
 
Join Date: Oct 2007
Posts: 14
Soundzz is on a distinguished road

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
Originally Posted by davekw7x
SKIP
wow!!!!! it solves my problem exactly!! By changing the "r" into "rb" !! Really thank you very much! and now I know that the different between r and rb~

Really Thank you a lot!!!

Regards
  #32  
Old 05-Nov-2007, 11:19
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,218
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
Originally Posted by Soundzz
..Thank you...
You are very welcome. (And thanks to Howard, too, for providing the program example for reading the header information.)

Regards,

Dave
  #33  
Old 07-Nov-2007, 12:29
Howard_L Howard_L is offline
Regular Member
 
Join Date: Apr 2007
Location: Maryland/PA, USA
Posts: 803
Howard_L is a jewel in the roughHoward_L is a jewel in the roughHoward_L is a jewel in the rough

Re: How to get the pixels' value of a bmp image? (Pelles C)


I hadn't been checking in over here at C++ due to self-imposed fun-time limits.
The email notifications promted me to take a look. I had forgotten about the post I made earlier! (it's getting worse...)

I see how the fopen(x.x, "rb"); is all important. But not in linux?
When I saw that 0x1a is ctrl-z in MS I was rememberred that there was the ctrl-d (0x04) in linux which was similar. I don't know, thought I'd ask.

On reviewing the pages, way back on page 1 a point was made about pixel data width, which is what we're getting in iheader.width, and the need to take into account that byte padding may be applied if the total pixel bytes do not add up to be a multiple of 4. I was curious about it and so made this exercise program to look into it and I wondered if I was getting the concept right:
CPP / C++ / C Code:
#include <stdio.h>    /* width_exc.c */

int main(void)
{
  unsigned int a, b, c, d, e, f, g, i, start, end;
  start = 400;
  end   = 390;
  printf("\n\
\"Exercise for the student:  suppose it had a width of 399 pixels,\n\
how many padding bytes would be required for each row?\n\
How about 398? 397? 396?\" \n");

  printf("\n...so if we have a 24-bit .bmp which is 3 bytes per pixel.... \n");

  printf("\niheader.width  The math:       Tbytes                   Padding bytes needed\n");
  for(i = start; i > end; i--)
  {
    a = i * 3;  /* total bytes                                            */
    b = a % 4;  /* remainder after dividing by block-size                 */
    c = 4 - b;  /* the amount needed to bring up to full 1 block-size (4) */
    d = c % 4;  /* get rid of that 4 for widths which already fit correctly */
    e = (4-((i * 3)%4))%4 ;  /* seems like this can be shortened but I suffer from algeblock */
    printf(" %10u  (4 - ( (%u * 3 = %u) %% 4 = %u) = %u) %%4 =    %u \n", i, i, a, b, c, e );
  }
  printf("\n\
...but I guess we would actually do it like this leaving out the last %%4 :\n\n\
iheader.width   Padding bytes needed   pixel data eol (in bytes) \n");
  for(i = start; i > end; i--)
  {
    e = 0;
    if(i % 4 != 0)
    {
      e = (4-((i * 3)%4));
    }
    f = (i * 3);
    g = f + e;
    printf(" %12u     %u                    (%u * 3 = %u) + %u = %u \n", i, e, i, f, e, g );
  }

  return 0;
}
output:
Code:
"Exercise for the student: suppose it had a width of 399 pixels, how many padding bytes would be required for each row? How about 398? 397? 396?" ...so if we have a 24-bit .bmp which is 3 bytes per pixel.... iheader.width The math: Tbytes Padding bytes needed 400 (4 - ( (400 * 3 = 1200) % 4 = 0) = 4) %4 = 0 399 (4 - ( (399 * 3 = 1197) % 4 = 1) = 3) %4 = 3 398 (4 - ( (398 * 3 = 1194) % 4 = 2) = 2) %4 = 2 397 (4 - ( (397 * 3 = 1191) % 4 = 3) = 1) %4 = 1 396 (4 - ( (396 * 3 = 1188) % 4 = 0) = 4) %4 = 0 395 (4 - ( (395 * 3 = 1185) % 4 = 1) = 3) %4 = 3 394 (4 - ( (394 * 3 = 1182) % 4 = 2) = 2) %4 = 2 393 (4 - ( (393 * 3 = 1179) % 4 = 3) = 1) %4 = 1 392 (4 - ( (392 * 3 = 1176) % 4 = 0) = 4) %4 = 0 391 (4 - ( (391 * 3 = 1173) % 4 = 1) = 3) %4 = 3 ...but I guess we would actually do it like this leaving out the last %4 : iheader.width Padding bytes needed pixel data eol (in bytes) 400 0 (400 * 3 = 1200) + 0 = 1200 399 3 (399 * 3 = 1197) + 3 = 1200 398 2 (398 * 3 = 1194) + 2 = 1196 397 1 (397 * 3 = 1191) + 1 = 1192 396 0 (396 * 3 = 1188) + 0 = 1188 395 3 (395 * 3 = 1185) + 3 = 1188 394 2 (394 * 3 = 1182) + 2 = 1184 393 1 (393 * 3 = 1179) + 1 = 1180 392 0 (392 * 3 = 1176) + 0 = 1176 391 3 (391 * 3 = 1173) + 3 = 1176
Does that look right?

In the posting above by Dave an absolute check on the width is made:
CPP / C++ / C Code:
    if ((iheader.height != 512) || (iheader.width != 512) || (iheader.bits != 24)) {
        printf("This only works for 512x512 24-color bitmaps\n");
        return 0;
    }
...but I can see that we could perhaps write a program which adaptable to various pixel data layouts and using malloc() for databuff[x][x]. ...and I guess color bit-count too.

And there is never a eol marker for BMP's ?

I think I'll try the grayscale exercise next (in the "spare time"). Thanks
Howard();
  #34  
Old 07-Nov-2007, 14:21
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,218
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
Originally Posted by Howard_L
I hadn't been checking in over here at C++ due to self-imposed fun-time limits.
The email notifications promted me to take a look. I had forgotten about the post I made earlier! (it's getting worse...)

I see how the fopen(x.x, "rb"); is all important. But not in linux?
Linux I/O libraries for GNU compilers on my systems do not do anything special with 0x1a (or 0x0d or 0x0a or anything else) regardless of whether the 'b' is there or not. The 'b' is irrelevant. Doesn't help, doesn't hurt.

For Windows/cywgin users: The default at installation time is the Linux model, but it is possible to tell the cygwin installer to use "Windows" conventions in the I/O libraries so that 0x1a might be the end-of-file (I haven't checked), and the two-byte sequence '\r','\n' in a file is converted to a single '\n' in the stream buffer. I have tested this. (For writing in "windows" mode, '\n' in the stream buffer is converted to '\r',\n' in the file.)

For Windows Borland compilers that I have tested, they don't do anything special with 0x1a, but they convert '\r','\n' in a file to '\n' in the stream buffer unless the file was opened in binary mode.

Quote:
Originally Posted by Howard_L
When I saw that 0x1a is ctrl-z in MS I was rememberred that there was the ctrl-d (0x04) in linux which was similar

That ctrl-d thingie is for stdin input only. Bytes with value 0x04 in files do nothing special in the libraries supplied with GNU compilers, regardless of the 'b' in the mode.
Quote:
Originally Posted by Howard_L
On reviewing the pages, way back on page 1 a point was made about pixel data width, which is what we're getting in iheader.width

iheader.width gives the number of pixels per row, not the number of bytes per row.

Padding bytes are supplied if necessary to force the total number of bytes on a row to be a multiple of 4.
Roughly speaking, the number of bytes on a row is equal to the number of bytes per pixel times the number of pixels on a row.

Bytes per pixel is equal to bits per pixel divided by 8. I have encountered the following types of bmp files:

For info_header.bits = 24 (millions of colors), there are three bytes per pixel
For info_header.bits = 8, (256 colors) there is one byte per pixel
For info_header.bits = 4, (16 colors) there are two pixels per byte
For info_header.bits = 2, (four colors) there are four pixels per byte
For info_header.bits = 1, (two colors) there are eight pixels per byte

For bmp files with fewer than 256 colors, the number of pixel bytes on a row can be calculated from
CPP / C++ / C Code:
    ibyteswidth    = ceil(width * bitsperpixel/8.0);



Where width is info_header.width, and bitsperpixel = info_header.bits

The value of integer ibyteswidth is equal to the number of bytes on each row that contain pixel data, and it is used to determine the number of extra bytes for each row as follows:

The number of extra bytes is either 0, 1, 2 or 3 (that's obvious, isn't it?), depending on the number of bytes per row, so using the modulus operator, '%', we can do something like this:

Code:
Mapping from (bytes-per-row % 4) to 'extra bytes' (Bytes-per-Row % 4) => extra bytes 0 => 0 1 => 3 2 => 2 3 => 1

So, you can use a series if if-else statements using ibyteswidth%4. Or, you can use a switch statement using ibyteswidth%4. Or you can use the easily verified mathematical expression. (It's easy to verify; how "easy" it was to come up with it is another question.)
CPP / C++ / C Code:
    extrabytes     = (4 - ((ibyteswidth)%4)) % 4;

There are, of course, other ways.
Quote:
Originally Posted by Howard_L
And there is never a eol marker for BMP's ?
The bytes in bmp files are contiguous. Although the bytes are laid out in "rows", the the number of bytes per row is calculated from information in the header. (So end-of-line markers aren't required: each row has a predetermined number of bytes.)

Generally speaking binary files don't have "lines"; they have bytes.) In text files, structured as sequences of "lines," end-of-line markers are implementation dependent.

However for text files, since the lines are not necessarily all of the same length, and since the "real" data bytes are typically ASCII, end-of-line markers are required to allow you to separate the lines as you read the file.

The historical convention for UNIX systems text files, carried over into Linux, is 0x0a, and this is identified in C by '\n'.

The historical convention for DOS/Windows systems is that end-of-line in a text file is designated by the two-byte sequence 0x0d 0x0a.

The historical convention for text files on (old) Macintosh operating systems is 0x0d. Newer operating systems for the Macintosh use the UNIX convention.

For reading files, the libraries supplied by compiler vendors usually convert file end-of-line conventions to a single '\n' in the stream buffer unless the input file was opened in binary mode.

For writing files, the inverse operations are applied unless the output file was opened in binary mode.

Regards,

Dave
  #35  
Old 08-Nov-2007, 19:46
Howard_L Howard_L is offline
Regular Member
 
Join Date: Apr 2007
Location: Maryland/PA, USA
Posts: 803
Howard_L is a jewel in the roughHoward_L is a jewel in the roughHoward_L is a jewel in the rough

Re: How to get the pixels' value of a bmp image? (Pelles C)


In this:
CPP / C++ / C Code:
/*
 * You can change the "#if 0" to #if 1" if your compiler
 * has <stdint.h>
 */
#if 0
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef          int int32_t;
typedef unsigned short uint16_t;
#endif
What does: #if 0 ...indicate?
That is, what is the difference between 0 and 1?
  #36  
Old 09-Nov-2007, 08:49
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,218
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
Originally Posted by Howard_L
What does: #if 0 ...indicate?
That is, what is the difference between 0 and 1?

Inputs to logical expressions are the same for the C preprocessor as they are for C:

A value of zero evaluates false. A value of non-zero evaluates true.

With #if 0, as shown, the preprocessor will not pass the #include <stdint.h> to the compiler, but will make the typedefs following the #else.

The problem is that not all compilers have the assumed sizes for the various data types. (Recent Microsoft and Borland compilers that I use do have the assumed sizes, but older ones may have 16-bit ints, for example.) Note that the main() function that I gave actually tests the header sizes. The test will fail if the compiler doesn't have the assumed sizes for ints.

If people know that they have the C99 standard header <stdint.h> in their distribution, they could change the #if 0 to #if 1 and then would be absolutely certain that the correct sizes are used.


Regards,

Dave
  #37  
Old 10-Nov-2007, 16:37
Howard_L Howard_L is offline
Regular Member
 
Join Date: Apr 2007
Location: Maryland/PA, USA
Posts: 803
Howard_L is a jewel in the roughHoward_L is a jewel in the roughHoward_L is a jewel in the rough

Re: How to get the pixels' value of a bmp image? (Pelles C)


re: #if 0
Boy, that really seems like a dumb question now... sorry.

I think I have something half presentable which reads a 24 bit color .bmp file of ?any? size, manipulates that information , and writes 2 slightly different files in grayscale.
I made a lot of sidetrips in the exploration... fun stuff.
CPP / C++ / C Code:
#include <stdio.h>
#include <stdlib.h>     /* for calloc and free */

/* If you do NOT have <stdint.h> use #if 0 for the defined data sizes.
   If you DO     have <stdint.h> use #if 1
   mingw and dmc both have the definitions and don't need either!
   but niether complains about an #include <stdin.h> so #if 1  is OK*/
#if 1
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef          int int32_t;
typedef unsigned short uint16_t;
#endif

#include "bmp_headers.h"


void PAUSE(void){int cc=0; while( cc != EOF && cc != '\n') cc = getc(stdin);}

int main(int argc , char *argv[])
{
  FILE *fp1, *fp2, *fp3;
  uint8_t   r, g, b, gray, *pdat_in, *pdat_out;
  uint32_t  i, j, ibytewidth, padding, lbytewidth;
  char str        [20] ={0};
  char fname_out  [20] ={0};
  char fname_out2 [20] ={0};

  BmpFileHeader fheader;
  BmpInfoHeader iheader;

  /* printf("\n  %d \n  %s \n  %s \n", argc, argv[0], argv[1] ); */
  /*** this is kinda fancy but what the heck: ***/
  if(argc < 2)
  {
    for(i = j = 0; j < 20; i++, j++)
    {
      /* printf("%u %u, ", i, j );   for debug */
      if(argv[0][i] == '\\')
      {
        j = 0 - 1;  /* set 1 under, the next increment brings it to 0 */
      }             /* done like this because j is unsigned           */
      else
      {
        if(argv[0][i] == 0)
        {
          break;
        }
        str[j] = argv[0][i];
      }
    }
    str[j] = 0;
    printf("\n  !!! ERROR !!! Must include file !!! Usage: %s filename.bmp \n\n", str);
    return 1;
  }

  if( (fp1 = fopen(argv[1], "rb")) == NULL)
  {
    printf("input file %s failed to open , is it there?", argv[1]);
    return 1;
  };

  /*** make a new output filename out of the old one: ***/
  /* STEP1) get filename without the extension  */
  for(i = 0; i < 10; i++)
  {
    if(argv[1][i] == '.')
    {
      break;
    }
    str[i] = argv[1][i];
  }
  str[i] = 0;
  /* STEP2)  combine it with with a suffix (including the extension) */
  sprintf(fname_out, "%s_out.bmp", str);

  printf(">%s< \n", fname_out);
  /*** done ***/

  if( (fp2 = fopen(fname_out, "wb")) == NULL)
  {
    printf("!!! failed to open %s for output !!! , exiting...", fname_out);
    return 1;
  };

  /* read the file header into the structures */
  fread(&fheader, sizeof(fheader), 1, fp1 );
  fread(&iheader, sizeof(iheader), 1, fp1 );

  /* might as well write the header info into the output file now */
  fwrite(&fheader, sizeof(fheader), 1, fp2 );
  fwrite(&iheader, sizeof(iheader), 1, fp2 );

  printf("  This program reads a 24 bit color .bmp file of ?any? size, manipulates\n  that information , and writes 2 slightly different files in grayscale.\n");
  printf("\n           fheader.type: %04x    %d bytes\n", fheader.type,            sizeof(fheader.type) );
  printf("           fheader.size: %-6u  %d bytes  \n", fheader.size,            sizeof(fheader.size) );
  printf("      fheader.reserved1: %-6u  %d bytes  \n", (int)fheader.reserved1,  sizeof(fheader.reserved1) );
  printf("      fheader.reserved2: %-6u  %d bytes  \n", (int)fheader.reserved2,  sizeof(fheader.reserved2) );
  printf("         fheader.offset: %-6u  %d bytes  \n", fheader.offset,          sizeof(fheader.offset) );
  printf("           iheader.size: %-6u  %d bytes  \n", iheader.size,            sizeof(iheader.size) );
  printf("          iheader.width: %-6u  %d bytes  \n", iheader.width,           sizeof(iheader.width) );
  printf("         iheader.height: %-6u  %d bytes  \n", iheader.height,          sizeof(iheader.height) );
  printf("         iheader.planes: %-6u  %d bytes  \n", (int)iheader.planes,     sizeof(iheader.planes) );
  printf("           iheader.bits: %-6u  %d bytes  \n", (int)iheader.bits,       sizeof(iheader.bits) );
  printf("    iheader.compression: %-6u  %d bytes  \n", iheader.compression,     sizeof(iheader.compression) );
  printf("      iheader.imagesize: %-6u  %d bytes  \n", iheader.imagesize,       sizeof(iheader.imagesize) );
  printf("    iheader.xresolution: %-6u  %d bytes  \n", iheader.xresolution,     sizeof(iheader.xresolution) );
  printf("    iheader.yresolution: %-6u  %d bytes  \n", iheader.yresolution,     sizeof(iheader.yresolution) );
  printf("        iheader.ncolors: %-6u  %d bytes  \n", iheader.ncolors,         sizeof(iheader.ncolors) );
  printf("iheader.importantcolors: %-6u  %d bytes  \n", iheader.importantcolors, sizeof(iheader.importantcolors) );

  if(fheader.type != 0x4d42)
  {
    printf("Cannot read file properly.  The format is not  .bmp... \n");
  }
  /*
  if ((iheader.height != 512) || (iheader.width != 512) || (iheader.bits != 24))
  {
    printf("This only works for 512x512 24-color bitmaps\n");
    return 0;
  }
  */
  if ( iheader.bits != 24 )
  {
    printf("This only works for 24-color bitmaps\n");
    return 0;
  }
  if (fheader.offset != 54)
  {
    printf("This only works if the offset is equal to 54\n");
    return 0;
  }
  if ((iheader.imagesize %4 != 0))
  {
    printf("Imagesize is wrong \n");
    return 0;
  }
  /*** this section computes the line padding (if any is needed) and adds that
       to the image bytewidth to come up with an accurate eol value      ***/
  padding = 0;
  ibytewidth = (iheader.width * 3);

  if((ibytewidth % 4) != 0 )
  {
    padding = (4-(ibytewidth % 4)) ;
    printf("\npadding width with %u bytes\n", padding );
  }
  lbytewidth = ibytewidth + padding;
  /****
    ...but after seeing that iheader.imagesize is always correct,
    I am confident that I could just do this:
  lbytewidth = (iheader.imagesize / iheader.height);

    With a valid .bmp file this SHOULD always divide evenly
    and that result SHOULD divide evenly by 4 (bytes). Right???
    So now I know that I can use iheader.imagesize for calloc() ...duh
    It turns out that lbytewidth is not needed at all for this program,
    but it could come in handy for a future program which might alter the
    image size and would need to recalculate header size values.
    So I leave it for observation and future reference                     */

  printf("\niheader.width= %u    ibytewidth= %u    padding= %u   lbytewidth= %u\n", iheader.width, ibytewidth, padding, lbytewidth);

  /*  For reference from:  ucsd.edu/c/stdlib.html

  void *calloc(size_t nelem, size_t size);
  The function allocates an array object containing:
  nelem elements each of size size,
  stores zeros in all bytes of the array,
  and returns the address of the first element of the array if successful;
  otherwise, it returns a null pointer.
  You can safely convert the return value to an object pointer of any type
  whose size in bytes is not greater than size.
  */

  pdat_in  = calloc( (iheader.imagesize) + 1 , sizeof(uint8_t) );
  pdat_out = calloc( (iheader.imagesize) + 1 , sizeof(uint8_t) );

  /* I was getting a segfault for a file saved at 458x457 (padding=2)
     until I added the    + 1 here.  The segfault would occur at free(pdat_out);.
     I guess because at that point the OS noticed I was outa-bounds.
     I tested some other sizes but couldn't get it to re-occur.
     The following test results used a height of 457:
  wid  pad  result      wid  pad  result      wid  pad  result
  456  0    ok          524  0    ok          556  0    ok
  457  1    ok          525  1    ok          557  1    ok
  458  2    segfault    526  2    ok          558  2    ok
  459  3    ok          527  3    ok          559  3    ok
  460  0    ok          528  0    ok          560  0    ok
    If I change height to 458  width=458 works ok...
    hmm, I happened to hit a wierd one? I guess there's no harm in allocating
    an extra byte, but I still wonder why that one would fail...
    OR should they ALL have failed but slipped by!
    I think all the sizes look like they should work without the +1....
  */

  printf("\n(iheader.height * ibytewidth)= %u \n", (iheader.height * ibytewidth) );
  printf("\n(iheader.height * lbytewidth) = %u ...same as imagesize \n", (iheader.height * lbytewidth) );

  fseek(fp1, (long)fheader.offset, 0);   /* ensure fp is at right place */

  /***** ok here we go:
    step1) setup the big loop
    step2) get 3 bytes form infile and store in r,g,and b (fp automatically increments itself)
    step3) average the values stored r, g and b and store that in 'gray'
    step4) put the value of gray into 3 successive bytes of the outfile
    step4) loop ends and we go look at the gray picture,,, it works well!
  ***** /
  for(i = 0, j = 0; i < iheader.imagesize; i+=3)
  {
    r = getc(fp1);
    g = getc(fp1);
    b = getc(fp1);
    gray = (r+g+b)/3;
    putc(gray, fp2);
    putc(gray, fp2);
    putc(gray, fp2);
  }
  *** ok that was easy enough and it works goodly, but what about the unused arrays! */
  for(i = 0, j = 0; i < iheader.imagesize; )
  {
    r = getc(fp1);
    g = getc(fp1);
    b = getc(fp1);
    pdat_in[i++] = r;
    pdat_in[i++] = g;
    pdat_in[i++] = b;
    gray = (r+g+b)/3;
    putc(gray, fp2);
    putc(gray, fp2);
    putc(gray, fp2);

    /*** Play around with values a little and note the effect */
    if(gray > 20)      /* prevent from going past 0 to the Fx range */
    {
      gray -= 20;      /* darkens */
    }
    else
    {
      gray = 0;        /* maximum darkness (black) */
    }
    /*** Put the altered values into the 'out' array which goes to file2 */
    pdat_out[j++] = gray;
    pdat_out[j++] = gray;
    pdat_out[j++] = gray;

    /* This was for testing but I'll just leave it for some exitement! */
    if( (j % 10000) == 0 )
    {
      printf("%u ", i);
      /* printf("i= %u    j= %u    \n", i, j); */
    }
  }
  fclose(fp1);
  fclose(fp2);

  printf("\n  i= %u    j= %u  ...loop done.\n  pdat_in and pdat_out filled.  %s written  \n", i, j, fname_out);

  /* ok so we have it in the array, now I'll open another outfile: */
  sprintf(fname_out2, "%s_out2.bmp", str);      /* str is still as above */
  if( (fp3 = fopen(fname_out2, "wb")) == NULL )
  {
    printf("\n!!! failed to open %s for output !!! , exiting...", fname_out2);
    return 1;
  }
  else
  {
    printf("\nBegin writing pdat_out data to %s: \n", fname_out2);
  }
  /* And I'll just write the header and image as blocks...   */
  if(! fwrite(&fheader, sizeof(fheader), 1, fp3 ) )
  {
    printf("writing pdat_out fheader data to %s failed , exiting \n", fname_out2);
    return 1;
  }
  else
  {
    printf("pdat_out fheader data written to %s \n", fname_out2 );
  }

  if(! fwrite(&iheader, sizeof(iheader), 1, fp3 ) )
  {
    printf("writing pdat_out iheader data to %s failed , exiting\n", fname_out2);
    return 1;
  }
  else
  {
    printf("pdat_out iheader data written to %s \n", fname_out2 );
  }

  if(! fwrite(pdat_out, iheader.imagesize, 1, fp3 ) )
  {
    printf("writing pdat_out iheader data to %s failed , exiting\n", fname_out2);
    return 1;
  }
  else
  {
    printf("pdat_out   image data written to %s  \n", fname_out2 );
  }

  fclose(fp3);
  printf(" done with fp3\n");

  free(pdat_out);
  printf(" done with pdat_out\n");

  free(pdat_in);
  printf(" done with pdat_in\n");

  printf(" ...and we're done period. Sure is fast... \n");
  return 0;
}

/*  pretty cool...   */
See any problems?
There are a couple of curiosities I have commented. Other than that I understand things better now and am getting the hang of it. What's next direction?
++Howard;
  #38  
Old 10-Nov-2007, 17:20
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,218
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
Originally Posted by Howard_L
...
CPP / C++ / C Code:
  uint8_t   r, g, b...
.
.
.
    gray = (r+g+b)/3; /* overflow if r+g+b > 255 */
.
.
.

Why not make r, g, b unsigned ints? Then you have to watch for getc(). Its return value is int. So, maybe you could use something like
CPP / C++ / C Code:
    r = (unsigned)getc(fp1); /* guard against sign extension for value > 128 */
    g = (unsigned)getc(fp1);
    b = (unsigned)getc(fp1);
    gray = (r+g+b)/3;

Also, by the way, if you ever want to do something with colors (like decrease red and increase blue) you should be aware that the triads come in order green, blue, red (Not red, blue, green.)

Actually, I made them doubles so that I could conveniently round the value:
CPP / C++ / C Code:
    grayvalue = (g + b + r)/3.0 + 0.5;



That leaves one question. I have to ask you what the heck happened to the extra bytes?

The extra bytes do not go into your pixel data (but you have to re-insert them into the output file somehow). This may be why you had problems with having to allocate more than the data size of the file. As you go through the loop the last time, you are actually accessing beyond the array, I think.

Any time your program fails and you have to put in a fudge factor (the extra calloc stuff): beware! Just coming up with some kind of kludge that makes it not fail for a particular data set without actually knowing what the heck is going on is a recipe for disaster.

Here's an idea: Leave your loop the way it is, and put in a print statement whenever the index value goes beyond the end of what the array should be. I'll bet it shows you something.

Why not do it a row at a time? Use your knowledge of the structure of the bitmap format. You can use a 1-D or 2-D array for the (width *3 times height) pixel data bytes. (Actually if you are going to convert to gray, why not just have a (width times height) array and store gray-value bytes only?)

I think that the convenience of 2_D array notation to be able to locate a particular pixel by row and column number is the "only way to go." Conceivably if file I/O is a bottleneck, then reading the whole enchilada with a single fread statement (rather than the cumbersome byte-at-a-time or three-bytes-at a time or even a row-at-a-time) might be important. It's your call

Anyhow, for a 2-D array, you could do something like
CPP / C++ / C Code:
    for (row = 0; row < height; row++) { /* height from info_header */
        for (col = 0; col < width; col++) { /* width from info_header
.
.
.
            /* 
             * get g+b+r values (divided by 3) into a single byte, say graybyte.
             * Then
             */
            grayarray[row][col] = graybyte;
            for (i = 0; i < extrabytes; i++) {
                /* get padding byte from file and throw away */
            }
        }
    }

You can use getc() for each byte, or you can read three at a time (with fread) into a 3-char array or whatever...

There is some loss of resolution in going from a 24-bit grayscale to an 8-bit grayscale, but for many purposes it's irrelevant. If you want to keep full precision, then make grayarray[][] an array of ints instead of an array of unsigned chars, and don't divide the r+g+b value by three. (Notice that your routine converted to the equivalent of an 8-bit grayscale; it just used three equal bytes to represent the gray tone.)



Regards,

Dave
  #39  
Old 11-Nov-2007, 18:37
Howard_L Howard_L is offline
Regular Member
 
Join Date: Apr 2007
Location: Maryland/PA, USA
Posts: 803
Howard_L is a jewel in the roughHoward_L is a jewel in the roughHoward_L is a jewel in the rough

Re: How to get the pixels' value of a bmp image? (Pelles C)


Quote:
what the heck happened to the extra bytes?

The extra bytes do not go into your pixel data (but you have to re-insert them into the output file somehow). This may be why you had problems with having to allocate more than the data size of the file. As you go through the loop the last time, you are actually accessing beyond the array, I think.

...beware! Just coming up with some kind of kludge ...without actually knowing what the heck is going on is a recipe for disaster.
Well said! and you are exactly right! I knew I should have looked into it further. I guess I got lazy.

What was happening was that:
- The i < imagesize was being checked at the beginning of each loop.
- i and j could increment up to 3 past 'imagesize' within the loop without
being checked. As a result, the program would overflow pdat_in or pdat_out.

I tried .bmp file widths from the 458x457 which showed up originally to 500x457 and found only 1 more (474x457) which would segfault although, with the printf()'s in the loop, I could see that on some tests j was incrementing 2 or 3 beyond the array size with no segfault. 458 and 474 were both 1 beyond the loop size.
I think the reason it SOMETIMES segfaults and NOT always is that something like this happens:
calloc requests x amount of memory.
The OS rounds that size up to an even 'block' that it likes to work with which is deemed "in-bounds".
If the in-bounds block limit happens to be very close to the requested size,
the program writes past THAT limit and the OS issues a segfault...
(I have run a char pointer through some data declaration areas of memory before and noticed these 'blocks' the OS rounds to.)

So as a cheap fix for the code I posted,
I just stuck a bunch of checks within the loop after each increment:
CPP / C++ / C Code:
/* fixes to previous post */
/*... snip ...*/
  pdat_in  = calloc( (iheader.imagesize) , sizeof(uint8_t) );
  pdat_out = calloc( (iheader.imagesize) , sizeof(uint8_t) );
/*... snip ...*/
  isize = iheader.imagesize;       /* new! variable for shorter name */
  for(i = j = k = 0; i < isize;)
  {
    r = getc(fp1);
    g = getc(fp1);
    b = getc(fp1);
    pdat_in[i++] = r;
    if( i < isize)            /* new! */
      pdat_in[i++] = g;
    if( i < isize)            /* new! */
      pdat_in[i++] = b;
    gray = (r+g+b)/3;
    putc(gray, fp2);
    putc(gray, fp2);
    putc(gray, fp2);

    /*** Play around with values a little and note the effect */
    if(gray > 20)      /* prevent from going past 0 to the Fx range */
    {
      gray -= 20;      /* darkens */
    }
    else
    {
      gray = 0;        /* maximum darkness (black) */
    }
    /*** Put the altered values into the 'out' array which goes to file2 */
    if( j > (isize - 3)  printf("j= %u\n", i);  /* debug print */
    pdat_out[j++] = gray;
    if( j >= isize) break;          /* new! */

    if( j > (isize - 3)  printf("j= %u\n", i);  /* debug print */
    pdat_out[j++] = gray;
    if( j >= isize) break;          /* new! */

    if( j > (isize - 3)  printf("j= %u\n", i);  /* debug print */
    pdat_out[j++] = gray;
    if( j >= isize) break;          /* new! */

    /* This was for testing but I'll just leave it for some exitement! */
    if( (j % 10000) == 0 )
    {
      printf("%u ", i);
      /* printf("i= %u    j= %u    \n", i, j); */
    }
  }
  fclose(fp1);
  fclose(fp2);
Actually I was suprised I didn't have to do any manipulation to account for paddding. But now I realize that the same number of bytes need to be in each object in the same order. (in this situation)
Next I'll be trying to implement some of those good suggestions you made. Thanks!
Last edited by Howard_L : 11-Nov-2007 at 19:23.
  #40  
Old 07-Mar-2009, 18:29
Silvermaul Silvermaul is offline
New Member
 
Join Date: Mar 2009
Posts: 4
Silvermaul is on a distinguished road

Re: How to get the pixels' value of a bmp image? (Pelles C)


Hi all. This was the very best thread I found that helped me create my own bmp loading code. However I do have one question which I will try to explain after I post all my code.

this is a V5 bmp header file

CPP / C++ / C Code:
#ifndef BMP_HEADERS
#define BMP_HEADERS
/*
 * I have found that the following pragma is necessary to ensure
 * the correct size of the structs.
 *
 * In the file, the BmpFileHeader struct is 14 bytes long and
 * the BmpInfoHeader is 40 bytes long
 *
 * Works for GNU, Borland bcc32, Microsoft VC++
 *
 * davekw7x
 */
/* Note that all 'standard' bitmap files are little-endian
 * If your architecture is little-endian, then you can
 * read the first 54 bytes of the file directly into the
 * following two structs.
 */ 


#pragma pack(push, 1)

typedef struct {
	int ciexyzX;
	int ciexyzY;
	int ciexyzZ;
} CIEXYZ;// This is 12 bytes

typedef struct {
	CIEXYZ ciexyzRed;
	CIEXYZ ciexyzGreen;
	CIEXYZ ciexyzBlue;
} CIEXYZTRIPLE;// This is 36 bytes

typedef struct {
    unsigned short type;               /* Two chars "BM" in little-endian order  */
    unsigned int size;               /*unsigned int 4 bytes File size                              */
    unsigned short reserved1;          //unsigned short 2 bytes
	unsigned short reserved2;
    unsigned int offset;             /* Bytes from start of file to pixel data */
} BmpFileHeader;

typedef struct {
    unsigned int size;               /* Size of this header  (40 bytes)= DOWRD */
    int width;                       /* Bitmap width in pixels                 */
    int height;                      /* Bitmap height in pixels                */
    unsigned short planes;             /* Must be 1                              */
	unsigned short bits;               /* Bits per pixel. (8 for 256-color bmps) */

    unsigned int compression;        /* 0 means no compression                 */
    unsigned int imagesize;          /* Number of bytes in pixel data section  */
    int  xresolution;        /* Not used by any of my functions        */
    int  yresolution;        /* Not used by any of my functions        */

	
    unsigned int ncolors;            /* 0 means use all colors                 */
    unsigned int importantcolors;    /* 0 means all are important              */

	unsigned int redMask;
	unsigned int greenMask;
	unsigned int blueMask;
	unsigned int alphaMask;
	unsigned int CSType;
	CIEXYZTRIPLE endPoints;
	unsigned int gammaRed;
	unsigned int gammaGreen;
	unsigned int gammaBlue;
	unsigned int intent;
	unsigned int profileData;
	unsigned int profileSize;
	unsigned int Reserved;


} BmpInfoHeader;
#pragma pack(pop)



#endif

this is a little bmp class I made

CPP / C++ / C Code:
#pragma once
#ifndef BMP_H
#define BMP_H
#include "bmp_headers.h"
#include <iostream>

using namespace std;
class Bmp
{
public:
	Bmp(BmpFileHeader&,BmpInfoHeader&,int&,int&,unsigned short&);
 	Bmp(void);
	~Bmp(void);
	friend ostream& operator<<(ostream&,Bmp&);
	int getWidth();
	int getHeight();
	unsigned short getBpp();
	unsigned char* getArrayPtr();
	private :
	BmpFileHeader FH;
	BmpInfoHeader IH;
	unsigned char* imageArray;
};
#endif

here is the cpp of the above class

CPP / C++ / C Code:
#include "Bmp.h"


Bmp::Bmp(BmpFileHeader &myFH,BmpInfoHeader &myIH,int &width,int &height,unsigned short&bpp):FH(myFH),IH(myIH)
{
imageArray=new unsigned char[width,height,bpp/8];
}
Bmp::Bmp()
{}

Bmp::~Bmp(void)
{
}

ostream& operator <<(ostream& output,Bmp& arg)
	{
		

		return output<<hex<<"Bmp File Type is : "<<arg.FH.type<<endl
		<<dec<<"Bmp Size is :"<<arg.FH.size<<endl
		<<"Bmp Reserved one is :"<<arg.FH.reserved1<<endl
		<<"Bmp Reserved two is :"<<arg.FH.reserved1<<endl
		<<"Bmp Header Offset is :"<<arg.FH.offset/8<<endl//Offset in bytes meaning that after byte 134 the actual pixels can be found
		<<"Bmp Header Size is :"<<arg.IH.size<<endl
		<<"Image width is : "<<arg.IH.width<<endl
		<<"Image height is : "<<arg.IH.height<<endl
		<<"Image bpp is : "<<arg.IH.bits<<endl
		<<"Image compression is : "<<arg.IH.compression<<endl
		<<"Byts in pixel data section are : "<<arg.IH.imagesize<<endl;
	}
int Bmp::getHeight()
	{
	return IH.height;
	}
int Bmp::getWidth()
	{
	return IH.width;
	}
unsigned short Bmp::getBpp()
	{
	return IH.bits;
	}
unsigned char* Bmp::getArrayPtr()
	{
	return imageArray;
	}

and here is the main cpp

CPP / C++ / C Code:
#include <fstream>
#include <cstdlib>
#include "Bmp.h"

int main()
	{
	ifstream myBmpFile("test2.bmp",ios::in|ios::binary);
	if(!myBmpFile)
		{
		cerr<<"File Could not be Opened."<<endl;
		exit(1);
		}
	//Bmp myBmp;
	BmpFileHeader myFH;
	BmpInfoHeader myIH;
	myBmpFile.read(reinterpret_cast<char*>(&myFH),sizeof(myFH));
	myBmpFile.read(reinterpret_cast<char*>(&myIH),sizeof(myIH));

	Bmp myBmp(myFH,myIH,myIH.width,myIH.height,myIH.bits);
	
	cout<<"Size of File Header is : "<<sizeof(myFH)<<endl
		<<"Size of Info Header is : "<<sizeof(myIH)<<endl;
	long startLocation=myBmpFile.tellg();	
	if(startLocation!=138)
		{
		cout<<"The file is corrupted"<<endl;
		exit(1);
		}	
	cout<<endl<<myBmp<<endl;
	cout<<"File pointer at the beginning of storing to the 2Darray :"<<myBmpFile.tellg()<<endl;

	for(int i=0;i<myBmp.getHeight();++i)
		{
		for(int j=0;j<myBmp.getWidth();++j)
			{
			myBmpFile.read(reinterpret_cast<char*>(myBmp.getArrayPtr()),sizeof(unsigned char));
			}
		}
	long endLocation=myBmpFile.tellg();
	cout<<"File pointer at the end of storing to the 2Darray :"<<myBmpFile.tellg()<<endl
		<<"Total number of bytes read is : "<<endLocation-startLocation<<endl;
	



	
	while(1);
	return 0;
	}


The Print out i get is this :

Size of FileHeader is : 14
Size of InfoHeader is :124

Bmp File Type is : 4d42
Bmp Size is : 263222(this is exactly the same as windows tell me so it's OK)

Bmp Reserved one is : 0
Bmp Reserved two is : 0
Bmp Header Offset is 134(this should be 138 I think)
Bmp Header FileSize is : 40(and this 124)

Image Width is : 512
Image Height is : 512 (both correct)

Image Bpp is : 8(correct since I am using 8bit grayscale)
Image Compression is : 0

Bytes in Pixel data section are : 262144

File Pointer at the beginning of storing to the 2Darray is : 138(should be correct)

File Pointer at the end of storing to the 2Darray is : 262282

Total number of bytes read is : 262144(should also be correct)


My questions are these :
Firstly it seems that I am missing some 940 bytes since my file size is 263222
and the pointer stops to 262282. Has anyone got any idea as to where those bytes are or what they are used for?

Why is the offset 134 and not 138? 14+124 for (V5) should make 138 right?
Last edited by admin : 07-Mar-2009 at 20:10. Reason: Please insert your example C/C++ codes between [CPP] and [/CPP] tags
 
 

Recent GIDBlogAccepted for Ph.D. program by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Question about locking surfaces to directly access pixels, SDL. george89 C++ Forum 0 18-Jun-2006 22:16
Pixels dan_ielle20 C++ Forum 0 23-Mar-2005 09:54
Checking source codes of image, audio and video files onauc C Programming Language 5 26-Feb-2005 22:47

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 01:04.


vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.