Detection Algorithm for Night Algorithm Overview A PVC pipe with a vertical stripe of LEDs is installed. The LEDs are positioned directly towards the camera. With a high signal noise ratio, the nighttime water level detection algorithm is quite simple. We define a region of interest (ROI) to speed up the process and avoid false positives. Figure 1 is the flow diagram of the algorithm. The output contains a processed image, the length of the ON pixels (which will be converted to a normalized water level in the driving perl script), and the confidence value – the line fitting error. Figure 2 shows a sample image taken at the dawn be processed. Image + ROI Binarized the image Image cleaning dilation and erosion) Input Image with ROI superimposed Compute the length of ON pixels Fit a line to the ON pixels Compute the line fitting error + Raw LED length Image + Confidence Value Processed Figure 1: Block Diagram for nighttime water level Detection ROI being processed Figure 2: A sample image being processed Implementation Details We use an image IO utility (OpenIL) to load and save images. It is freely from the web at http://www.openil.org. The nighttime detection module is a standalone C program. Its source contains three files, filter.C, filter.h, and night.C. night.C is the driver program that calls image processing functions that are implemented in filter.c. In filter.C, the following image processing functions are implemented. void dilation(int w, int h, unsigned char * src, unsigned char * des) ; Description: Perform image dilation using a 3x3 kernel; Prerequisite: a) the image must be a binary image; each pixel can only have two valid values, either zero or one. B) The src and des pointers cannot be the same. Parameters: w – image width h – image height src – pointer to the source image; des – pointer to the destination image void erosion(int w, int h, unsigned char * src, unsigned char * des) ; Description: Perform image erosion using a 3x3 kernel; Prerequisite: a) the image must be a binary image, each pixel can only have two valid values, either zero or one. B) The src and des pointers cannot be the same. Parameters: w – image width H – image height Src – pointer to the source image Des – pointer to the destination image. void binarize(int w, int h, unsigned char * src, unsigned char * des, float threshold) ; Description: convert a gray scale image to a binary image; Prerequisite: a) the source image must be a gray scale image; Parameters: w – image width H – image height Src – pointer to the source image; Des – pointer to the destination image Threshold – the threshold value, normalized between 0 and 1 void imfeature(int w, int h, unsigned char * src, FEATURES *fea) ; Description: compute some image features. Right now, one only the length of the feature and feature size (in pixels) are computed; Prerequisite: NONE Parameters: w – image width H – image height Src – a pointer to the source image; fea – a pointer to the FEATURES structure (defined below). Only the m_top, m_bottom and m_pixCnt will be filled by this function. struct FEATURES{ int m_top, m_bottom; int m_pixCnt; float m_line[4]; float m_fitError; float m_lineDir; // to be expanded as needed; }; void crop(int w, int h, unsigned char * src, int startx, int starty, int newW, int newH, unsigned char * des); Description: crop the image. Prerequisite: 0 < startx < w, 0< starty < h; b) the image must be a single channel image, i.e. one byte per pixel. Parameters: w – image width H – image height Src – pointer to the source image; Startx, starty – the upper left corner of the cropped image NewW, newh – the dimension of the cropped image Des – pointer to the cropped image void fill(int w, int h, unsigned char * src, int startx, int starty, int newW, int newH, unsigned char * des); Description: update a potion of the image with. Prerequisite: 0 < startx < w, 0< starty < h; b) the image must be a single channel image, i.e. one byte per pixel. Parameters: w – original image width H – original image height Src – pointer to the image that will be replaced; Startx, starty – the upper left corner of the update region NewW, newh – the dimension of the update region; Des – pointer to the pixel array that will replace the region in the original image void MNCC(int w, int h, unsigned char * src, int pw, int ph, unsigned char * pattern, float * result); Description: Perform normalized correlation using a custom-provided template. Prerequisite: the template must have odd sizes in both dimensions; b) the image must be a single channel image, i.e. one byte per pixel; Parameters: w – original image width H – original image height Src – pointer to the image; Pw, ph – the size of the template pattern – pointer to the template’s array of pixels result – pointer to a float array where the correlation score will be stored. Algorithm: The correlation score is computed as r 2 [n IM ( I ) M ] 2 [n I 2 ( I ) 2 ][ n M 2 ( M ) 2 ] where n is the number of pixels in the template, and I is the image and M is the template (model) float * fitLine(int w, int h, unsigned char * src, float * line) ; Description: Fit the ON pixels to a line; Prerequisite: a) the image must be a binary image, each pixel can only have two valid values, either zero or one. B) line must be an array that can at least hold four numbers. Parameters: w – image width H – image height Src – pointer to the source image line – pointer to the array that will hold the line parameters. The line is x t * line[0] line[2] expressed in a parametric form. , where t is a y t * line[1] line[3] parameter. float calDist(int w, int h, unsigned char * src, float * line) ; Description: Fit the ON pixels to a line; Prerequisite: a) the image must be a binary image, each pixel can only have two valid values, either zero or one. Parameters: w – image width H – image height Src – pointer to the source image Line – pointer to the array that holds the line parameters, in the same format as in function fitLine. Algorithm Tuning The only user-defined values are the ROI and the threshold for binarize the image. While the ROI is supplied as a command line parameter, the threshold can only be changed at compile time. It is defined as a constant number in night.C. Usually, the default value (0.72) works fine. The binarization algorithm uses the threshold as a relative number to adjust to various lighting conditions. It is not recommended to change that value. COMP 145 – Project #6 Flood Warning System Team Report April 26, 2001 _________ _________ _________ _________ Kevin Berry Ashes Ganguly Alex Giouzenis Ruigang Yang Introduction The goal of this project is to develop a Flood Warning System that will be deployed near Little Creek, Chapel Hill. The upstream tributaries of Little Creek flood regularly and frequently damage Eastgate Shopping Center and Camelot Village apartments. Our client is Stephen Tell, who already has a camera setup at Little Creek near his house. A picture from that camera is shown below. We develop image analysis software to detect the water level, both in day and night. A web-based archive and report system is also implemented. System administrator can customize various parameters of the detection algorithms, as well as the warning actions when a dangerous water level is detected. It is our belief that we have reached our primary goal – providing a working system that is robust, easy to use, and highly customizable. Technical Lessons Learned Image Analysis The core of the system is the water level detection algorithm. Our client is responsible for the hardware setup; we have to come up with our own detection algorithm. It contains two separate modules for daytime and nighttime respectively. Alex and Ruigang are responsible for the design and implementation of these modules. Stephen installed a piece of plywood, painted with alternating black and white stripes, as you can see in the above picture, high-lighted in the right. The stripes are slanted to prevent ambiguity from reflections (a great idea!). Basically, we will have to solve a pattern-matching problem – detect the slanted stripes from the image. We tested two methods, one is based on statistics of the stripes, such as the slant angle, blob size, etc. The other is based on template matching. It turned out that the first method is quite susceptible to noise and variation in lightings. On the other hand, the template matching method is quite robust. It can detect the stripes even when more than 80% of the plywood is under water. It behaved better than expected when we rotated the image to simulate the rotation of camera. It is able to detect with up to +/-10 degrees of rotations. While template matching is a great method, cares must be taken to select the template. Our experiment shows that a real template cropped from real images behaves much better than a hand-drawn template. In the production code, we use a 13x21 template shown in the right. Reflection was one of our major concerns during the design phase. The stream was flooded once so we actually have some real pictures in which the fiducicals were actually submerged. It turned out that reflections rarely exist. The nighttime detection module is simpler compared to the daytime one. Stephen installed a vertical stripe of LEDs on a PVC pipe (highlighted in the left in the creek picture). The LEDs are pointing directly to the camera. They are the only things visible at night. We convert the image into a binary image and count the number of on pixels. Our only concern is the light refracted under water. It has not been tested because the water level remains lower than the LEDs since the pipe was installed. However, we notice that the water is very muddy during normal time, thus we expect it be even less transparent when flood occurs. (Can some one generate a ray-tracing physical-based muddy water picture for testing? ) In both modules, we use a user-defined region of interest (ROI) to speed up the computation and avoid false positives. The ROI can be quite relaxed to reduce the frequency of “calibration”. The biggest pity for the detection algorithm is the lack of high accuracy, especially in the daytime. The current code sometime misses the lowest block in the plywood, which results to a 5-10 cm fluctuation of water levels. It is a quite difficult task to accurately detect every block given that each block shows up in the camera no bigger than a 10 x 10 pixel blob. Prof. Welch suggested us to use a zoom camera for larger targets. According to our client, it is quite difficult to find a weather-resistant camera with a zoom lens. So we have to make the best use of the existing hardware. We hope the 5-10 cm resolution is good enough for a warning system. The system’s accuracy can certainly be improved by using a bigger target pattern. This is difficult to do because the force of flooding water is quite big. During the semester, the target pattern has to be salvaged several times. A big pattern makes it even more difficult to withstand water. Our client wants to have a confidence measure about the water level reported. We spend quite sometime thinking and discussing what kind of confidence metrics we should use. The metrics we come up are based on some heuristics. We wish we could have some more scientific measures. System Integration System integration was quite tedious. Ashes did a great job binding every piece together into a working system. The use of Perl script is a smart choice. System configurations are all in human-readable plain text. We believe our client will like this all console-based interface. One of the challenges for system integration is to make the output from daytime and nighttime modules consistent. Right now, it is still up to the user to decide a bias and a scale to normalize both outputs. If we had time, we could make it automatic by examining the two outputs in more detail. Lessons Learned from Team work We enjoy a very high level of “democracy” in our group. Typically, we divide a task into several sub tasks, and everyone picks his own task based on preference and capabilities. Thus, every one in the team contributes to the task and learns something from it. Usually it worked quite well. Our final product is truly a group product. Since everyone sticks to a relatively simple and well-defined interface, our system actually worked in the first time we put every piece together. The downside is that some time the finished product or documents lack consistency. Our presentation in class was less than perfect primarily because of that. We have assigned roles for everyone, but they are not carried out quite efficiently. If we were going to do this again, we would probably encourage everyone to pursue his management role more aggressively. It also seems inevitable that a project takes as long as the deadline is not coming. Fortunately, our project reached our goal on time, though everyone must remember the last few hectic days. Conclusion Overall, we believe we have a successful project and a friendly and united team. Everyone learned something from it, both from a technical standpoint and a teamwork standpoint. We enjoyed a high level of “democracy” and discussed outstanding issues openly and frankly. We believe our final product will be used in the real environment. Of course, there are still places for improvement; a number of them are mentioned in previous sections. As a project in general, there are two things we would do differently next time. First, we probably would use some quick prototyping tools such as matlab to first experiment with different detection algorithms, instead of starting from scratch in C. Secondly, we also wish the final hardware setup could be in place earlier to give us more real pictures to test with. It is hard to simulate refractions and reflections in pictures.