Examples for Assignment 1

Random Noise

void ImageAddNoise(Image *img, double factor);

Adds noise to an image. The amount of noise is given by the factor in the range [0.0..1.0]. 0.0 adds no noise. 1.0 adds a lot of noise.

noise0.gif (12403 bytes)
0.0
noise1.gif (18518 bytes)
0.25
noise2.gif (21625 bytes)
0.5
noise3.gif (22782 bytes)
0.75
noise4.gif (23266 bytes)
1.0

Brightness

void ImageBrighten(Image *img, double factor);

Changes the brightness of an image by interpolating between a black image (factor = 0.0) and the original image (factor = 1.0). Interpolation darkens the image, and extrapolation brightens it.  See Graphica Obscura.

brightness0.gif (1001 bytes)
0.0
brightness1.gif (12393 bytes)
0.5
brightness2.gif (12403 bytes)
1.0
brightness3.gif (11830 bytes)
1.5
brightness4.gif (10715 bytes)
2.0

Contrast

void ImageChangeContrast(Image *img, double factor);

Changes the contrast of an image by interpolating between a constant gray image (factor = 0) with the average luminance and the original image (factor = 1). Interpolation reduces contrast, extrapolation boosts contrast, and negative factors generate inverted images. See Graphica Obscura.

contrast0.gif (12278 bytes)
-0.5
contrast1.gif (1001 bytes)
0.0
contrast2.gif (12285 bytes)
0.5
contrast3.gif (12403 bytes)
1.0
contrast4.gif (11338 bytes)
1.7

Saturation

void ImageChangeSaturation(Image *img, double factor);

Changes the saturation of an image by interpolating between a gray level version of the image (factor = 0) and the original image (factor = 1). Interpolation decreases saturation, extrapolation increases it, and negative factors preserve luminance but invert the hue of the input image. See Graphica Obscura.

saturation0.gif (12584 bytes)
-1.0
saturation1.gif (18237 bytes)
0.0
saturation2.gif (12764 bytes)
0.5
saturation3.gif (12403 bytes)
1.0
saturation4.gif (12301 bytes)
2.5

Quantization

void ImageQuantize(Image *img, int nbits);

Converts an image to nbits bits per channel using uniform quantization.

The number of levels per channel is L = 2nbits. The size of each input interval is a = 256 / L. The size of each output output interval is b = 255.0 / (L - 1). Each component c is mapped to floor(c / a) * b. The graph below shows the resulting staircase function for the case nbits = 3

quantization.jpg (70758 bytes)

All the pixels within the same input interval are mapped to the same output level. Notice the contours that appear when nbits is low.

quantize1.gif (3642 bytes)
1
quantize2.gif (6953 bytes)
2
quantize3.gif (10603 bytes)
3
quantize4.gif (11920 bytes)
4
quantize5.gif (12496 bytes)
5

Other mappings exist, and will be accepted. Just make sure you explain the mapping you use.

Random Dither

void ImageRandomDither(Image *img, int nbits);

Converts an image to nbits bits per channel using random dithering. It is similar to uniform quantization, but random noise is added to each component during quantization. Using a and b as defined for quantization, each component c is mapped to floor(c / a + noise()) * b. The function noise() returns a random floating point number in the interval [-0.5,0.5].

randomDither1.gif (6166 bytes)
1
randomDither2.gif (11112 bytes)
2
randomDither3.gif (14954 bytes)
3
randomDither4.gif (13871 bytes)
4
randomDither5.gif (13053 bytes)
5

Ordered Dither

void ImageOrderedDither(Image *img, int nbits);

Converts an image to nbits bits per channel using ordered dithering. It is similar to uniform quantization, but pseudo-random noise is added to each component before quantization. The amount of noise added is determined by a Bayer's pattern matrix. The following examples used the matrix

Bayer4 = 15 7 13 5
3 11 1 9
12 4 14 6
0 8 2 10

For each pixel at (x,y), we compute i = x % 4, j = y % 4. Then, using a and b as defined for quantization, a component c is mapped to floor(c / a - 0.5 + Bayer4[i][j] / 15.0) * b.

orderedDither1.gif (3612 bytes)
1
orderedDither1.gif (3612 bytes)
2
orderedDither1.gif (3612 bytes)
3
orderedDither1.gif (3612 bytes)
4
orderedDither1.gif (3612 bytes)
5

Floyd-Steinberg Dither

void ImageFloydSteinbergDither(Image *img, int nbits);

Converts an image to nbits per channel using Floyd-Steinberg dither with error diffusion. Each pixel (x,y) is quantized, and the quantization error is computed. Then the error is diffused to the neighboring pixels (x + 1, y), (x - 1, y + 1), (x, y + 1), and (x + 1, y + 1) , with weights 7/16, 3/16, 5/16, and 1/16, respectively.

orderedDither1.gif (3612 bytes)
1
orderedDither1.gif (3612 bytes)
2
orderedDither1.gif (3612 bytes)
3
orderedDither1.gif (3612 bytes)
4
orderedDither1.gif (3612 bytes)
5

Blur

void ImageBlur(Image *img, int n);

Blurs an image by convolving it with a n x n Gaussian filter. In the examples below, the Gaussian function used was

wpe8D.jpg (2570 bytes)

and the value for sigma was chosen so that the weight at the center of the filter is 1.0, and the weight at a corner of the filter is 1 / (6 * r2 + 4 * r + 1), where r is n div 2.

blur1.gif (12577 bytes)
3
blur2.gif (11603 bytes)
7
blur3.gif (11161 bytes)
11
blur4.gif (11311 bytes)
15
blur5.gif (11312 bytes)
19

Edge detect

void ImageEdgeDetect(Image *img);

Detect edges in an image by convolving it with an edge detection kernel. In the example below, the kernel used was

-1

-1

-1

-1

8

-1

-1

-1

-1

edgeDetect.gif (11555 bytes)

Scale

Image *ImageScale(Image *img, double sx, double sy);

Scales an image in x by sx, and y by sy. The result depends on the current sampling method (point, bilinear, or Gaussian). In the example below, the size of the Gaussian filter is 3x3.

scale1.gif (26874 bytes)
Point
scale2.gif (29226 bytes)
Bilinear
scale3.gif (27586 bytes)
Gaussian

If minifying, instead of magnifying, first blur the image, then point sample. The size of the blur filter is the inverse of the minification factor, rounded up to the closest odd number greater than or equal to 3.

Rotate

Image *ImageRotate(Image *img, double angle);

Rotates an image by the given angle. The result depends on the current sampling method (point, bilinear, or Gaussian). In the example below, the size of the Gaussian filter is 3x3.

rotate1.gif (13595 bytes)
Point
rotate2.gif (13842 bytes)
Bilinear
rotate3.gif (13617 bytes)
Gaussian

Composite

void ImageComposite(Image *bottom, Image *top, Image *result);

Composites the bottom and top images into the result image.

Original Images

selecao.gif (145753 bytes)

wagner.gif (127838 bytes)

Brazilian soccer team ("seleção")

Me

Auxiliary Images

image -constantColor 373 512 0 0 0 > black.bmp
image -constantColor 373 512 0 0 255 > blue.bmp
black.gif (1540 bytes) blue.gif (1540 bytes)
image -scale .27272727 .27272727 < wagner.bmp > front_mask1.bmp
image -extractBlueMask 94 26 60 106 < front_mask1.bmp > front_mask2.bmp
image -subimage 94 26 60 106 < front_mask2.bmp > front_mask3.bmp
front_mask1.gif (11429 bytes) front_mask2.gif (1696 bytes) front_mask3.gif (1409 bytes)
image -paste front_mask3.bmp 200 138 < blue.bmp > front_mask4.bmp
image -blur 11 < front_mask4.bmp > front_mask.bmp
front_mask4.gif (1993 bytes) front_mask.gif (8001 bytes)
image -subimage 94 26 60 106 < front_mask1.bmp > front1.bmp
image -paste front1.bmp 200 133 < black.bmp > front.bmp
front1.gif (8724 bytes) front.gif (6820 bytes)

Final Image

image -composite black.bmp front.bmp front_mask.bmp < selecao.bmp > final.bmp

composite.gif (145527 bytes)

Fun

void ImageFun(Image *img);

Warps an image using a creative filter of your choice. In the following example, each pixel is mapped to its corresponding scaled polar coordinates. The artifacts of point sampling are very noticeable in this example.

funk.gif (8490 bytes)
Original
fun1.gif (6775 bytes)
Point
fun2.gif (10878 bytes)
Bilinear
fun3.gif (10541 bytes)
Gaussian