Race Condition Image Batch Assignment

From CSE231 Wiki
Jump to navigation Jump to search

Motivation

Race conditions can lead to difficult bugs to find and fix. We gain experience finding them and fixing them.

Background

Pixels

The word pixel stands for Picture Element. A pixel is a small part of a picture. Pixels are the little dots that make up computer screens. When you see a low-resolution picture that is grainy, the grains you’re seeing are the pixels.

Color Models

There are many different representations of Color. These representations are called color models.

Subtractive Color Models

Some color models are subtractive. These models are useful for printing. They are subtractive because they model the subtraction of light as each color absorbs light (before what remains to bounce off into your eyes). The most common of these models is CMYK which represents Cyan, Magenta, Yellow, blacK. If you have ever changed the ink in a color printer, you have encountered CMYK cartridges. Truth be told, you don’t need the black. Essentially all of the visible spectrum of light would be absorbed printing layers of cyan, magenta, and yellow. A lot of black tends to be printed, so it is more cost effective to add to add black into the model.

CMYK subtractive color mixing

Additive Color Models

Component_video_RCA

Some color models are additive. These models are useful for display devices. They are additive because they model the addition of light which is thrown at your eyes.

RGB

RGB_color_solid_cube

The most common of these models is RGB which repesents Red, Green, Blue. If you have ever plugged an old device into a TV with a component video cable, that is what the separate cables are carrying: analog signal for red, green, and blue.

RGB_illumination

HSV

We will use the HSV color model which represents Hue, Saturation, Value.

HSV_color_solid_cylinder_saturation_gray

This model benefits from often being easier for humans to think about and will enable us to create some compelling image filters with minimal effort. Evidence for it being easier for humans to think about can be found in most defaults for color pickers, including the one which can be found by searching on Google for color picker.

Play around with the color picker for a while and watch the hue, saturation, and value change as you interact with it. Try to isolate the saturation by dragging left to right in the rectangle component of the color picker. Isolate changes to the value by dragging up and down. Control the hue with the slider below.

Google color picker.png

Hue

Hue is cyclical. Red is usually at 0.0 and the hue changes as you go around the ring… returning back to red at 1.0.

Saturation

Full saturation is a completely “vivid” form of the color. No saturation is “dull” gray.

Value

This component is somewhat uninspiringly named: “value”. It is called brightness or lightness in similar color models. Value can be somewhat confusing since one might expect a full (1.0) "brightness" value to always equate to white, which it does not.

Code To Investigate

HsvColor

class HsvColor

double hue()
double saturation()
double value()


SequentialImageFilter

class SequentialImageFilter  
public class SequentialImageFilter implements ImageFilter {
	@Override
	public HsvImage apply(HsvImage src, PixelFilter pixelFilter) {
		HsvImage dst = new HsvImage(src.width(), src.height());
		for (int y = 0; y < src.height(); ++y) {
			for (int x = 0; x < src.width(); ++x) {
				Optional<HsvColor> srcPixelOptional = src.colorAtPixel(x, y);
				if (srcPixelOptional.isPresent()) {
					HsvColor srcPixel = srcPixelOptional.get();
					HsvColor dstPixel = pixelFilter.apply(srcPixel);
					dst.setColorAtPixel(x, y, dstPixel);
				} else {
					throw new Error();
				}
			}
		}
		return dst;
	}
}

DesaturateAllPixelFilter

class DesaturateAllPixelFilter  
public class DesaturateAllPixelFilter implements PixelFilter {
	@Override
	public HsvColor apply(HsvColor src) {
		return new HsvColor(src.hue(), 0.0, src.value());
	}
}

DesaturateNonSkinTonePixelFilter

class DesaturateNonSkinTonePixelFilter  
public class DesaturateNonSkinTonePixelFilter implements PixelFilter {
	private static boolean isInRange(double min, double x, double max) {
		return min < x && x < max;
	}
	private static boolean isSkin(HsvColor src) {
		return (src.hue() < 0.1 || src.hue() > 0.9) && isInRange(0.1, src.saturation(), 0.7);
	}
	@Override
	public HsvColor apply(HsvColor src) {
		return new HsvColor(src.hue(), isSkin(src) ? src.saturation() : 0.0, src.value());
	}
}

SequentialImageBatch

public class SequentialImageBatch implements ImageBatch {
	@Override
	public ImmutableHsvImage[] filterAllImages(ImmutableHsvImage[] images, ImageFilter imageFilter,
			PixelFilter pixelFilter) throws InterruptedException, ExecutionException {
		ImmutableHsvImage[] filteredImages = new ImmutableHsvImage[images.length];
		for (int i = 0; i < images.length; ++i) {
			filteredImages[i] = imageFilter.apply(images[i], pixelFilter);
		}
		return filteredImages;
	}
}

Code To Debug

ImageBatch

filterAllImages

class: ParallelImageBatch.java Debugging icon.png
methods: filterAllImages
package: racecondition.image.exercise
source folder: student/src/main/java

method: ImmutableHsvImage[] filterAllImages(ImmutableHsvImage[] images, ImageFilter imageFilter, PixelFilter pixelFilter) Parallel.svg (parallel implementation required)

If one had a filter that could be applied to an image independently, it is reasonable to apply the filter to each image in an array of images in parallel. Unfortunately, the code you must debug has a data race. Fix the data race in ParallelImageBatch's filterAllImages method.

public class ParallelImageBatch implements ImageBatch {
	@Override
	public ImmutableHsvImage[] filterAllImages(ImmutableHsvImage[] images, ImageFilter imageFilter,
			PixelFilter pixelFilter) throws InterruptedException, ExecutionException {

		@SuppressWarnings("unchecked")
		Future<Void>[] futures = new Future[images.length];
		ImmutableHsvImage[] filteredImages = new ImmutableHsvImage[images.length];
		int[] array = { 0 };
		for (array[0] = 0; array[0] < images.length; ++array[0]) {
			futures[array[0]] = void_fork(() -> {
				filteredImages[array[0]] = imageFilter.apply(images[array[0]], pixelFilter);
			});
		}
		join(futures);
		return filteredImages;

	}
}

Client

class: ImageBatchApp.java VIZ
package: racecondition.image.viz
source folder: student/src/main/java

Testing Your Solution

Correctness

class: _ImageBatchTestSuite.java Junit.png
package: racecondition.image.exercise
source folder: testing/src/test/java

Pledge, Acknowledgments, Citations

file: race-condition-image-batch-pledge-acknowledgments-citations.txt

More info about the Honor Pledge