Bitmap/Histogram

From Rosetta Code
Revision as of 23:28, 13 December 2008 by rosettacode>ShinTakezou (C)
Task
Bitmap/Histogram
You are encouraged to solve this task according to the task description, using any language you may know.

Extend the data storage type defined on this page to support image histograms. The image histogram contains for each luminance the count of image pixels having this luminance. Choosing the histogram data format take care about the data type used for the counts. It must be at least NxM, where N is the image width and M is the image height.

Histogram is useful for many image processing operations. As an example, use it to convert an image into black and white art. The method works as follows:

  • Convert image to grayscale;
  • Compute the histogram
  • Find the median of. The median is defined as the luminance such that the image has an approximately equal number of pixels with lesser and greater luminance.
  • Replace each pixel of luminance lesser than the median to black, and others to white.

Use read/write ppm file, and grayscale image solutions.

Ada

Histogram of an image: <ada> type Pixel_Count is mod 2**64; type Histogram is array (Luminance) of Pixel_Count;

function Get_Histogram (Picture : Grayscale_Image) return Histogram is

  Result : Histogram := (others => 0);

begin

  for I in Picture'Range (1) loop
     for J in Picture'Range (2) loop
        declare
           Count : Pixel_Count renames Result (Picture (I, J));
        begin
           Count := Count + 1;
        end;
     end loop;
  end loop;
  return Result;

end Get_Histogram; </ada> Median of a histogram: <ada> function Median (H : Histogram) return Luminance is

  From  : Luminance   := Luminance'First;
  To    : Luminance   := Luminance'Last;
  Left  : Pixel_Count := H (From);
  Right : Pixel_Count := H (To);

begin

  while From /= To loop
     if Left < Right then
        From := From + 1;
        Left := Left + H (From);
     else
        To    := To    - 1;
        Right := Right + H (To);         
     end if;
  end loop;
  return From;

end Median; </ada> Conversion of an image to black and white art: <ada>

  F1, F2 : File_Type;

begin

  Open (F1, In_File, "city.ppm");
  declare
     X : Image := Get_PPM (F1);
     Y : Grayscale_Image := Grayscale (X);
     T : Luminance := Median (Get_Histogram (Y));
  begin
     Close (F1);
     Create (F2, Out_File, "city_art.ppm");
     for I in Y'Range (1) loop
        for J in Y'Range (2) loop
           if Y (I, J) < T then
              X (I, J) := Black;
           else
              X (I, J) := White;
           end if;
        end loop;
     end loop;      
     Put_PPM (F2, X);
  end;
  Close (F2);

</ada>

C

<c>typedef unsigned int *histogram;</c>

<c>#define GET_LUM(IMG, X, Y) ( (IMG)->buf[ (Y) * (IMG)->width + (X)][0] )

histogram get_histogram(grayimage im) {

  histogram t;
  unsigned int x, y;
  
  if ( im == NULL ) return NULL;
  t = malloc( sizeof(histogram)*256 );
  memset(t, 0, sizeof(histogram)*256 );
  if (t!=NULL)
  {
      for(x=0; x < im->width; x++ )
      {
        for(y=0; y < im->height; y++ )
        {
           t[ GET_LUM(im, x, y) ]++;
        }
      }
  }
  return t;

}</c>

The given histogram must be freed with a simple free(histogram).

Translation of: Ada

<c>luminance histogram_median(histogram h) {

   luminance From, To;
   unsigned int Left, Right;
   
   From = 0; To = (1 << (8*sizeof(luminance)))-1;
   Left = h[From]; Right = h[To];
   
   while( From != To )
   {
      if ( Left < Right )
      {
         From++; Left += h[From];
      } else {
         To--; Right += h[To];
      }
   }
   return From;

}</c>

An example of usage is the following code.

<c>#include <stdio.h>

  1. include <stdlib.h>

/* #include "imglib.h" */

/* usage example */

  1. define BLACK 0,0,0
  2. define WHITE 255,255,255

int main(int argc, char **argv) {

   image color_img;
   grayimage g_img;
   histogram h;
   luminance T;
   unsigned int x, y;
   
   if ( argc < 2 )
   {
      fprintf(stderr, "histogram FILE\n");
      exit(1);
   }
   color_img = read_image(argv[1]);
   if ( color_img == NULL ) exit(1);
   g_img = tograyscale(color_img);
   h = get_histogram(g_img);
   if ( h != NULL )
   {
         T = histogram_median(h);
         
         for(x=0; x < g_img->width; x++)
         {
           for(y=0; y < g_img->height; y++)
           {
              if ( GET_LUM(g_img,x,y) < T )
              {
                  put_pixel_unsafe(color_img, x, y, BLACK);
              } else {
                  put_pixel_unsafe(color_img, x, y, WHITE);
              }
           }
         }
         output_ppm(stdout, color_img);
         /* print_jpg(color_img, 90); */
         free(h);
   }
      
   free_img((image)g_img);
   free_img(color_img);

} </c>

Which reads from the file specified from the command line and outputs to the standard out the PPM B/W version of the input image. The input image can be of any format handled by ImageMagick (see Read image file through a pipe)

Forth

: histogram ( array gmp -- )
  over 256 cells erase
  dup bdim * over bdata +  swap bdata
  do 1 over i c@ cells + +! loop drop ;