How do I manipulate images in Java?
Use our Picture
data type (which is part of algs4.jar
)
and Java’s java.awt.Color data
type.
Luminance.java
and
Grayscale.java
are example clients.
I noticed that the Picture API has a method to change the origin (0, 0) from the upper left to the lower left. Can I assume (0, 0) is the upper left pixel? Yes (and you should not call this method).
Must the arguments to removeHorizontalSeam()
and removeVerticalSeam()
be minimum energy seams?
No. Each method should work for any valid seam (and throw an exception for any invalid one).
The SeamCarver
data type is mutable. Must I still defensively copy of the Picture
objects?
A data type should not have side effects (unless they are specified in the API).
It should behave properly as prescribed even if the client mutates
the Picture
object passed to the constructor or returned from the
picture()
method.
As a result, you might need to make defensive copies of any Picture
objects
that you either take as input or return as output.
Can I use dynamic programming? Yes, though, in this context, dynamic programming is equivalent to the topological sort algorithm for finding shortest paths in DAGs.
My program is using recursion to find the shortest energy path. Is this okay? You should not need recursion. Note that the underlying DAG has such special structure that you don’t need to compute its topological order explicitly.
My program seems to be really slow. Any advice? We recommend that you implement the first four of these optimizations, but you can improve performance further my implementing some of the later ones.
EdgeWeightedDigraph
.
Instead, execute the topological sort algorithm directly on the pixels.
energy()
at most once per pixel.
For example, you can save the energies in a local variable energy[][]
and access the information directly from the 2D array (instead of recomputing from scratch).
get()
method in Picture
.
For example, to access the red, green, and blue components of a pixel,
call get()
only once (and not three times).
Color
objects can be a bottleneck.
Each call to the get()
method in Picture
creates a new Color
object.
You can avoid this overhead by using the getRGB()
method in Picture
,
which returns the color, encoded as a 32-bit int
.
The companion setRGB()
method
sets the color of a given pixel using a 32-bit int
to encode the color.
Picture
or int[][]
until you need to do so.
For example, if you perform a sequence of 50 consecutive horizontal seam
removals, you should need only two transposes (not 100).
System.arraycopy()
to shift elements within an array.
How much memory can my SeamCarver
object use as a function of W
and H?
A Picture
objects uses ~ 4W H bytes of memory—a single 32-bit int
per pixel.
Unless you are optimizing your program by updating only the energy values that change after
removing a seam, you should not need to maintain the energy values in an instance variable.
Similarly, the distTo[][]
and edgeTo[][]
arrays should be local variables,
not instance variables.
For reference, a Color
object consumes 48 bytes of memory.
Clients. You may use the following client programs to test and debug your code.
printseams.txt
file
(such as 5x6.printseams.txt), so you can
compare your results to the correct solution.
Sample input files. The zip file seam.zip contains the client programs above along with some sample image files. You can also use your own image files for testing and entertainment.
picture()
, width()
and height()
.
These should be very easy.
energy()
.
Calculating Δx2 and Δy2
are very similar. Using two private methods will keep your code simple.
To test that your code works,
use the client PrintEnergy
described in the testing section above.
findVerticalSeam()
, you will want to first make
sure you understand the topologial sort algorithm for computing a shortest path in a DAG.
Do not create an EdgeWeightedDigraph
. Instead construct a 2d
energy array using the energy()
method that you have already written.
Your algorithm can traverse this matrix
treating some select entries as reachable from (x, y)
to calculate where the seam is located.
To test that your code works,
use the client PrintSeams
described in the testing section above.
findHorizontalSeam()
,
transpose the image, call findVerticalSeam()
,
and transpose it back.
removeVerticalSeam()
.
Typically, this method will be called with the output of findVerticalSeam()
,
but be sure that they work for any seam.
To test that your code words, use the client ResizeDemo
described in the testing section above.
removeHorizontalSeam()
, transpose the image, call removeVerticalSeam()
,
and transpose it back.