Grayscale image: Difference between revisions

From Rosetta Code
Content added Content deleted
(Vedit macro language added)
(<code>)
Line 8: Line 8:


=={{header|Ada}}==
=={{header|Ada}}==
<ada>
<code ada>
type Grayscale_Image is array (Positive range <>, Positive range <>) of Luminance;
type Grayscale_Image is array (Positive range <>, Positive range <>) of Luminance;
</ada>
</code>
Conversion to a grayscale image:
Conversion to a grayscale image:
<ada>
<code ada>
function Grayscale (Picture : Image) return Grayscale_Image is
function Grayscale (Picture : Image) return Grayscale_Image is
type Extended_Luminance is range 0..10_000_000;
type Extended_Luminance is range 0..10_000_000;
Line 33: Line 33:
return Result;
return Result;
end Grayscale;
end Grayscale;
</ada>
</code>
Conversion to a color image:
Conversion to a color image:
<ada>
<code ada>
function Color (Picture : Grayscale_Image) return Image is
function Color (Picture : Grayscale_Image) return Image is
Result : Image (Picture'Range (1), Picture'Range (2));
Result : Image (Picture'Range (1), Picture'Range (2));
Line 46: Line 46:
return Result;
return Result;
end Color;
end Color;
</ada>
</code>


=={{header|C}}==
=={{header|C}}==
Line 52: Line 52:
Definition for a grayscale image.
Definition for a grayscale image.


<code c>
<c>typedef unsigned char luminance;
typedef unsigned char luminance;
typedef luminance pixel1[1];
typedef luminance pixel1[1];
typedef struct {
typedef struct {
Line 59: Line 60:
luminance *buf;
luminance *buf;
} grayimage_t;
} grayimage_t;
typedef grayimage_t *grayimage;</c>
typedef grayimage_t *grayimage;
</code>


The same as <tt>alloc_img</tt>, but for grayscale images.
The same as <tt>alloc_img</tt>, but for grayscale images.


<code c>
<c>grayimage alloc_grayimg(unsigned int width, unsigned int height)
grayimage alloc_grayimg(unsigned int width, unsigned int height)
{
{
grayimage img;
grayimage img;
Line 71: Line 74:
img->height = height;
img->height = height;
return img;
return img;
}
}</c>
</code>


Convert from ''color'' image to ''grayscale'' image.
Convert from ''color'' image to ''grayscale'' image.


<code c>
<c>grayimage tograyscale(image img)
grayimage tograyscale(image img)
{
{
unsigned int x, y;
unsigned int x, y;
Line 97: Line 102:
}
}
return timg;
return timg;
}
}</c>
</code>


And back from a ''grayscale'' image to a ''color'' image.
And back from a ''grayscale'' image to a ''color'' image.


<c>image tocolor(grayimage img)
<code c>image tocolor(grayimage img)
{
{
unsigned int x, y;
unsigned int x, y;
Line 122: Line 128:
}
}
return timg;
return timg;
}
}</c>
</code>


'''Notes'''
'''Notes'''
* <tt>tocolor</tt> and <tt>tograyscale</tt> do not free the previous image, so it must be freed normally calling <tt>free_img</tt>. With a cast we can use the same function also for grayscale images, or we can define something like
* <tt>tocolor</tt> and <tt>tograyscale</tt> do not free the previous image, so it must be freed normally calling <tt>free_img</tt>. With a cast we can use the same function also for grayscale images, or we can define something like


<code c>
<c>#define free_grayimg(IMG) free_img((image)(IMG))</c>
#define free_grayimg(IMG) free_img((image)(IMG))
</code>


* ''Luminance'' is rounded. Since the C implementation is based on unsigned char (256 possible values per components), L can be at most 255.0 and rounding gives 255, as we expect. Changing the color_component type would only change 256, 255.0 and 255 values here written in something else, the code would work the same.
* ''Luminance'' is rounded. Since the C implementation is based on unsigned char (256 possible values per components), L can be at most 255.0 and rounding gives 255, as we expect. Changing the color_component type would only change 256, 255.0 and 255 values here written in something else, the code would work the same.
Line 183: Line 192:


Conversion to a grayscale image:
Conversion to a grayscale image:
<code ocaml>
<ocaml>let to_grayscale ~img:(_, r_channel, g_channel, b_channel) =
let to_grayscale ~img:(_, r_channel, g_channel, b_channel) =
let width = Bigarray.Array2.dim1 r_channel
let width = Bigarray.Array2.dim1 r_channel
and height = Bigarray.Array2.dim2 r_channel in
and height = Bigarray.Array2.dim2 r_channel in
Line 202: Line 212:
done;
done;
done;
done;
(gray_channel)</ocaml>
(gray_channel)
</code>


Conversion to a color image:
Conversion to a color image:
<code ocaml>
<ocaml>let to_color ~img:gray_channel =
let to_color ~img:gray_channel =
let width = Bigarray.Array2.dim1 gray_channel
let width = Bigarray.Array2.dim1 gray_channel
and height = Bigarray.Array2.dim2 gray_channel in
and height = Bigarray.Array2.dim2 gray_channel in
Line 224: Line 236:
r_channel,
r_channel,
g_channel,
g_channel,
b_channel)</ocaml>
b_channel)
</code>


=={{header|Vedit macro language}}==
=={{header|Vedit macro language}}==

Revision as of 08:37, 27 January 2009

Task
Grayscale image
You are encouraged to solve this task according to the task description, using any language you may know.

Many image processing algorithms are defined for grayscale (or else monochromatic) images. Extend the data storage type defined on this page to support grayscale images. Define two operations, one to convert a color image to a grayscale image and one for the backward conversion. To get luminance of a color use the formula recommended by CIE:

L = 0.2126·R + 0.7152·G + 0.0722·B

When using floating-point arithmetic make sure that rounding errors would not cause run-time problems or else distorted results when calculated luminance is stored as an unsigned integer.

Ada

type Grayscale_Image is array (Positive range <>, Positive range <>) of Luminance; Conversion to a grayscale image: function Grayscale (Picture : Image) return Grayscale_Image is

  type Extended_Luminance is range 0..10_000_000;
  Result : Grayscale_Image (Picture'Range (1), Picture'Range (2));
  Color  : Pixel;

begin

  for I in Picture'Range (1) loop
     for J in Picture'Range (2) loop
        Color := Picture (I, J);
        Result (I, J) :=
           Luminance
           (  (  2_126 * Extended_Luminance (Color.R)
              +  7_152 * Extended_Luminance (Color.G)
              +    722 * Extended_Luminance (Color.B)
              )
           /  10_000
           );
     end loop;
  end loop;
  return Result;

end Grayscale; Conversion to a color image: function Color (Picture : Grayscale_Image) return Image is

  Result : Image (Picture'Range (1), Picture'Range (2));

begin

  for I in Picture'Range (1) loop
     for J in Picture'Range (2) loop
        Result (I, J) := (others => Picture (I, J));
     end loop;
  end loop;
  return Result;

end Color;

C

Definition for a grayscale image.

typedef unsigned char luminance; typedef luminance pixel1[1]; typedef struct {

  unsigned int width;
  unsigned int height;
  luminance *buf;

} grayimage_t; typedef grayimage_t *grayimage;

The same as alloc_img, but for grayscale images.

grayimage alloc_grayimg(unsigned int width, unsigned int height) {

    grayimage img;
    img = malloc(sizeof(grayimage_t));
    img->buf = malloc(width*height*sizeof(pixel1));
    img->width = width;
    img->height = height;
    return img;

}

Convert from color image to grayscale image.

grayimage tograyscale(image img) {

  unsigned int x, y;
  grayimage timg;
  double rc, gc, bc, l;
  unsigned int ofs;
  timg = alloc_grayimg(img->width, img->height);
  
  for(x=0; x < img->width; x++)
  {
     for(y=0; y < img->height; y++)
     {
       ofs = (y * img->width) + x;
       rc = (double) img->buf[ofs][0];
       gc = (double) img->buf[ofs][1];
       bc = (double) img->buf[ofs][2];
       l = 0.2126*rc + 0.7152*gc + 0.0722*bc;
       timg->buf[ofs][0] = (luminance) (l+0.5);
     }
  }
  return timg;

}

And back from a grayscale image to a color image.

image tocolor(grayimage img) {

  unsigned int x, y;
  image timg;
  luminance l;
  unsigned int ofs;
  timg = alloc_img(img->width, img->height);
  
  for(x=0; x < img->width; x++)
  {
     for(y=0; y < img->height; y++)
     {
       ofs = (y * img->width) + x;
       l = img->buf[ofs][0];
       timg->buf[ofs][0] = l;
       timg->buf[ofs][1] = l;
       timg->buf[ofs][2] = l;
     }
  }
  return timg;

}

Notes

  • tocolor and tograyscale do not free the previous image, so it must be freed normally calling free_img. With a cast we can use the same function also for grayscale images, or we can define something like

  1. define free_grayimg(IMG) free_img((image)(IMG))

  • Luminance is rounded. Since the C implementation is based on unsigned char (256 possible values per components), L can be at most 255.0 and rounding gives 255, as we expect. Changing the color_component type would only change 256, 255.0 and 255 values here written in something else, the code would work the same.

Forth

\ grayscale bitmap (without word-alignment for scan lines)

\ bdim, bwidth, bdata all work with graymaps

: graymap ( w h -- gmp )
  2dup * bdata allocate throw
  dup >r 2! r> ;

: gxy ( x y gmp -- addr )
  dup bwidth rot * rot + swap bdata + ;

: g@ ( x y gmp -- c ) gxy c@ ;
: g! ( c x y bmp -- ) gxy c! ;

: gfill ( c gmp -- )
  dup bdata swap bdim * rot fill ;
\ RGB <-> Grayscale
: lum>rgb ( 0..255 -- pixel )
   dup 8 lshift or
   dup 8 lshift or ;

: pixel>rgb ( pixel -- r g b )
  256 /mod 256 /mod ;
: rgb>lum ( pixel -- 0..255 )
  pixel>rgb
   722 *   swap
  7152 * + swap
  2126 * + 10000 / ;

: bitmap>graymap ( bmp -- gmp )
  dup bdim graymap
  dup bdim nip 0 do
    dup bwidth 0 do
      over i j rot b@ rgb>lum
      over i j rot g!
    loop
  loop nip ;

: graymap>bitmap ( gmp -- bmp )
  dup bdim bitmap
  dup bdim nip 0 do
    dup bwidth 0 do
      over i j rot g@ lum>rgb
      over i j rot b!
    loop
  loop nip ;
 

OCaml

Conversion to a grayscale image: let to_grayscale ~img:(_, r_channel, g_channel, b_channel) =

 let width = Bigarray.Array2.dim1 r_channel
 and height = Bigarray.Array2.dim2 r_channel in
 let gray_channel =
   let kind = Bigarray.int8_unsigned
   and layout = Bigarray.c_layout
   in
   (Bigarray.Array2.create kind layout width height)
 in
 for y = 0 to pred height do
   for x = 0 to pred width do
     let r = r_channel.{x,y}
     and g = g_channel.{x,y}
     and b = b_channel.{x,y} in
     let v = (2_126 * r +  7_152 * g + 722 * b) / 10_000 in
     gray_channel.{x,y} <- v;
   done;
 done;
 (gray_channel)

Conversion to a color image: let to_color ~img:gray_channel =

 let width = Bigarray.Array2.dim1 gray_channel
 and height = Bigarray.Array2.dim2 gray_channel in
 let all_channels =
   let kind = Bigarray.int8_unsigned
   and layout = Bigarray.c_layout
   in
   Bigarray.Array3.create kind layout 3 width height
 in
 let r_channel = Bigarray.Array3.slice_left_2 all_channels 0
 and g_channel = Bigarray.Array3.slice_left_2 all_channels 1
 and b_channel = Bigarray.Array3.slice_left_2 all_channels 2
 in
 Bigarray.Array2.blit gray_channel r_channel;
 Bigarray.Array2.blit gray_channel g_channel;
 Bigarray.Array2.blit gray_channel b_channel;
 (all_channels,
  r_channel,
  g_channel,
  b_channel)

Vedit macro language

Conversion to a grayscale image.

//  Convert RGB image to grayscale (8 bit/pixel)
//    #10 = buffer that contains image data
//  On return:
//    #20 = buffer for the new grayscale image

:RGB_TO_GRAYSCALE:
File_Open("|(VEDIT_TEMP)\gray.data", OVERWRITE+NOEVENT+NOMSG)
#20 = Buf_Num
BOF
Del_Char(ALL)
Buf_Switch(#10)
Repeat(File_Size/3) {
    #9 =  Cur_Char() * 2126
    #9 += Cur_Char(1) * 7152
    #9 += Cur_Char(2) * 722
    Char(3)
    Buf_Switch(#20)
    Ins_Char(#9 / 10000)
    Buf_Switch(#10)
}
Return

Conversion to a color image.

//  Convert grayscale image (8 bits/pixel) into RGB (24 bits/pixel)
//    #20 = buffer that contains image data
//  On return:
//    #10 = buffer for the new RGB image

:GRAYSCALE_TO_RGB:
File_Open("|(VEDIT_TEMP)\RGB.data", OVERWRITE+NOEVENT+NOMSG)
#10 = Buf_Num
BOF
Del_Char(ALL)
Buf_Switch(#20)			// input image (grayscale)
BOF
Repeat(File_Size) {
    #9 =  Cur_Char()
    Char
    Buf_Switch(#10)		// output image (RGB)
    Ins_Char(#9, COUNT, 3)
    Buf_Switch(#20)
}
Return