This page does not represent the most current semester of this course; it is present merely as an archive.
There are two options for this assignment.
filename.png
in various languagespng
files in C or C++ so I don’t have details).
System.Drawing.Bitmap
: Bitmap img = Bitmap.fromFile("filename.png")
auto img = read_image("filename.png")
javax.imageio.ImageIO
: BufferedImage img = ImageIO.read("filename.png")
img = Image.open("filename.png")
The input examples use the following input files:
The structure of this assignment will be somewhat similar to those before: you’ll read an input .txt
file and create an output .png
file. The input .txt
will generally begin with an instruction to read an RGBA .png
file and generally end with an instruction to write an RGBA .png
file of the same dimensions as the input.
You can probably make some progress working directly on the image files, but you will almost certainly find it easier to do the following:
Convert all the 0–255 integers into 0–1 floating-point values as soon as you load an image.
Do not clamp pixel channel values to the 0–1 range during processing, but do do so before saving the image.
You’ll want to be able to query and change R, G, B, H, S, L, V, and A channels on an image. There are two basic ways to do this:
hue(r, g, b)
, red(h, s, l)
, etc.)
getHue
and setSaturation
.
\(V = \max(R,G,B)\)
\(\Delta = V - \min(R,G,B)\) (note: \(\Delta\) is not itself a channel, but is useful in computing several of the other channels).
\(S = \frac{\Delta}{V}\) (or 0 if \(V\) is 0)
There are other formulae for saturation. This version is typical for HSV color models; HSL often has a different form.
\(L = 0.299 R + 0.587 G + 0.114 B\)
There are many other formulae for lightness. This version is from ITU BT.601.
\(H =\) a piecewise-linear function:
Recall that Hue is a circle, so 0 is closer to 0.9 than it is to 0.2.
For some optional parts you’ll need the reverse functions too.
To convert \((H,S,V) \rightarrow (R,G,B)\)
To change \(L\)
Given the way we’ve defined \(H\), \(S\), and \(L\) we cannot always change \(L\) without changing \(S\) (this follows from picking HSV’s version of \(S\) instead of HSLs). The following does the best we can do:
Otherwise,
See http://www.rapidtables.com/convert/color/ for another explanation (but note that their HSL uses different S and L than we have above).
The required part is worth 50%
hw5monochromeL.txt
hw5monochromeS.txt
hw5monochromeH.txt Replace the red, green, and blue channels of the current image with a copy of the given channel. Set every alpha value to 1.
You may assume that channel is one of the following eight strings: red
, green
, blue
, alpha
, hue
, saturation
, value
, lightness
.
This operator can typically be done in-place, though it also works if you copy the image.
hw5equalize.txt Find the minimum and maximum value of the specified channel in the image. Then replace every pixels’ entry in that channel with \(channel\_value - minumum \over maximum - minimum\).
You may assume that channel is one of the following three strings: red
, green
, blue
.
This operator can typically be done in-place, though it also works if you copy the image.
hw5gradient.txt The Scharr 3-by-3 convolution filter \[\frac{1}{16}\begin{bmatrix}+3&+10&+3\\0&0&0\\-3&-10&-3\end{bmatrix}\] will find the \(y\)-gradient of the image; its rotated version \[\frac{1}{16}\begin{bmatrix}-3&0&+3\\-10&0&+10\\-3&0&+3\end{bmatrix}\] will find the \(x\)-gradient. You’ll need those gradients for many of the optional parts.
For the required part, set the green channel of the image to the \(y\)-gradient of the lightness channel and both the blue and red channels to the \(x\)-gradient of the lightness channel.
This operator can typically cannot be done in-place; you’ll need to make a copy of the image first.
hw5equalizeL.txt
hw5equalizeH.txt Extend all operations to work on any of the eight channels.
When setting Hue, Saturation, or Value, assume that the other two of those are held constant. When setting Lightness, scale R, G, and B by new lightness ÷ old lightness;.
Black is a special case for almost all of these; you are welcome to handle initially-black pixels however you wish.
hw5posterize.txt Clamp the given channel to just \(n\) distinct values, \(i \over n - 1\) for \(i \in \{0, 1, 2, \dots, n-1\}\). Move every pixel’s value in the given channel to the nearest of those values.
You may assume that \(n \ge 2\) and that channel is one of the following four strings: red
, green
, blue
, alpha
.
posterize
)
hw5dither.txt Clamp the given channel to just \(n\) distinct values, \(i \over n - 1\) for \(i \in \{0, 1, 2, \dots, n-1\}\). For any pixel whose value is between two of the output values, pick one of the two nearest values randomly with probability proportional to the nearness to each.
You may make the same assumptions about \(N\) and channel as you did for posterize
.
red
, green
, blue
, or alpha
. The result of the convolution should become the new current image.
hw5blur.txt Convolve the given channel in x and in y by a discrete approximation of a Guassian filter with \(n\) entries. The entries should be normalized binomial coefficients (i.e., the \(n\)th row of Pascal’s triangle divided by \(2^{n-1}\)); for example, \(n=7\) will give the filter \(\frac{1}{64}\begin{bmatrix}1&6&15&20&15&6&1\end{bmatrix}\).
You may assume that \(n\) is a positive odd integer and that channel is one of the following four strings: red
, green
, blue
, alpha
.
hw5sharpen.txt Sharpen the given channel of the image by convolving it with the matrix \[\begin{bmatrix}-0.1a&-0.15a&-0.1a\\-0.15a&1+a&-0.15a\\-0.1a&-0.15a&-0.1a\end{bmatrix}\]
You may assume that channel is one of the following three strings: red
, green
, blue
.
hw5flood.txt Flood fill the image, starting with the pixel at coordinate \(x\), \(y\), with the color \((r, g, b, a)\). Fill any pixel that is four-connected to another filled pixel and is within \(\Delta\) (which will be between 0 and 1) of the original pixel at coordinate \(x\), \(y\) in all four of the RGBA channels.
You may assume the initial color at \((x,y) \ne (r,g,b,a)\)
hw5carve.txt Use seam carving to make the image one pixel narrow
er in width or short
er in height. Use gradient magnitude as a proxy for visual interest. In case of a tie (two or more seams of equally low total interest), pick one arbitrarily.
To find the gradient magnitude, compute the \(x\) and \(y\) gradients of the image in all R, G, and B and combine those six values using Euclidean distance (i.e., \(\sqrt{G_{r,x}^2 + G_{r,y}^2 + G_{g,x}^2+\dots}\)).
hw5path.txt Use a shortest-path algorithm to connect the two input pixels \((x_1, y_1)\) and \((x_2, y_2)\). Fill the input pixels, and all pixels on the path between them, with the color \((r, g, b, 1)\).
Each pixel has eight neighbors. The distance
to a neighbor is Euclidean distance (1 for 4-connect neighbors, \(\sqrt{2}\) for diagonal neighbors) times the flatness
of the neighbor being entered (there are various ways to compute that; we’ll use \(1 \over \mathrm{gradient\;magnitude} + 0.1\)).
To find the gradient magnitude, compute the \(x\) and \(y\) gradients of the image in all R, G, and B and combine those six values using Euclidean distance (i.e., \(\sqrt{G_{r,x}^2 + G_{r,y}^2 + G_{g,x}^2 + \dots}\)).
hw5advect.txt Use back-advection to move colors around the image. The new color of pixel \((x, y)\) should be computed as the color of the image at \((x + g_x d, y + g_y d)\) where \((g_x, g_y)\) is the gradient of the chan channel of the image at \((x, y)\).
When sampling a pixel at location \((x,y)\) with non-integer coordinates, use a weighted average of the pixels at \((\lfloor x\rfloor, \lfloor y\rfloor)\), \((\lceil x\rceil, \lfloor y\rfloor)\), \((\lfloor x\rfloor, \lceil y\rceil)\), and \((\lceil x\rceil, \lceil y\rceil)\).