Grayscale image: Difference between revisions
(→{{header|C}}: fixed a bug) |
(→{{header|C}}: more logical typedefs) |
||
Line 52: | Line 52: | ||
Definition for a grayscale image. |
Definition for a grayscale image. |
||
<c>typedef |
<c>typedef unsigned char luminance; |
||
typedef luminance pixel1[1]; |
|||
typedef struct { |
typedef struct { |
||
unsigned int width; |
unsigned int width; |
||
Line 66: | Line 67: | ||
grayimage img; |
grayimage img; |
||
img = malloc(sizeof(grayimage_t)); |
img = malloc(sizeof(grayimage_t)); |
||
img->buf = malloc(width*height*sizeof( |
img->buf = malloc(width*height*sizeof(pixel1)); |
||
img->width = width; |
img->width = width; |
||
img->height = height; |
img->height = height; |
||
Line 92: | Line 93: | ||
bc = (double) img->buf[ofs][2]; |
bc = (double) img->buf[ofs][2]; |
||
l = 0.2126*rc + 0.7152*gc + 0.0722*bc; |
l = 0.2126*rc + 0.7152*gc + 0.0722*bc; |
||
timg->buf[ofs][0] = ( |
timg->buf[ofs][0] = (luminance) (l+0.5); |
||
} |
} |
||
} |
} |
||
Line 104: | Line 105: | ||
unsigned int x, y; |
unsigned int x, y; |
||
image timg; |
image timg; |
||
luminance l; |
|||
unsigned int ofs; |
unsigned int ofs; |
||
Revision as of 23:19, 13 December 2008
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
<ada> type Grayscale_Image is array (Positive range <>, Positive range <>) of Luminance; </ada> Conversion to a grayscale image: <ada> 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; </ada> Conversion to a color image: <ada> 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; </ada>
C
Definition for a grayscale image.
<c>typedef unsigned char luminance; typedef luminance pixel1[1]; typedef struct {
unsigned int width; unsigned int height; luminance *buf;
} grayimage_t; typedef grayimage_t *grayimage;</c>
The same as alloc_img, but for grayscale images.
<c>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;
}</c>
Convert from color image to grayscale image.
<c>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;
}</c>
And back from a grayscale image to a color image.
<c>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;
}</c>
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
<c>#define free_grayimg(IMG) free_img((image)(IMG))</c>
- 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: <ocaml>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)</ocaml>
Conversion to a color image: <ocaml>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)</ocaml>