Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Determine if an image is solid

This thread is locked; no one can reply to it. rss feed Print
Determine if an image is solid
Nazerith
Member #12,551
February 2011

Hey guys. I'm working with a bitmap image from an old piece of software (2001-ish). The image is a tile sheet of tiles used in the game. I'm creating a map editor for the game, so I need to read and write the map files in the exact same format.

In the map files, tiles are numerically ordered starting from one, based on the order they appear in the sheet (tiles are 100x100 pixels). However, not all spots in the sheet contain images. In some cases, the spot is filled in with a single color (which the program uses as transparent on its tile). In cases where a tile is absent, that spot is skipped for the purposes of assigning numbers to the tiles.

So I need a way to do one of two things:

1) Test if a bitmap is a solid color.

or

2) Test if two bitmaps are equal.

I couldn't find a function for either in allegro, and I was curious if I missed it. Worse comes to worse, I'll write the function if it doesn't exist, but prefer not to do that if I can avoid it.

Or am I just missing a totally obvious solution? I kinda feel like I am.

Trent Gamblin
Member #261
April 2000
avatar

I'd be interested in a solution that doesn't have to compare every pixel (i.e., is faster than doing that). I don't know of one. Allegro does not have either function though.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Nazerith said:

1) Test if a bitmap is a solid color.

2) Test if two bitmaps are equal.

You'll have to do both yourself. The first is easy, and the second is only slightly harder.

1)

int is_bitmap_solid_color(BITMAP* bmp , int color) {
   if (!bmp) {return 0;}
   for (int y = 0 ; y < bmp->h ; ++y) {
      for (int x = 0 ; x < bmp->w ; ++x) {
         if (color != getpixel(bmp , x , y)) {return 0;}
      }
   }
   return 1;
}

2)

int are_bitmaps_equal(BITMAP* b1 , BITMAP* b2) {
   if (!b1 || !b2) {return 0;}
   if (b1 == b2) {return 1;}
   if (bitmap_color_depth(b1) != bitmap_color_depth(b2)) {return 0;}
   if ((b1->w != b2->w) || (b1->h != b2->h)) {return 0;}
   for (int y = 0 ; y < b1->h ; ++y) {
      for (int x = 0 ; x < b1->w ; ++x) {
         if (getpixel(b1,x,y) != getpixel(b2,x,y)) {return 0;}
      }
   }
   return 1;
}

I just wrote them myself, since they only took a couple minutes.

Nazerith
Member #12,551
February 2011

Appreciate the effort Edgar. I knew how to write them, but was hoping for a more elegant solution than a per pixel comparison :-/. Guess we can't have everything in life can we?

[EDIT]

I just noticed you put getpixel. I assume you meant al_get_pixel.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You didn't specify A4 or A5, so I just used A4.

Using A5 will be somewhat different :
1)

int is_bitmap_solid_color(ALLEGRO_BITMAP* bmp , ALLEGRO_COLOR color) {
   if (!bmp) {return 0;}
   al_lock_bitmap(bmp , al_get_bitmap_format(bmp) , ALLEGRO_LOCK_READONLY);
   for (int y = 0 ; y < al_get_bitmap_height(bmp) ; ++y) {
      for (int x = 0 ; x < al_get_bitmap_width(bmp) ; ++x) {
         if (color != al_get_pixel(bmp , x , y)) {
            al_unlock_bitmap(bmp);
            return 0;
         }
      }
   }
   al_unlock_bitmap(bmp);
   return 1;
}

2)

#SelectExpand
1int are_bitmaps_equal(ALLEGRO_BITMAP* b1 , ALLEGRO_BITMAP* b2) { 2 if (!b1 || !b2) {return 0;} 3 if (b1 == b2) {return 1;} 4 if (al_get_bitmap_format(b1) != al_get_bitmap_format(b2)) {return 0;} 5 if ((al_get_bitmap_width(b1) != al_get_bitmap_width(b2)) || 6 (al_get_bitmap_height(b1) != al_get_bitmap_height(b2))) {return 0;} 7 8 al_lock_bitmap(b1 , al_get_bitmap_format(b1) , ALLEGRO_LOCK_READONLY); 9 al_lock_bitmap(b2 , al_get_bitmap_format(b2) , ALLEGRO_LOCK_READONLY); 10 11 for (int y = 0 ; y < al_get_bitmap_height(b1) ; ++y) { 12 for (int x = 0 ; x < al_get_bitmap_width(b1) ; ++x) { 13 if (al_get_pixel(b1,x,y) != al_get_pixel(b2,x,y)) { 14 al_unlock_bitmap(b1); 15 al_unlock_bitmap(b2); 16 return 0; 17 } 18 } 19 } 20 al_unlock_bitmap(b1); 21 al_unlock_bitmap(b2); 22 return 1; 23}

A5 takes more code. :P

Nazerith
Member #12,551
February 2011

[EDIT]

Text removed because I am dumb.

Audric
Member #907
January 2001

With allegro 4 bitmaps, you could use memcmp() on each bmp->line[y] to speed up the comparison. It would also avoid the bit-shifting that occurs in al_get_pixel() to re-order the R G B components.

Tobias Dammers
Member #2,604
August 2002
avatar

I'd be interested in a solution that doesn't have to compare every pixel (i.e., is faster than doing that). I don't know of one. Allegro does not have either function though.

For checking whether two images are exactly identical, I can think of a few optimizations:
1. Use some heuristic to determine the areas where images are most likely to be different, and start comparison there (e.g., the center of an image is more likely to be distinctive than the edges)
2. Upon loading each bitmap, create a digest hash and keep it around. Only do the per-pixel comparison when the hash matches. If your hash is large enough and has sufficient entropy, you might even take the risk of a hash collision and skip the pixel test altogether.
3. Use a few quick checks to weed out obvious non-matches: differing sizes, color depths, file sizes, etc.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Audric
Member #907
January 2001

Looks like ML already posted some code for fast image comparison:
http://www.allegro.cc/forums/thread/606084/898790#target
In the linked post he compared only edges, ie. lines on top, bottom, left and right.
The critical code is:

  // Do once
  b1_lock = al_lock_bitmap(b1, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READONLY);
  b2_lock = al_lock_bitmap(b2, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READONLY);  
  b1_data = b1_lock->data;
  b2_data = b2_lock->data;
  // Do for each y line of bitmaps:
  if (memcmp(
      (uint8_t*)&b1_data[x1] + b1_lock->pitch * (y1+y), 
      (uint8_t*)&b2_data[x2] + b2_lock->pitch * (y2+y),
          width)) {...} // is different

(with x1,y1 the coordinates of the block in bitmap b1, and x2,y2 the coordinates in bitmap b2)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Go to: