Assigned: Friday, Jan 11, 2002
Due: Thursday, Jan 17, 2002 (by 11:59pm)
You will implement a simple window-based image filtering tool, called imgflt. This tool allows you to load an image and apply any 5x5 cross-correlation filter to it. The filter may be applied to the entire image, or "brushed" on to any selected region.
You will be given a working skeleton program, which provides the user interface that you'll need for this program. Specifically, it allows you to load in an image and specify any 5x5 filter by typing in the filter coefficients, a scale factor which multiplies each filter coefficient, and an offset which is added to the pixel before displaying. The interface supports loading and saving of both images and filters. You can also change the brush size. For a complete description of which mouse button does what, run the program and select the "Help" menu item.
We have provided a sample solution executable and test images. Try this out to see how your program should run. Pay special attention to the behavior of the brush. It should apply the filter to each pixel only once, even if the brush is moved over that pixel multiple times. This may be accomplished by copying the image to a temporary image which is the one currently displayed. Filtering operations affect the temporary image but leave the original image intact. When you click "Accept" in the filter window, the changes are committed to the original image.
You will write the code to do cross-correlation filtering. First, however, you should check out the online documentation for FLTK 1.0, a cross-platform user interface and graphics API that we'll be using in this class.
You can download the skeleton files. The code is compiled in Visual C++ 6.0, and organized by the workspace file imgflt.dsw. All the source files (.h/.cpp) are in the subdirectory src. There are 21 files total, but many are just user interface files that are automatically generated by fluid, the FLTK user interface building tool. Here is a description of what's in there:
unsigned char *imgBuf;
imgBuf points to a memory of size [3*W*H], which saves an image of
W columns and H rows sequentially from left to right and from top to bottom.
Each pixel has three color R,G,B. The arrangement of the buffer is a sequence of
R,G,B colors. The RGB of top left pixel occupies the first 3 bytes in imgBuf,
and the top row of W pixels occupy the first 3*W bytes, and so on.
For example, the pixel at column i and row j is :
imgBuf[3*(j*W+i)+0],imgBuf[3*(j*W+i)+1],imgBuf[3*(j*W+i)+2].
double *origImg,*curImg;
origImg and curImg save two images of the same size as imgBuf does. The difference is
they two represent colors in floating point type for filtering while imgBuf uses
unsigned char for displaying. origImg initially is loaded with an original
image. Any following filter operations will cache the results in curImg for preview
purpose. If the operations are accepted (by a button in Filter Design Panel), the content
in curImg is copied to origImg. If the operations are cancelled, the content in origImg
is copied to curImg. imgBuf is kept consistent with curImg, up to rounding errors after
clampping to [0,255], for displaying purpose.
unsigned char *brushSelection;
brushSeletion is a buffer of size W*H. It is used to indicate where the filter has been
applied in brush mode. For example, if the filter has been applied to
pixel (col,row), then
brushSelection[row*imgWidth+col] = 1;
Otherwise,
brushSelection[row*imgWidth+col] = 0.
Square Brush
When the mouse moves to position (col,row), you should apply filter to
all the pixels (i,j) inside the square around the mouse, defined as:
|i-col| < brushSize AND |j-row| < brushSize.
Round Brush
When the mouse moves to position (col,row), you should apply filter to
all the pixels (i,j) inside the cirle around the mouse, of radius
brushSize, defined as:
(i-col)*(i-col)+(j-row)*(j-row) < brushSize*brushSize.
Brush Opacity
brushOpacity is a floating number between 0 and 1, which is used to
attenuate the pixel colors that have been filtered in brush mode.
For example, if pixel (i,j) has color (R,G,B) and is filtered in brush
mode, e.g., brushSelection[j*imgWidth+i] = 1, then pixel (i,j) will
be drawn as (R*brushOpacity, G*brushOpacity, B*brushOpacity) instead of
its original color (R,G,B).
If you look at the ImageLib files, images can contain tags that control how border padding is handled (zero, replicate, reflect). You only need to support one of these options and can hard-code it into your program.
We're not expecting anything fancy beyond the basic requirements on this project, although you're welcome to add to it if you'd like. We probably won't be giving out extra credit on this project since it's meant to help people get up to speed quickly with the tools and data structures.
Last modified on January 09, 2002