SciVis 2015 Project 2: "mapr"
Assigned Mon Jan 26; Due Wed Feb 4 at 11:59pm
This project involves material covered in the class Jan 15 through Jan 27, the readings on colormaps assigned, and in (FSV) class notes Sections 1.0 through 1.10 (FSV Sections 4.3 and 4.4 are redundant with math covered on the board, but may be useful for reference; they were not assigned because they different variable naming than everything else we've done). The basic goal of this project is to generalize to two dimensions the abstraction implemented in the first project: a continuous field (reconstructed by convolution with discretely sampled data) that may be evaluated and differentiated at arbitrary points in world-space. We also include colormapping, shading (based on the gradient), and 2-D isocontouring via "Marching Squares". In the end you will have a utility that can create nice shaded topographic maps as EPS files.
(note non-canonical due date and time)
Logistics
Your CNETID-scivis-2015 directory should now be populated with a p2mapr directory which contains all the files for this project. As long as you have environment variable $SCIVIS set correctly, and if you are logged into one of the CSIL Macs, you should be able to type make in p2mapr to build a mapr executable. You should also have a reference executable rmapr which you should use for comparison and debugging. You can work individually or in pairs for this project; see the information in the Logistics section of the Project 1 page for details; you should see a "Project 2: mapr (p2mapr)" assignment for which you can create a work group. If you pair up with the same partner as in a previous assignment, you will be re-using the previously created repository.What to do
As in the first project, the specification of what to do lies mainly within the given source files, and reference executable rmapr. As before, run "./rmapr" to review the commands available, and run "./rmapr about" the functions that will need to be implemented. For each of the mapr X commands corresponding to work you have to do, you should carefully read the usage information (generated by "./mapr X") to make sure you understand the purpose of the command and the meaning of its command-line options. Scrutinizing the implementation of the command (in mapr_X.c) may also be informative.In the definition of functions that you have to implement, you will see lines:
DO NOT EDIT THESE LINES (the ones with v.v.v.v and ^'^'^'^'^), or anything outside the regions that they delineate. For this project there aren't blank lines that indicate the number of lines in the reference implementation, to ensure that you can think freely about what is needed for the project and how to create it./* v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v begin student code */ /* ^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^'^ end student code */For this project, you should may also edit the header file (mpr.h) to augment the definition of the mprContext struct, to include resources (buffers) or state that you want to set on a per-image or per-kernel basis, independent of where the convolution is being evaluated. Resources allocated in mprContextNew should be cleaned up in mprContextNix. Thus, your implementation of mprConvoEval will involve making multiple coordinate changes to multiple files, unlike the more strictly sequential nature of work in the first project. In some source files you may also add new functions, but these must be static functions (only for use within that source file). As before, you may not create new source files, or edit the Makefile.
You are responsible for reading through mpr.h to understand what functions are defined where, and reading through mprMath.h to see what matrix-related macros are available for use.
At the start of the functions that you have to implement, there is a comment block that defines what the inputs and outputs to the function should be; this provides the technical definition of what a correct implementation should be. The reference implementation rmapr should conform to this.
The implementation of mprPictureSample() (given to you) may be especially informative to read through. It shows how:
mprPictureEval() is also good to understand, since it shows the context of calling mprPictureRGB(), which you have to implement.
- different "modes" (different values of the mprMode enum) generate different kinds of images (in terms of img->type and img->channel)
- a rectangular view of world-space is specified by the center, angle, height, and size0,size1 arguments
- how the output image index space is sampled, and what happens at each sample: first mprConvoEval(), and then mprPictureEval(), which draws on the information learned by convolution and stored in the mprContext.
For 33710 students
For this project there is some additional work for 33710 students to do relative to 23710 students (although in reality it more like some of the original expectations are not required for 23710):
- The mprIsocontour implementation should avoid computing isocontour segments for cells (i.e. the squares between four adjacent data samples) that lie outside the view defined by the -c, -h, -a, and -r options to mapr iso (which are the center, height, angle, and aspect arguments to mprIsocontour().
- The mprIsocontour should gracefully handle the case of having one cell corner's value be exactly equal to the given isovalue. That means that a zero-length segment should not be generated there, nor should adjacent segments disappear (relative to what would be seen were the isovalue a tiny bit higher or lower).
- The interpolation between colormap control points in HSV space correctly handles that hue=0 is the same as hue=1 (these are two ways of identifying the same point on a circle). When linearly interpolating between two points on the hue circle, you should choose the shorter of the two paths to move along. So, interpolating from hue 0.86 to hue 0.03 should be like interpolating from 0.86 to 1.03, except that interpolated hues above 1.0, or below 0.0, are wrapped back into [0,1], but subtracting or by adding one, respectively, before conversion to RGB.
Example mapr/rmapr commands to try
The commands here use "./rmapr"; you should make sure that you get the exactly same results by running "./mapr". There is new data in the scivis-2015 repository, which below will be referred to below as "$SCIVIS", in the data/2d subdirectory. Read the 00-info.txt file there to see a description of the datasets useful for this project. There are also (as of Jan 30) some sample colormaps in the cmap directory.
- Always make sure your code builds cleanly with "make"
- To learn about the geometry of any of the given images, you can use rmapr info. There is no code in here for you to write. Try "./rmapr info $SCIVIS/data/2d/x00a.nrrd" In this project (an in this class in general), axes are ordered fast to slow; so when rmapr info says "15 by 31 image" it means 15 samples on the faster axis (or at run-time 15 == img->size[0]) and 31 samples on the slower axis (31 == img->size[1]). The information about where the corners of the image are can inform settings in the "-c" and "-h" arguments to psamp commands.
- For mprConvoEval(), note that (from the code in mprContextNew()) the only kind of image that you'll have to handle for convolution is a 1-channel image of floats. Make sure you can correctly reconstruct from the different samplings of f(x,y)=x in $SCIVIS/data/2d/x???.nrrd. The point is that your convolution evaluation should always return the first ("x") world-space coordinate, because those are the value stored in the sampled data, and the gradient should always be, to within floating point errors, (1,0).
- ./rmapr ceval -i $SCIVIS/data/2d/x00i.nrrd -k tent -w 0 0 -g true
- ./rmapr ceval -i $SCIVIS/data/2d/x00i.nrrd -k tent -w 0.3 0 -g true
- ./rmapr ceval -i $SCIVIS/data/2d/x00i.nrrd -k tent -w 0.3 0.4 -g true
- Try all the of the above, but using any of the other x-ramp datasets: x00a.nrrd (no grid rotation, but anisotropic sampling), x30i.nrrd (isotropic grid rotated by 30 degrees), x30a.nrrd (anisotropic grid rotated by 30 degrees), etc.
- Try all these with the different kernels (as listed by "mapr klist") in place of "-k tent". Note that "-k box" will not correctly reconstruct f(x,y)=x.
- You can use the psamp command in its default mprModeValue mode ("-m v") as a thin wrapper around mprConvoEval, to test mprConvoEval. For example, to see the results of nearest-neighbor interpolation:
./rmapr psamp -i $SCIVIS/data/2d/x30a.nrrd -k box -c 0 0 -h 25 -o tmp.nrrd unu 2op exists tmp.nrrd 0 | unu quantize -b 8 -o tmp.png open tmp.pngThe "unu 2op exists" usage says "where the values in tmp.nrrd are finite (not NaN), use them, otherwise use 0". This is then quantized to 8-bits for inspection.- One test of correctly handling image orientation is enabled by the different ways of showing the "2-by-3" matrix of integers from 0 to 5 in the same locations in world space:
./rmapr psamp -i $SCIVIS/data/2d/sixa.nrrd -k box -c 1 0.5 -h 2 -sz 300 200 -o tmp.nrrd unu minmax tmp.nrrd unu quantize -b 8 -i tmp.nrrd -min 0 -max 5 -o tmp.png; open tmp.pngThe unu minmax command should print exactly:
min: 0 max: 5and not anything about "has non-existent values", which would signify that your mprConvoEval code set either ctx->outside[0] or ctx->outside[1] to non-zero. The commands above should be exactly the same for all eight sixa.nrrd, sixb.nrrd, sixc.nrrd, ..., and sixh.nrrd.- Part of applying a colormap is knowing the range of scalar values that are being mapped. You can learn this not with mapr info, but with unu minmax:
- unu minmax $SCIVIS/data/2d/x30a.nrrd
- unu minmax $SCIVIS/data/2d/italy.nrrd
- To test your handling of colormaps in mprPictureRGB, you can use the mapr cma command to apply a colormap per-sample, without any convolution (you can see in mapr_cma.c how this is done).
The last one will reveal whether you are correctly handling interpolation of hue near hue=0, which is the same red as hue=1 (hue values from 0 to 1 trace out a circle). Doing this right is expected of the 33710 students.
- ./rmapr cma -i $SCIVIS/data/2d/ramp.nrrd -cmap $SCIVIS/cmap/gray-cmap.txt -o tmp.png; open tmp.png
- ./rmapr cma -i $SCIVIS/data/2d/ramp.nrrd -cmap $SCIVIS/cmap/bbody-cmap.txt -o tmp.png; open tmp.png
- ./rmapr cma -i $SCIVIS/data/2d/ramp.nrrd -cmap $SCIVIS/cmap/helix-cmap.txt -o tmp.png; open tmp.png
- ./rmapr cma -i $SCIVIS/data/2d/ramp.nrrd -cmap $SCIVIS/cmap/bow-cmap.txt -o tmp.png; open tmp.png
- Fixing the colormap so that its domain is appropriate for the range of data values can be done with mapr cmrs (implemented for you). For example, based on the output of unu minmax $SCIVIS/data/2d/italy.nrrd, we might:
./rmapr cmrs -i $SCIVIS/cmap/helix-cmap.txt -mm -4000 4000 -o map.txt ./rmapr cma -i $SCIVIS/data/2d/italy.nrrd -cmap map.txt -o tmp.png; open tmp.png- To combine testing your handling of colormaps with convolution, you can also look at the x-ramp data with the psamp and a gray-scale colormap (set up as informed by unu minmax $SCIVIS/data/2d/x30a.nrrd.
and then try all the other available kernels in place of "-k box"
- ./rmapr cmrs -i $SCIVIS/cmap/gray-cmap.txt -mm -20.5 20.5 -o map.txt
./rmapr psamp -m vc -i $SCIVIS/data/2d/x30a.nrrd -k box -c 0 0 -h 25 -cmap map.txt -o tmp.png; open tmp.png- ./rmapr cmrs -i $SCIVIS/cmap/helix-cmap.txt -mm -20.5 20.5 -o map.txt
./rmapr psamp -m vc -i $SCIVIS/data/2d/x30a.nrrd -k box -c 0 0 -h 25 -cmap map.txt -o tmp.png; open tmp.png- To test your handling of gradients, you can use the ceval command to test how rmapr vs your mapr compute gradients at specific locations (of your choosing, in images of your choosing). You can also use the "psamp -m g", and then make a qualitative visualization of the gradients that result:
./rmapr psamp -i $SCIVIS/data/2d/dome3a.nrrd -k bspln3 -m g -c 0.7 0.7 -h 5 -sz 400 400 -o - | unu pad -min 0 0 0 -max 2 M M -b wrap | unu 2op exists - -0.5 | unu quantize -b 8 -min -4 -max 4 -o tmp.png && open tmp.pngNote that the output of the psamp command is being directly piped into unu. Try this also with dome3b.nrrd, dome3c.nrrd, and dome3d.nrrd. The "unu pad" command turns the 2-channel image into a 3-channel image by wrapping the x-component of the gradient into the 3rd channel, which is then quantized to an 8-bit color image, in which gray means zero, magenta means positive X, and green means positive Y. The -c and -h settings to psamp were informed by using ./rmapr info.- To show how gradients can be used for shading a topographic map:
./rmapr cmrs -i $SCIVIS/cmap/diverg-cmap.txt -mm -2000 2000 -o map.txt ./rmapr psamp -i $SCIVIS/data/2d/italy.nrrd -cmap map.txt -m vcs \ -l -1 1 1 -ze 7 -sh 0.5 -c 0 0 -h 1040000 -k bspln3 -sz 660 880 -o tmp.png ; open tmp.png- To test your isocontouring code, you should start with a tiny dataset for which you can almost compute the isocontour segments by hand, and then make sure they agree with what your code does. This is the point of $SCIVIS/data/2d/lump.nrrd (you can cat or more or less the file to see all the data and meta-data). You can make an EPS file of the mapr psamp output because the orientation meta-data is saved within the PNG file. First to see the original data values:
./rmapr cmrs -i $SCIVIS/cmap/helix2-cmap.txt -mm 0 6 -o map.txt ./rmapr psamp -i $SCIVIS/data/2d/lump.nrrd -m vc -cmap map.txt \ -k box -c 0 0 -h 5 -sz 400 400 -o tmp.png ./rmapr eps -i tmp.png -scl 2 -o tmp.eps; open tmp.epsAnd then, to see the data with the bilinear interpolation (related to the linear interpolation underlying the isocontouring), and with some shading to highlight the cell boundaries (re-using same map.txt as above):./rmapr psamp -i $SCIVIS/data/2d/lump.nrrd -m vcs -cmap map.txt \ -l -1 2 4 -sh 0.5 -k tent -c 0 0 -h 5 -sz 400 400 -o tmp.png ./rmapr eps -i tmp.png -scl 2 -o tmp.eps; open tmp.epsAnd finally, adding an isocontour (re-using tmp.png as above):./rmapr iso -i $SCIVIS/data/2d/lump.nrrd -v 1.5 -o seg-1.txt ./rmapr eps -i tmp.png -c seg-15.txt -scl 2 -th 2 -o tmp.eps; open tmp.epsOr many isocontours (in bash, again re-using tmp.png):rm -f seg-?.txt for V in 0 1 2 3 4 5; do ./rmapr iso -i $SCIVIS/data/2d/lump.nrrd -v $V.5 -o seg-$V.txt done ./rmapr eps -i tmp.png -c seg-?.txt -scl 2 -th 2 -o tmp.eps; open tmp.eps- To make sure that the isocontouring code correctly handles all the cases correctly (the 16 cases of the cell corners being above or below the isocontour), its nice to have a small dataset that exercises all those possibilities. $SCIVIS/data/2d/noise.nrrd was created for this purpose, at isovalue 0.5. We can first visualize what the isocontour should look like, with a colormap that selects a very narrow range of colors, and otherwise uses a clear threshold:
./rmapr psamp -i $SCIVIS/data/2d/noise.nrrd -k tent -m vc \ -cmap $SCIVIS/cmap/thresh-cmap.txt -sz 600 520 -c 7.5 6.5 -h 13 -o tmp.png ./rmapr eps -i tmp.png -scl 1.3 -o tmp.eps; open tmp.epsAnd then computing and drawing an isocontour on the same re-used tmp.png:./rmapr iso -i $SCIVIS/data/2d/noise.nrrd -v 0.5 -o seg.txt ./rmapr eps -i tmp.png -c seg.txt -scl 1.3 -o tmp.eps; open tmp.epsNote how the black computed isocontour segments should agree with the white approximate isocontour generated via bilinear interpolation and then colormapping. The agreement should be exact at the cell boundaries. In the "ambiguous" cases the colormapped isocontour will have a curved shape rather than a straight line, but the topology should be correct nonetheless. Redo with inverted data values stress tests the ambiguous cases further:./rmapr psamp -i $SCIVIS/data/2d/nnoise.nrrd -k tent -m vc \ -cmap $SCIVIS/cmap/thresh-cmap.txt -sz 600 520 -c 7.5 6.5 -h 13 -o tmp.png ./rmapr iso -i $SCIVIS/data/2d/nnoise.nrrd -v 0.5 -o seg.txt ./rmapr eps -i tmp.png -c seg.txt -scl 1.3 -o tmp.eps; open tmp.eps- Having fun with the Italy dataset again:
./rmapr cmrs -i $SCIVIS/cmap/diverg-cmap.txt -mm -2000 2000 -o map.txt ./rmapr psamp -i $SCIVIS/data/2d/italy.nrrd -cmap map.txt -m vcs \ -l -1 1 1 -ze 7 -sh 0.5 -c 0 0 -h 1000000 -k bspln3 -sz -sz 825 1100 -o tmp.png; open tmp.png rm -f seg??.txt isos=(100 700 1400 2000) for I in $(seq 0 1 3); do ./rmapr iso -i $SCIVIS/data/2d/italy.nrrd -v ${isos[$I]} -c 0 0 -h 1000000 -r 0.75 -o seg+$I.txt ./rmapr iso -i $SCIVIS/data/2d/italy.nrrd -v -${isos[$I]} -c 0 0 -h 1000000 -r 0.75 -o seg-$I.txt done ./rmapr iso -i $SCIVIS/data/2d/italy.nrrd -v 0 -c 0 0 -h 1000000 -r 0.75 -o seg00.txt ./rmapr eps -i tmp.png -c seg??.txt -th 0.3 -o tmp.eps; open tmp.epsGrading
The grade will be based on correctness (80%) and style (20%). If your code does not compile cleanly, with the Makefile provided, you will get a ZERO for correctness. Correctness will be evaluated with examples such as those above, and maybe some additional ones to test corner cases. For the style points, keep in mind:
- You should try to avoid needlessly recomputing things with every call to mprConvoEval. This is why you're allowed to add variables and state to the mprContext. Resources allocated in mprContextNew should be cleaned up in mprContextNix.
- If your implementation mptConvoEval and mprPictureSample runs markedly slower than the reference implementation, you may lose some points. The rate (in kilohertz or kHz) of the computation is printed by mapr psamp.