Category Archives: School

Details about my Computer Science Masters Degree

COMP 770 Program 4: 3D Rasterizer

Download the source (c++ w/ XCode project): Program4.tar.gz
Download the binary (Intel Mac OS X): rasterizer.gz

I know this is a naive thing to say type, but after finishing this program I kind of feel like I just implemented OpenGL minus shaders. :) My approach was to get the scene parsing implemented first and then to get the GL Preview feature working. This allowed me to very quickly setup my light and camera and then to see my goal. Then I started in on my raster pipeline.

Features

Here’s a quick list of the features for my Raster Pipeline:

  • Moveable camera
  • Moveable light
  • Orthographic Projection
  • Perspective Projection
  • Per-Vertex Color
  • Wireframe
  • Flat Shading
  • Gouraud Shading
  • Phong Shading
  • Use full Phong lighting with light intensity falloff
  • Configurable (on/off) backface culling
  • Configurable (on/off) cheap clipping
  • Efficient span-based triangle fill
  • z-buffer with epsilon for z-fighing resolution
  • Timing instrumentation
  • PNG output

And here are the features support in the OpenGL Preview mode:

  • Moveable camera
  • Moveable light
  • Orthographic Projection
  • Perspective Projection
  • Per-Vertex Color
  • Wireframe
  • Flat Shading
  • Smooth (Gouraud?) Shading

Shading

After doing two raytracing assignments, I really doubted that rasterizing would hold a candle in terms of aesthetics. I was stunned when I saw how good the OpenGL preview looked, so I really wanted to dive into shading. I ended up implementing wireframes, flat shading, Gouraud shading and Phong shading.

Challenges

I then started in on my own raster pipeline. As I stumbled through a myriad of problems with my transformations. In particular, the projection transformations were troublesome. I tried to implement them in a way similar to the class notes, but I was getting the results that I was looking for…or any results. I kept segfaulting. I turned to the text, and found that they did a great job explaining both orthographic and projection transformations.

Clamping and normals were also a problem for me. Interestingly enough, once you fix one clamping or normal bug, you tend to clamp and normalize everything. The clamping problem was worst with my color calculations. Specular highlights produce some very illuminated pixels. I ended up bleeding past 1.0 on several of the channels which caused several rainbow effects. Additionally, when I was calculating barycentric coordinate, floating pointer errors led to scenarios where the coordinates were being returned beyond [0.0,1.0]. Normally this would mean that the point was off of the triangle, but I was attempting to calculate for pixels that were known to be on the triangle.

Normals were by far the most difficult problem. At least it was the toughest one I had to solve. My specular highlights were causing a grid pattern along the edges of triangles. I fought it for two days. My problem resulted from normals interpolated between to vertices on the edges. The were not unit length, and so they increased the effect of the specular highlights when I calculated the dot product with the half viewing vector. Normalizing these fixed the problem.

Optimizations

Backface culling was a really straight-forward optimization to make. To implement it, I added a check right before the viewing and projection transformations. The check involved computing the dot product of each of the normals with the viewing vector. If none of those normals were visible, then the entire triangle is back facing and was culled. It yielded a significant speedup on Andrew’s dragon model.

rasterizer –projection persp -0.1 0.1 -0.0 0.2 3.0 7.0 –camera 0 0 5 0 1 0 –light 0.1 0.1 0.1 –nocull scenes/dragon.txt
Render scene: 1287.702000 ms

versus

rasterizer –projection persp -0.1 0.1 -0.0 0.2 3.0 7.0 –camera 0 0 5 0 1 0 –light 0.1 0.1 0.1 scenes/dragon.txt
Render scene: 708.403000 ms

I really wanted to implement full clipping, but I found out that “cheap clipping” is pretty effective by itself. The first step is to add a check if a pixel is in the viewport before calculating the color for it. Calculating color is pretty expensive, so this eliminated a lot of cost. Then next step was to use Cohen-Sutherland clipping to determine when a line or triangle was completely outside of the viewport. I didn’t do a thorough test either. I did the simple bit-wise and operation on the bit codes for each point and rejected the triangle if it was not zero. This means that some of the corner cases were missed.

By cheating like this, I was able to avoid a lot of triangles without having to implement the clipping of individual triangles into separate polygons. This meant that I was still rasterizing parts of triangle that were outside of the viewport, but at least with my check above I wasn’t calculating the color for them. The results were rather satisfactory, especially compared to the cost of implementing it.

rasterizer –camera 0 0 5 0 1 0 –projection persp -0.1 0.1 -0.1 0.1 3.0 7.0 //zoom_in –noclip scenes/beethoven.txt
Render scene: 414.369000 ms

was reduced to

rasterizer –camera 0 0 5 0 1 0 –projection persp -0.1 0.1 -0.1 0.1 3.0 7.0 //zoom_in –output img/beethven_clipped.png scenes/beethoven.txt
Render scene: 310.444000 ms

Although a span-based triangle fill was pointed out as an opportunity for extra credit, it was really the most straightforward way to implement this for triangles, since they’re convex. At one point in my career, I did a lot of 2D raster graphics work for J2ME cellphones. Most of our displays were optimized to send data to the display in rows. So I attacked this problem the same way. I found the top most pixel. I then started drawing each leg using the midpoint line algorithm. Each time I placed a pixel which changed y, I added it to an edge list. When I reached the end of a leg, I switched to the third segment…unless that leg was already horizontal. I then went back and drew horizontal lines from one edge map to the other. Since this was the only triangle fill algorithm I used, I didn’t get any timing numbers for comparison.

The use of a Z-Buffer to determine the rendering order is so genius in its simplicity, that I didn’t even consider any other ways to implement it. So this is another scenario where I didn’t try to implement another method for comparison. However, I was able to throw in a small improvement that resolve the z-fighting example that I threw at it. When determining when to paint over another pixel, I checked that the new pixel was closer to the camera by a margin, epsilon. I set epsilon to 0.000001. It resolve my test model without causing any visible changes to the other models. My testing certainly wasn’t extensive, and so I’m sure that it would fail on scenarios where a camera with a very narrow FOV caused massive magnification. Perhaps in that situation, I could use a dynamic epsilon that is calculated based on the camera’s FOV.

Remaining Images

Here are the remaining rendering of the models provided, including Andrew’s dragon model from the Stanford 3D Scan Repository.

COMP 770 Program 3: Ray Tracing Part 2

Download Project Source/Scenes/Mac-Binaries: Program3.tar.gz

Overview

For the first part of the Ray Tracing project, I added a quite a few extra features. One of those extra features was the recursive calculations of Specular Reflection, Dielectric Reflection, and Dielectric Transmission. I considered myself pretty lucky, considering that this feature is one of the two features that we were required to add for this second part. However, I wasn’t quite in the clear. Lets just say that I had a looser understanding of ray tracing than I thought.

New Features

Many of the features of my Ray Tracer were implemented in the first part. That list can be seen on that project post. The following are new features:

KD Tree

  • Mid-Axis Partitioning
  • SAH Partitioning
  • Cost-Based Termination of leaf nodes for both
  • Recursive KD Tree Traversal
  • KD Tree Printing in Debug Builds

Miscellaneous

  • Fixed Ray Tracing bugs
  • Dramatically Improved Ray Tracing Performance
  • Interactive Ray Shooting in Debug Builds

Default Configuration

When you launch my Ray Tracer, the following are the defaults that are used unless you specify otherwise.

  • Dimensions: 500×500
  • Sampling: 4 x 4 Adaptive Jittered Supersampling
  • Ray Casting: Blinn-Phong Lighting with an Ambient Factor
  • Ray Tracing: Specular Reflections, Dielectric Reflections, and Dielectric Transmission supported through recursion terminated based on a contribution threshold
  • Multi-Processing: Uses multiple CPU cores through OpenMP
  • KD Tree: Built using SAH cost analysis to determine best split and when to terminate branches

Ray Tracing

The optics involved with refraction are not very intuitive to me. Initially, I thought that an image seen through a glass sphere would be reduced, but instead it’s actually magnified. I had a rather serious bug when calculating refraction. I was refracting my rays with a dot product of the ray and surface normal with the wrong sign. Correcting that made a tremendous difference.

Once I started rendering the scene with 16 spheres, I started to realize that I had some serious additive errors on calculations of the transmissive component. There were two reasons for this. Firstly, I was calculating the reflective and transmissive components inside of the loop that calculated the phong shading for each light source. Fixing this corrected several of the bright spots, and it led to a signficant speed improvement.

Secondly, I was calculating the phong shading and reflective components for for illumination points inside of a sphere. This scenario arose whenever I was calculating the color for a refracted ray transmitted through a sphere. The refracted ray would intersect the other side of the sphere on the inside, and at that point I should have only been calculating the transmissive component. Making this change also led to a dramatic speedup.

KD Tree

My KD Tree was actually a deceleration structure for much of the project. I had several issues when creating the tree, as well as the traversal. I started by creating a KD Tree that simply divided the space at the midpoint of the split axis.

The first issue that I had, was that I was creating a new bounding box around the primitives in each of the newly split subspaces. This is very problematic, because it created overlapping spaces whenever I had the occurrence of a single primitive shared between both spaces. Once drew a clear delineation between space partitioning and bounding volume hierarchies, I was able to clean up my KD Tree and I saw fewer artifacts.

My next hurdle was understanding how to traverse the tree correctly and to fix the remaining artifacts. Initially, while I was trying to learn how KD Trees work, I was only considering an algorithm where the ray always intersected the outermost bounding box. This was fundamentally flawed for several reasons. First off, the ground sphere made the bounding box really large, but it didn’t create to many artifacts for me. The second major instance of rays originating inside of the outermost bounding box where theway used when calculating shadows, reflections, and transmissions. Through some digging, I found a very helpful post that illustrated the different cases that have to be handled when traversing a KD Tree.

His diagrams were very helpful. They were so implanted in my brain that I ended up adopting his algorithm completely from the code that he posted. He still missed two cases, that I initially had some trouble finding. I ended up implementing a special, interactive debug feature that would allow me to use the mouse to point at a pixel in the viewing window and result in the rendering of that single view ray. I would use it by rendering the entire scene, setting a breakpoint, then clicking on the pixel that I needed to test. This was invaluable in finding the remaining artifacts as well as some ray tracing issues.

At this point, my KD Tree still proved to be more of a deceleration structure. I fired up a profiler, and found a number of slowdowns related to mallocs when operating on C++ vectors. I reduced my use of vectors and passed them by reference throughout the KD Tree traversal. This brought significant gains, but my KD Tree was still slower.

The next step was to implement a smarter space partitioning scheme based on comparing the Surface Area Heuristic of each new subspace. This cost calculation was also critical to determining when to make a leaf node. I had a few bugs that led to excessive node duplication. Once I sorted those out, I finally got the gains I was hoping for. My resulting tree for the more complicated scene was 11 nodes deep, and contained several empty leaf nodes.

16 Sphere Scene Without a KD Tree

Size: 500x500
Total Primitive Intersection Checks: 223084940
Total Node Traversals: 0
Total Render: 29.763917 seconds

16 Sphere Scene With KD Tree

Size: 500x500
Build KD Tree: 0.000580 seconds
Total Primitive Intersection Checks: 55731412
Total Node Traversals: 161224507
Total Render: 24.878577 seconds

I reduced the number of sphere intersections from 225m to 161m while only adding 55m node traversals. The time savings wasn’t as dramatic as I had hoped, likely because my algorithm still used functional recursion instead of maintaining a smaller stack inside of a loop. For my final project, I’m likely going to go stackless altogether since I’ll be using the GPU too.

However, I really started to notice gains when I upped the complexity of the scene. I created a model of 140 reflective spheres arranged into a tightly-packed pyramid.

140 Sphere Scene Without KD Tree

Size: 500x500
Total Primitive Intersection Checks: 1016735174
Total Node Traversals: 0
Total Render: 103.413575 seconds

140 Sphere Scene With KD Tree

Size: 500x500
Build KD Tree: 0.091852 seconds
Total Primitive Intersection Checks: 230486448
Total Node Traversals: 161218665
Total Render: 38.800175 seconds

Sample Images

COMP 770 Program 2: Ray Tracing Part 1

Download Project Source/Scenes/Mac-Binaries: Program2.tar.gz

Overview

I’ve read about ray tracing a few times in the past, but this assignment gave me a dramatically new perspective on the topic. Two things really struck me about ray tracing. First, what I understood to be ray tracing was actually just ray casting. I didn’t know this while I was implementing the diffuse shaders (pure Lambertian, Blinn-Phong, and Blinn-Phong with Ambience), and so I was rather impressed with the results. However, as soon as I implemented specular reflection via recursion, I started to realize that ray tracing is indeed a much more significant step over ray casting in terms of realism.

My second dramatic realization was just how expensive ray tracing is. Every feature that I added would drive my render times up. And this was compounded by framebuffer resolution, sampling grid size, number of lights, and number of scene primitives. I found myself switching between implementing new features and then going back and implementing various optimizations just to make the render times tolerable.

Features

For part one of this ray tracer program, I used the COMP 575 assignment as a guideline on features to add beyond the minimum in the COMP 770 assignment. I kept going, adding feature after feature, unaware of whether or not these “extra features” would actually be required for the second part of the assignment or not.

Basic

  • Resizable View Rect Dimensions
  • Fully Configurable Camera (position, rotate, FOV)
  • Multiple, Colored Light Support
  • Configurable Background Color
  • Output to PNG
  • Supports both Ray Casting and Ray Tracing
  • Specular Reflection
  • Dielectric Reflection and Transmission w/ Refraction

Shaders

  • Lambertian
  • Blinn-Phong
  • Blinn-Phong with Ambient

Super Sampling

  • Configurable Sample Count for Regular, Jittered, and Adaptive
  • Basic
  • Regular
  • Jittered

Optimizations

  • Multi-Processing Support with OpenMP
  • Simplified Scene Intersection Calculations with Normalized Direction Vectors
  • Tracks recursive contribution of color calculations for early recursion termination
  • Adaptive [Jittered] Sampling

Miscellaneous

  • Timing Instrumentation
  • Can build without OpenGL, OpenMP, and libpng for benchmarking on embedded systems

Building and Usage

I’ve provided a Makefile with the following targets. It has been tested on Mac OSX, Linux (Ubuntu) and Android for ARM.

NOTICE: By default, I build on a system with OpenGL, OpenMP (libgomp), and libpng. If you don’t have those on your system, then use the NO_GL=1, NO_OMP=1, and NO_PNG=1 settings when running make.

Build Targets/Options

  • make – Builds release.
  • make debug – Builds debug.
  • make clean – Cleans src directory and removes objdir directories.
  • make NO_OMP=1 – Won’t attempt to compile using OpenMP. Handy if the system doesn’t have support. Can be used with other NO_*.
  • make NO_PNG=1 – Won’t attempt to compile using libpng. Handy if the system doesn’t have support. Can be used with other NO_*.
  • make NO_GL=1 – Won’t attempt to compile using OpenGL. Handy if the system doesn’t have support. Can be used with other NO_*.

Usage

Usage: raytracer [-shader ] [-sampling ] [-samples ] [-background <0xRRGGBBAA>] [-window  ] [-timing] [-noparallel] [-norecursion] [-nodisplay] [-output ] 

  -shader 
       Sets the shader used. Each one builds upon the previous shader. Default = reflective
  -sampling 
       Chooses which sampling method to use. Default = adaptive
  -samples 
       Specifies n x n grid of samples to collect. Ignored for basic sampling. Default = 5
  -background <0xRRGGBBAA>
       Sets the background color. Default = 0x000000ff
  -window  
       Sets the window size to the specified width and height. Default = 500 x 500
  -timing
       This switch turns on timing output on the console. Default = off
  -noparallel
       This switch turns off multiprocessing. Default = on
  -norecursion
       This switch turns off recursive ray tracing resulting in simple ray casting. Default = on
  -nodisplay
       This switch turns the output to the display. Default = on
  -output 
       This switch causes the ray tracer to output a png image of the renderer scene.

Image Results

spheres3.xml

Once I started working on support for dielectrics, I wanted to create a reasonably familiar scene so that I could interpret the results better. I placed a large, mostly transparent, smoke-gray sphere in front of the camera. The ground sphere is still somewhat reflective, but the two colored spheres in the background are non-reflective. When viewing this scene, it’s best to use a white background (-background 0xffffffff) in order to see the distortion at the perimeter of the sphere.

<scene>
	
	<!-- camera at (0,2,-12) pointed towards the origin -->
	<camera x="0.0" y="2.0" z="-8.0" fov="90.0"
			lookAtX="0.0" lookAtY="2.0" lookAtZ="0.0"
			upX="0.0" upY="1.0" upZ="0.0"/>
	
	<!-- smoked sphere -->
	<sphere radius="2.0" x="0.0" y="1.75" z="-3.0">
		<color r="0.3" g="0.3" b="0.3" a="0.3"/>
		<material reflectance="0.0" refraction="1.5" phongExponent="0.0"/>
	</sphere>
	
	<!-- blue sphere -->
	<sphere radius="1.25" x="-4.0" y="2.0" z="2.0">
		<color r="0.0" g="0.0" b="1.0" a="1.0"/>
		<material reflectance="0.0" refraction="1.0" phongExponent="16.0"/>
	</sphere>
	
	<!-- green sphere -->
	<sphere radius="1.25" x="4.0" y="2.0" z="2.0">
		<color r="0.0" g="1.0" b="0.0" a="1.0"/>
		<material reflectance="0.0" refraction="1.0" phongExponent="16.0"/>
	</sphere>
	
	<!-- white overhead light -->
	<light x="0.0" y="5.0" z="0.0" ambient="0.25">
		<color r="1.0" g="1.0" b="1.0" a="1.0"/>
	</light>
	
	<!-- "ground" sphere -->
	<sphere radius="50.0" x="0.0" y="-50.0" z="0.0">
		<color r="0.75" g="0.75" b="0.75" a="1.0"/>
		<material reflectance="0.3" refraction="1.5" phongExponent="32.0"/>
	</sphere>
	
</scene>

Optimizations

Of the various optimizations that I implemented, none provided the immediate results that the parallelism through OpenMP. I was definitely embarrassed that I didn’t think of it before the COMP 575 professor mentioned it. I fully anticipated that I would have to refactor my code to be multi-threaded. I was pleasantly surprised to find OpenMP. I had used a similar compiler extension on some Cell Processor development years ago, but OpenMP is much further along in terms of ease-of-use and compiler support. I was so thrilled when I discovered it, that I blogged about it here. With one line in my Makefile and two lines of code, I gained a nearly 75% increase.

Development Challenges

  • Viewing Rect
  • Floating Point Error When Intersecting Light Ray
  • Transparency + Ray Casting = Does Not Compute
  • Floating Point Error Part Deux

Overall, development went really smooth on this project. I was definitely making a lot of hand-gestures while trying to visualize where my cross products would be aiming as I was trying to generate the viewing rect. I didn’t know how to correlate the up vector of the camera with the vector from the camera position to the lookAt point, especially when they weren’t perpendicular. Finally I decided to use the up vector and assume that the camera was looking straight forward, along it’s z axis. Without this assumption, I felt like I would have to be dealing with an oblique projection, which I wasn’t ready for.

I struggled a little when I was trying to calculate intersections with the scene for the light vector from the visible point back to the light source. Initially I tried to throw out intersections with the primitive that the visible point was on. Of course, that didn’t yield results, so I finally settled on throwing out all intersections that were closer to the visible point than a particular threshold, lambda. The next lecture, the same strategy was mentioned as a solution to that problem.

The next significant problem that I phased was how to deal with transparency. Again, I was unlucky enough to be a little early to implement this feature. Two lectures later, we discussed ray tracing vs. ray casting. Recursive ray tracing, makes reflection and transmission with refraction nearly trivial. For a while, I was a little confused between specular reflection and dielectric reflection, but I finally differentiated the two and accepted the fact that an object can be a dielectric and also have specular reflective material properties. The last part of ray tracing that was really challenging, was the calculation of the “a” constant when determining the filtering of light when it is transmitted through a dielectric. The textbook described how the Beer-Lambert Law determined how much light is transmitted, but they said that a constant for each color channel is chosen and that the natural logs from the formula are rolled into that. Furthermore, they mentioned that developer’s often tune this parameter by eye. I settled on a calculation for “a” that took each color channel of the intersected primitive and multiplied it with (1 – alpha) for that color. Visually, I found the results to be satisfactory.

The last hurdle that I faced was again related to detecting intersections that are too close to the visible point. This time, the rays in question were the transmitted/refracted rays. I was still using the threshold from before to eliminate intersections that were too close to the ray origin. However, the threshold value that I was using was very small. I found that several of the refraction calculations involved a lot of floating point math errors that had built up through the multiple calculations and amplified by the recursion. I just relaxed the threshold and the noise was eliminated.

Finding OpenMP – Best Day EVAR, This Week

So I’ve been working on this Ray Tracer for class. It’s rather primitive, but it’s starting to slow to a crawl as I add features (especially multi-sampling). I’m still only rendering three spheres, but a full screen render at 1920×1066 was taking 13+ seconds. The professor gave us a few tips today on speeding up the algorithms involved. I felt pretty dumb for not thinking of the most obvious recommendation that he made. And wouldn’t you know it, it turned out stunning results.

Only spheres so far, but check out that Blinn-Phong w/ Ambient Shading

OpenMP – Multi-Processing Made Real Easy

Of course, Ray Tracing is ridiculously parallel. You have to do the same calculations on every ray. That’s at least one ray per pixel in your viewing plane. Ten minutes of searching the internet for multi-processing methodologies in C/C++ delivered me to the OpenMP Wikipedia Page. It’s a very friendly introduction. I’ve used something lightly similar years ago for IBM’s Cell processor, but it wasn’t nearly as easy as OpenMP.

I doubted that my gcc compiler on my MacBook Pro supported OpenMP, but digging through the OpenMP compiler page revealed that there has been OpenMP 2.5 support since gcc 4.2 and I’m running gcc 4.2.1.

There’s a note on the same OpenMP compiler page that says “Compile with -fopenmp”. At first I thought that I’d have to rebuild gcc with that flag. Dummy. All I need to do was to use that feature flag when compiling with my version of gcc.

So here it is. My three lines of code.

Adding -fopenmp to Makefile

CCFLAGS+=-fopenmp

Including omp.h in RayTracer.cpp

#include

Putting a #pragma above my outermost for loop

#pragma omp parallel for

Results

Before:

  • Size: 1920×1066 – Render time: 13.178630 seconds

After:

  • Size: 1920×1066 – Render time: 7.544398 seconds

Professionally, I work on a performance and optimization team in the embedded space. Usually when I see such gains with just a handful of lines of code, it’s because I finally remembered that I was building DEBUG.

COMP 770 Program 1: Image Processing

Download Entire Project: Image_cpp.tar.gz
Download image.cpp only: image.cpp.tar.gz
Download extra sample image results: lena.tar.gz

Overview

This assignment was a blast. It basically required us to implement just about every worthwhile image processing filter out there. Here’s a quick list of them:

  • Brighten
  • Add Random Noise
  • Crop
  • Extract Channel
  • Adjust Contrast
  • Sharpen
  • Blur
  • Quantize
  • Dither (Random, Ordered, Floyd-Steinberg)
  • Scale
  • Rotate
  • Fun (Swirl)
  • Nonphotorealism (Toon/Comic Shading)

A skeleton of the project was provided with helpful WBMP code as well as classes for Image and Pixel. The Image::Image (const Image& src) was busted, but other than that everything worked perfectly. For reference, here’s my modifications to the copy contructor:

Image::Image (const Image& src)
{
  
  bmpImg = new BMP();
	
  width           = src.width;
  height          = src.height;
  num_pixels      = width * height;
  sampling_method = src.sampling_method;
  
  if (!bmpImg->SetSize(width, height)){
    printf("Error allocating image.");
    exit(-1);
  }
	
  pixels = new Pixel[num_pixels];
  memcpy(pixels, src.pixels, num_pixels * sizeof(Pixel));

  assert(pixels != NULL);
}

Getting The Code

The various image filters were implemented as methods of the Image class and can be viewed in the image.cpp file. Further details of the implementation are explained in the comments.

Download Entire Project: Image_cpp.tar.gz
Download image.cpp only: image.cpp.tar.gz

Building

The project should build on any system with c++ compiler, stdlibc++ library, and make. I did my development on Linux and Mac OSX. I don’t anticipate any problems building in windows, but please let me know if it does.

Untar the project it in a convenient directory and run make to build:

$ tar -xzf Image_cpp.tar.gz
$ cd Image_cpp
$ make

The debug and clean targets work as well:

$ make debug
$ make clean

Run the program with no parameters to get usage:

$ objdir-release/image
Usage: image -input  [-option [arg ...] ...] -output 
-help
-input 
-output 
-noise 
-brightness 
-contrast 
-saturation 
-crop    
-extractChannel 
-quantize 
-randomDither 
-blur 
-sharpen 
-edgeDetect
-orderedDither 
-FloydSteinbergDither 
-scale  
-rotate 
-fun
-sampling 
-toon

Sample Images
The following are screen shots of the results of the various image processing filters. The command lines that were used are displayed as captions beneath the images. You can read more details about how they work after the gallery.

Noise, Brightness, Contrast, Saturation
This group of image filters all use interpolation at their core. Specifically:

  • Noise – Interpolation with an image of random noise
  • Brightness – Interpolation with a black image
  • Contrast – Interpolation with constant gray image with luminance equal to the average luminance of the source image
  • Saturation – Interpolation with a grayscale version of the source image

Crop

Cropping is a simple blit of the specified pixel region no a new image with the region’s dimensions.

Extract Channel

The specified channel was extracted by setting the other channels to zero for each pixel in the source image.

Quantize, Random Dither, Ordered Dither, Floyd-Steinberg Dither

This groups of image filters reduces the bits per channel to the number specified by the input parameter. The Quantize algoritm is the simplest, as it just reduces each channel of each pixel. This produces dramatic Intensity Quantization errors.

Random Dithering breaks up the color boundaries in the image by adding noise to the source image first. It isn’t simply added though; instead the source image is interpolated with a random noise image. When the resulting image is Quantized the color boundaries look dramatically better, but the introduced noise negatively affects the image quality.

Ordered Dithering improves the color boundaries by moving the rounding errors when choosing one pixel over the next. Instead of simply rounding, the most significant of the dropped bits is compared to a value in a bayer matrix chosen based on the pixel’s coordinates. The pixel’s color is rounded up or down if the error is greater or lesser than that error. More details can be found in this Wikipedia article. This produces visual quality much higher than random dithering, but a noticeable repeating pattern emerges in the image based on the size of the matrix used.

Floyd-Steinberg Dithering deals with the rounding errors differently. Portions of the error are distributed, through additions/subtractions, to the pixels around the pixel being rounded. The resulting images shows dithering quality better than ordered dithering without any repeating patterns.

Scale, Rotate, and Fun (Swirl)

These image processing filters use transformation to move the pixels from the source image to new coordinates in the destination image. Instead of using calculations that transform the source pixels to the destination pixels, the reverse calculations are used. This is particularly important when scaling to a larger dimension, for instance.

The calculations in these reverse transformations often result in real numbers instead of discrete coordinates in the source image. Therefore the image needs to be resampled in order to approximate what the value should be at the given real coordinates. Point Sampling finds the nearest pixel and uses that value. It produces heavily aliasing in the destination image. Bilinear Sampling interpolates between the four nearest pixels based on the the real coordinates distance from those pixels. Gaussian Sampling uses a gaussian filter, producing a mild blurring effect that can be controlled with the right radius.

Blur/ Sharpen

Blur uses a Gaussian filter. I implemented it using a one-dimensional kernel, taking advantage of the separability of the Gaussian filter. The size of the kernel is passed as the parameter on the command line. The size is radius * 2 of the Gaussian curve used to generate the real values in the kernel. I calculated the optimal standard deviation for the equation so that the blurring effect would grow as the radius grew.

Sharpening removes the blurriness of a source image by extrapolating the source image from a blurred version of the same image.

Edge Detect

Edge Detect works similar to the Gaussian filter, but it uses a specific edge detection kernel. I implemented it with a two-dimensional kernel because I wasn’t sure if it was separable and it wasn’t too costly to implement due to the small size of the kernel (3×3).

Toon

Perhaps inspired by all of those “Comic book” yourself applications out there, I attempted to create a “Toon” filter. I built upon the image filters created already and added an alpha blender. I started the process by creating the “color layer”. First the image was saturated and brightened a little. Then it was quantized.

The “ink layer” is built by edge detecting the color layer and then desaturating completely. Then each pixel of the ink layer is analyzed. If its near white, then it is made completely white (for debugging) and completely transparent. The other pixels make up the ink, and so they are made completely black and opaque.

Finally the ink layer is composited over the color layer and the results is blurred a little for effect.

MAMP – LAMP for Your Mac

MAMP does more than just take the L out of LAMP. MAMP is a single package that include Apache w/ PHP and MySQL. A professor recently suggested something called NetServer for Windows, but it left the Mac guys out in the cold. Luckily, MAMP is much cooler.

Both of these packages include decent web interfaces for checking vital stats of the server and phpMyAdmin for configuring our MySQL server. However, MAMP makes use of Expose by creating a simple little widget that you can use to bring the servers up and down.

As far as features, NetServer is a clear winner. It includes a Mail server and an FTP server. This is fine for my development purposes, as MAMP is not intended to host sites. Actually both packages leave the database wide open, and so they probably shouldn’t be used for public purposes unless you tighten up the admin password.

technorati tags:, , ,

Blogged with Flock

Project Two: Portability

I’m putting the finishing touches on project two. I’ve beautified the code…as much as I’m going to. Sorry, Professor, if it’s a pain to read/grade. The last thing is to remove elements of non-portability. I’ve got a couple of places that use paths specific to my server. I’ve just about cleaned them up using functions like:

  • dirname()
  • basepath()

I’ll be uploading it soon, we’ll see how well it installs. :)

Update: It installed just fine. Only one hitch, the URLs in the RSS feeds still point to my server. I need to change them to use $_SYSTEM. – Done

Project Two: Managers’ Dashboard

I’m finally finished with the managers’ dashboard. I decided to make a single page where the manager could get critical information. It contains the following sections:

  • Outstanding Orders
  • Today’s Deliveries
  • Today’s Scans
  • Historical Deliveries

The first two and the last section display a expandable list of tracking numbers. Clicking on the tracking number opens the item and shows the details and scans items. Clicking on those items then shows the details or shows all of the scans. The third item is a simple table that shows a list of the day’s scans.

The Historical Deliveries shows a month’s worth of deliveries. The manager can select a new month or year to view those deliveries.

This was by far the most difficult page, because it was so multi-purpose. I had to come up with some complicated MySQL queries to find the deliveries that were made during a particular month…finding the ones for a day is much simpler. A typical query looks like:

SELECT * FROM package_scans WHERE (DATE_FORMAT(scan_date, “%Y-%c”)=’2006-4′)

Besides complicated queries, I had to build expandable list supports. I sought inspiration from http://wilsonet.com/mythtv/. To accomplish this, I had to write (copy) a simple javascript, add some simple rules to my CSS and then build the list. Building the list consisted of a bunch of PHP code in a new function. Overall, I’m quite pleased with the result.

Project Two: Update

Quizzes are done! I’ve spent tha past few days working on those and cleaning up the sidebar. I wrote a seperate php file for the sidebar that has intelligence for displaying the proper menu items based on the user. I manually added this logic to the seperate pages previously. Now I simply include them.

The only think remaining is my Managers page. I laid out the different information that I want to display.

  • Outstanding Orders – These are orders that haven’t been delivered yet. From this list, the manager will be able to modify the estimated delivery date.
  • Today’s Shipped Orders – A list of the orders that were delivered today.
  • Today’s Scans – A list of the scans for the day, ordered by tracking number.
  • History – This allows a manager to view the orders shipped for the given month with an option to see the scans too.

I decided to take my time on this report section, so maybe I’ll get motivated and do some javascript that allows the user to expand orders to see their details and/or scans. We’ll see.