An Analysis of Parallelized Motion Masking Using Dual-Mode Single Gaussian Models
Abstract

Motion detection in video is important for a number of applications and fields. In video surveillance, motion detection is an essential accompaniment to activity recognition for early warning systems. Robotics also has much to gain from motion detection and segmentation, particularly in high speed motion tracking for tactile systems. There are a myriad of techniques for detecting and masking motion in an image. Successful systems have used Gaussian Models to discern background from foreground in an image (motion from static imagery). However, particularly in the case of a moving camera or frame of reference, it is necessary to compensate for the motion of the camera when attempting to discern objects moving in the foreground. For example, it is possible to estimate motion of the camera through optical flow methods or temporal differencing and then compensate for this motion in a background subtraction model. We selection a method by Yi et al. using Dual-Mode Single Gaussian Models which does just this. We implement the technique in Intel’s Thread Building Blocks (TBB) and NVIDIA’s CUDA libraries. We then compare parallelization improvements with a theoretical analysis of speedups based on the characteristics of our selected model and attributes of both TBB and CUDA. We make our implementation available to the public.

1 Introduction

Motion detection in video is important for a number of applications and fields. In video surveillance, motion detection is an essential accompaniment to activity recognition for early warning systems [1, 2, 3]. Robotics also has much to gain from motion detection and segmentation, particularly in high speed motion tracking for tactile systems [4]. Others can clearly benefit from such technologies as well. However, motion detection is a hard problem, particularly with a moving camera reference frame, frequent changes in lighting or dynamic backgrounds. As such, many attempts at tackling this problem have been made. Modern research into motion detection and segmentation systems generally falls into 3 categories [5]: background subtraction, temporal differencing, and optical flow.

Background subtraction involves developing a model in a series of images which differentiates the foreground (i.e. motion) from its background. A background model is typically learned on a per-pixel basis. A large portion of background modeling techniques involve keeping a Gaussian Model (GM), or number of candidate GMs, of the background for each pixel. Wren et al. [6] first used Single Gaussian Models (SGM) (with one GM per pixel) for motion detection. The Gaussian model is updated incrementally per some learning rate depending on whether or not a pixel intensity falls within the model’s variance. While this technique provided acceptable results for certain cases, large objects moving through the image or changes in lighting proves to contaminate the model significantly. Further expansion on this involves keeping several candidate Gaussian models indicating possible backgrounds, and a probabilistic mixture is used to differentiate the foreground from the background [7]. This typically yields better results in most cases, but can still run into the same problems as SGMs.

In temporal differencing, the absolute difference of pixel intensities across two or more frames is averaged and a threshold value is used to determine when motion occurs. Component analysis methods are used to cluster differences into regions of motion [8, 3].

Optical flow methods are widely varied, but there are several methods used often as a basis for many complex systems. Two often discussed algorithms are Lucas-Kanade [9] and Horn-Schunk [10]. Lucas-Kanade find the vector transformation of pixels by using least-squares methods to determine the flow for a neighborhood of pixels, while Horn-Schunk used the smoothness constraint in the aperture problem to find optical flow in an image.

Many newer motion detection systems use an ensemble of these methods to accomplish the complex task of motion detection. Particularly in the case of a moving camera or frame of reference, it is necessary to compensate for the motion of the camera when attempting to discern objects moving in the foreground. For example, it is possible to estimate motion of the camera through optical flow methods or temporal differencing and then compensate for this motion in a background subtraction model [11, 12].

We select a method by Yi et al. [11] to detect motion in a series of images (or video) using one of these ensemble methods (though the focus is on background subtraction methods). We use OpenCV for some basic tools (like image parsing and display) as well as some of the motion compensation and preprocessing. We parallelize the motion detection algorithm using Intel’s Thread Building Blocks (TBB) and NVIDIA’s Compute Unified Device Architecture (CUDA) libraries.

Intel’s TBB is a library which provides abstractions for interaction with operating system provided threading libraries (i.e. POSIX) [13, 14]. Rather than dealing with thread synchronization and handling manually, TBB provides an abstraction which allows for the creation of tasks which are allocated to different machine cores by the library run-time engine. TBB also handles CPU-cache transactions to make processing more efficient. We choose TBB because of the abstractions available to simplify parallelization as well as the optimizations of task scheduling and cache management which the library provides. We also considered OpenMP [15], but ran into compilation issues relating to the Mac OS X gcc compiler’s interaction with OpenCV. OpenMP is not supported by older versions of the gcc tool on Mac. However, newer versions of the tool are not compatible with OpenCV on Mac. We then reverted to using TBB as it seemed like a sensible and powerful alternative.

NVIDIA’s CUDA is a platform which gives developers access to low level GPU instruction sets [16]. References to CUDA often refer to the NVIDIA CUDA C/C++ language and libraries which provide high level control over the GPU. It is this that we use for our project. While this can vary between graphics cards, generally the paradigm for CUDA GPUs is as such (based on the Kepler architecture [17], but applies similarly to others like Fermi [18]). The GPU contains several multiprocessors (MPs) each with many CUDA cores (processing units). Processing functions are divided into blocks of threads. Each block is assigned to one MP. Once a block is assigned, another MP cannot access that block or its shared memory. The block of threads is further assigned to CUDA cores by a warp scheduler. A warp is a group of threads which will be scheduled onto CUDA cores in parallel, typically in blocks of 32, but this depends on the warp size of the card. The threads can either fetch from global or shared memory, but shared memory is typically shared only within a block on an MP.

2 Background

2.1 Preprocessing

To improve the accuracy of the motion detection, as in Yi et al., we first pre-process the incoming frame. Two filters are used for this task: a Gaussian filter and a median filter. A Gaussian filter creates a matrix of size with a Gaussian distribution of weights across the matrix. The Gaussian distribution function for a one dimensional vector can be seen in Equation 1 where is the standard deviation, is the mean value and is the distance parameter desired.

(1)

The image can then be convolved with this normal distribution of weights to set a pixel’s value to the summed normal distribution of its neighbors for some given size and sigma value.

In a median filter, a pixel is set to the median value of its neighbors. This preprocessing is done to smooth the edges of motion detection and ensure that fewer per-pixel lighting anomalies are detected.

2.2 Single Gaussian Model

In SGM background subtraction methods, the mean and variance of every pixel in a series of images is kept. They are updated based on a specified learning rate to develop a model for the background of an image. In their method, Yi et al. use a variable learning rate based on the age of the model to place more emphasis on earlier frames. However, the age is capped at 30 to prevent excessive emphasis and ghosting effects222Ghosting is referred to contamination of the background model such that motion is always observed there because a previously stationary object has moved from the background, leaving a ghosting effect.. On each iteration which affects the background model, the mean, variance and age are updated as follows. We take the equations here directly from Yi et al.’s paper. However, it is important to note that while Yi et al. use an average of pixel intensities in a grid of size size , we calculate these on a per pixel basis, and hence, for each grid the size of our Grid is 1:

(2)

The mean of the SGM is updated according to:

(3)

Here, the mean of the background model is updated based on the previous mean and the current pixel intensity. While Yi et al. use to be defined as follows:

(4)

We use a per-pixel model, and thus is equivalent to . Further, the variance is updated according to:

(5)

Here, the variance is updated based on the age, the previous variance, and the absolute difference of the mean and the current pixel intensities. Again, though Yi et al., define:

(6)

We use a per-pixel model, and as such this just becomes . Lastly, the age of the model is updated according to:

(7)

In all of the above, represent the previous values after motion compensation, as will be discussed later. While an SGM may be acceptable for a static background and relatively simple background subtraction tasks, large objects moving through the image sequences can contaminate the background and changes in lighting will result in large errors. To overcome this, Yi et al. propose a Dual-mode SGM model.

2.3 Dual-mode Single Gaussian Model

In the Dual-mode SGM model, an absolute background model and a candidate background model are updated in concert. The absolute model represents the current model used for differentiating foreground from background. The candidate model represents a possible new background after, say, a shift in lighting or camera position. These models are updated as follows. Per pixel, if the squared absolute difference of the absolute model’s mean and the pixel intensity is less than some weighted value of the variance, then the absolute model is updated as per the aforementioned SGM rules. This can be formulated as:

(8)

If the absolute model is not updated, then the candidate model will be updated if it falls within the similarly defined threshold as follows:

(9)

If neither model is updated, the candidate model is reset with the current mean set to the current pixel intensity, the variance set to some initial value (255 for the purposes of our implementation), and the age to 1.

If the age of the candidate model exceeds the age of the absolute model as in:

(10)

the absolute model is set to the candidate model and the candidate model is reset.

2.4 Motion Compensation

The motion compensation described in Yi et al. is as follows. Kanade-Lucas-Tomasi’s (KLT) feature tracking algorithm333KLT is a method of tracking the movement of pixels in an image sequence. In it, features (pixel sequences) are identified which are unique in an image. Methods based on Lucas-Kanade’s optical flow are used to track these pixels through a series of images. Other methods similar to this include SURF [19]. is used to find feature points and the vector shifts of the pixels [9, 20]. RANSAC [21] is then used to create a homography matrix from these vectors. Because in their method, Yi et al. use grid blocks rather than single pixels, they compute the mixture between grid blocks based on this homography matrix. However, because we compute SGMs on a per-pixel basis, we can simply use the homography matrix to map the SGM values to the appropriate pixels based on the overall motion of the image.

3 Methodology

3.1 Serial Implementation

3.1.1 Preprocessing

For Gaussian and median blurring, we use two methods of implementation. First, we use the current OpenCV implementation of both. Second, we implement our own unoptimized methods for both. In the serial Gaussian blur, for each pixel, we multiply a 2D Gaussian kernel (created by the Gaussian equation) by the surrounding pixels. The sum of this is then placed in the current pixel’s position in the updated image. For median blurring, we take the surrounding 8 pixels (though this can be changed, we generally stayed with 8), as well as the current pixel, and use a simple sorting algorithm to order their intensities. The median value is then used as the new value of the pixel. A snippet of the core serial code of these methods can be found in Appendices D and C.

3.1.2 Dual-Mode SGM

As per the aforementioned equations described by Yi et al., we implement the Dual-mode SGM model as a core loop, keeping the age, variance, and mean of the two models as matrices. The core code iterated for each pixel can be seen in Appendix E.

3.1.3 Motion Compensation

We implement motion compensation using OpenCV’s implementation of KLT and RANSAC. We first use the findGoodFeatures function to generate a list of possible points. We then use KLT (by the method calcOpticalFlowPyrLK) to find the movement vectors associated with these points. Finally we feed these vectors into OpenCV’s RANSAC (through the findHomography method). Lastly, we transform the current frame to match the previous frame’s keypoints via this homography matrix to attempt to reduce error from overall camera motion. Snippets of this code can be found in Appendix F. It is important to note that we did not achieve significant improvements from this method, which we will discuss in the results section. Because of the poor results and due to the efficiency of the existing OpenCV implementation and the complexity of the algorithms in comparison with the amount of time available for the project, we determined it to be out of the scope of the project to parallelize motion compensation as well as all other aspects.

3.2 Thread Building Blocks Implementation

Generally, for both the preprocessing parallelization and the Dual-mode SGM parallelization, we separate the inner process functions from the loops iterating over the pixels and formulate them as tasks with the overloaded TBB functions. We specify the number of tasks desired using the OpenCV TBB extension (cv::parallel_for method). The image matrix is decomposed by rows based on the number of tasks allotted. TBB then parallelizes the tasks among multiple threads and processors.

3.3 CUDA Implementation

With CUDA, we used a general scheme of decomposition for the current image frame. We choose a number of threads per block to form square blocks () and then we create a grid of blocks to match the size of the image. We provide CUDA with a simple kernel such that each thread will process a given pixel. We generally place the entire image into the global memory of the GPU, since past experimentation [22] seems to indicate that implementing a shared mechanism for the size of images we were using would have more overhead than a global memory implementation. The pixel that a thread worked on is determined according to standard CUDA conventions as:

{Verbatim}

[commandchars=
{}] const size˙t r = blockIdx.x * blockDim.x + threadIdx.x; const size˙t c = blockIdx.y * blockDim.y + threadIdx.y; const size˙t index = r * numCols + c;

Here, r is the row of the pixel, c is the column of the pixel, and index becomes the position of the current pixel in an array based on the current Thread ID, Block Dimension, and Block ID (provided by CUDA libraries).

3.3.1 Preprocessing

To parallelize the Gaussian blur, we first attempted to simply write a CUDA kernel which would take as input the image and Gaussian kernel. The kernel would determine which pixel the current thread was assigned to through previously described means. Then the surrounding pixels would be convolved with this kernel. This however, is a naive implementation. In this scenario operations are needed, where is the size of the image, and is the size of the kernel. To significantly reduce this cost, we can use a separable convolution. In this, a 1-Dimensional Gaussian kernel is used to convolve first the rows and then the columns [23]. This results in an equivalent output while requiring only operations. For the 2-Dimensional implementation of the Gaussian filter, we generally use the same code as the serial implementation in the CUDA kernel (obviously without looping over the pixels). For the separable convolution, we use similar code, but rather than running through a loop over a 2D Gaussian kernel for convolution we first run a CUDA kernel over the rows with a 1D Gaussian kernel, then we run it over the columns using the same code, with a flag raised. The core inner code remains fairly similar to the serial functions and can be found in the cuda_kernels.cu file

For median blurring, we simply take the surrounding pixels, order them through a simple swap sorting mechanism and then choose the median value just as in the serial implementation. However, we divide this per kernel such that each thread calculates the values for only one pixel. Generally, the core of this code remains the same as the serial implementation.

3.4 Dual-mode SGM

To parallelize the Dual-mode SGM, we take the same inner code as the serial version and similarly remove the two outer loops which iterate over the pixels in favor of the CUDA kernel thread model described above.

4 Results and Analysis

For both qualitative and quantitative analysis, we use the University of Sherbrooke CDNet database [24]. The database provides image sequences and videos for use in motion detection in different scenarios (including with motion of the camera).

4.1 Qualitative Algorithm Analysis

We first analyze the qualitative results of the algorithm. We note that all parallelized versions were verified against the serial version to ensure that no errors were introduced into the algorithm by parallelization. As such, this qualitative comparison is not necessary.

4.1.1 Effects of Preprocessing

We determined that preprocessing has is an important aspect in filtering out noise during motion detection. This is clearly visible in Figures 1,2,3, and 4. Without preprocessing, the motion detection segmentation mask becomes grainy as more small anomalies in lighting are picked up on a per pixel basis. After Gaussian and median filtering, the anomalies disappear as the image smooths out.

Figure 1: Motion segmentation mask, no Gaussian or median filtering. Figure 2: Motion segmentation mask, Gaussian and median filtering (OpenCV implementation).
Figure 3: Grey scale image, Gaussian and median filtering (OpenCV implementation). Figure 4: This is the original image from the U. Sherbrooke CDNet database. The camera here remains static.

4.1.2 Comparison to OpenCV MOG

Next, we wanted to compare our implementation of the Yi et al. algorithm against the Mixture of Gaussian model in OpenCV. MoG can potentially yield better results as it has a number of background models which can be used to develop a more robust representation of the background. In contrast to our expected results, we found that the MoG implementation of OpenCV did not produce readily identifiable objects in the image as seen in Figure 5. Most of the man is considered to be part of the background, while the man is more identifiable in Figure 6 for our implementation. However, it is worth noting that any place where the color of the man’s clothes blends in with his background, the algorithm cannot identify him as part of the foreground (as in his pants blending into the couch).

Figure 5: OpenCV MoG algorithm implementation, we used all default parameters. Figure 6: The Dual-mode SGM algorithm, with preprocessing.
Figure 7: The original image.

4.1.3 Motion Compensation Results

While we implemented motion compensation using OpenCV’s LKT, RANSAC, and transform functions, our results were not ideal and as such we did not focus on it for parallelization or other aspects. In a dataset with significant jitter as seen in Figures 8, 9, and 10, we saw minimal benefit to having motion compensation versus not. As can be seen in Figure 11, the MoG algorithm has a much cleaner image in this case. However, this is to be expected as it is both better suited to adaptable backgrounds and is much less sensitive than our implementation.

Figure 8: The motion mask with motion compensation. Figure 9: The motion mask without motion compensation
Figure 10: The original image. Figure 11: The OpenCV MoG results with the algorithm.

4.2 Thread Building Blocks

Originally, OpenMP was pursued for easy parallelization. However, on Mac OS X, compilation difficulties when building with OpenCV and OpenMP simultaneously were insurmountable. Since Thread Building Blocks (TBB) is readily supported on Mac OS X systems in combination with OpenCV and the compatible version of gcc, we use this.

4.2.1 Test Specifications

Combinations of using the OpenCV preprocessing filter versus an implemented version as well as including motion compensation in the computation yields four total variations: OpenCV preprocessing with Motion Compensation, OpenCV preprocessing without Motion Compensation, our preprocessing with Motion Compensation, and our preprocessing without Motion Compensation. Furthermore, serial and parallelized implementations of each variation were implemented.

An example set, showing a man enter the frame, sit on a sofa, and finally leave, was used. We use the first 500 frames of the set which has a resolution of 320x240. An original raw frame can be seen in Figure 7. The test machine consisted of an Intel Core i5 at 2.4Ghz with two cores and four hardware threads.

4.2.2 Results

Figure 12 displays the speedup of each the four parallel variations as compared to their respective serial versions with a varying number of TBB tasks. Figures 131415 and 16 reveals the time breakdown spent in each of the major parts of the complete algorithm for all four variations. It is important to note that while we can specify tasks to be parallelized TBB by default creates threads optimized for the number of processor cores and hardware threads. TBB then schedules these tasks onto the cores and hardware threads [25]. As such, we speak of tasks, not threads.

Across all the variations, there are a number of general trends. The optimal number of TBB tasks for running the algorithm plateaus between four and sixteen. Since the test machine has four hardware threads, this is a consistent result. TBB can schedule all the tasks successfully among the hardware threads. Comparing the runtime of the serial version to a single TBB task reveals the parallelization overhead associated with TBB since the serial version is typically slight faster. Furthermore, specifying TBB to use a number of tasks greater than 256 results in times comparable to only using one task. An unreasonably high number of tasks results in the framework not being able to schedule the task among multiple processors or hardware threads, and hence the result is the same as having only one thread. At this point the tasks become to small so the first core is complete with a task before the library can schedule the next one on a different processor so it schedules it on the same thread on the same core [25]. The addition of motion compensation into an algorithm delivers a near constant time addition to the serial portion of the runtime with little variation.

With regards to using the OpenCV Gaussian and median filters for preprocessing as compared to the serial and parallelized filters implemented in this project, the OpenCV implementations are consistently much faster. Despite any TBB parallelization used to speed up filtering, the OpenCV image processing library is optimized based on the architecture of the processor used 444The optimizations within OpenCV were revealed by examining the source code found on GitHub. Many preprocessing flags for specific processor architectures are used, indicating hardware specific optimizations. In particular: https://github.com/Itseez/opencv/blob/f50f249f804b35ad6f39459ec6df9a66fb0825f8/modules/imgproc/src/smooth.cpp. Ultimately, any attempt to re-implement and parallelize parts of OpenCV would most likely be significantly slower.

Processes

Speedup
Figure 12: Speedup comparison of the four main variations of DSGM. An example set of 500 frames as 320x240 was tested on a machine with an Intel Core i5 at 2.4Ghz with two cores and four threads. The use of OpenCV filters over the implemented filters typically speeds computation due to optimizations in the OpenCV library. Since the running time of the OpenCV filters is constant across all implementations, it does not contribute to the speedup. Using the implement filters, however, greatly contributes to the speedup of a variation since there is a significant running time difference between the serial and parallel implementations of the filters. Similar to the OpenCV filters, motion detection is constant time processing and thus diminishes the speed of a variation.

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Tasks

Time (seconds)
Figure 13: Using OpenCV Gaussian and median filtering with motion compensation disabled. An example set of 500 frames as 320x240 was tested on a machine with an Intel Core i5 at 2.4Ghz with two cores and four hardware threads. Across all tests, the OpenCV filtering remains constant time. The TBB parallelization shows faster running times with 4-16 tasks.

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Tasks

Time (seconds)
Figure 14: Using OpenCV Gaussian and median filtering with motion compensation enabled. An example set of 500 frames as 320x240 was tested on a machine with an Intel Core i5 at 2.4Ghz with two cores and four hardware threads. Across all tests, the OpenCV filtering remains constant time. With motion compensation enabled, a steady serial processing time is added to each test.

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Tasks

Time (seconds)
Figure 15: Using an implemented Gaussian and median filter with motion compensation disabled. An example set of 500 frames as 320x240 was tested on a machine with an Intel Core i5 at 2.4Ghz with two cores and four hardware threads. The implemented filter accounts for the majority of the processing time even with TBB. Despite the slow running time, the effectiveness of parallelization with TBB is evident.

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Serial

Tasks

Time (seconds)
Figure 16: Using an implemented Gaussian and median filter with motion compensation enabled for 500 frames as 320x240. The test machine used a Intel Core i5 at 2.4Ghz with two cores and four hardware threads. The implemented filter accounts for the majority of the processing time even with TBB. Despite the slow running time, the effectiveness of parallelization with TBB is evident. With motion compensation enabled, a steady serial processing time is added to each test.

4.3 Cuda

4.3.1 Machine Specifications

The main graphics card we use for testing is an NVIDIA GeForce GT 650M graphics card in conjunction with a 2.6 GHz Intel Core i7 processor. Though full specifications for the card from CUDA’s deviceQuery program can be seen in Appendix A, the main points to note are the following. It is a Kepler architecture card with two multiprocessors with 192 CUDA cores per multiprocessor. It has a warp size of 32 and a quad-warp scheduler (it schedules 4 warps at once for a total of 128 threads). Additionally it can handle a maximum of 1024 threads per block.

4.3.2 Preprocessing

We first compared our separable Gaussian filter implementation to the 2-Dimensional implementation. We ran this test on the NVIDIA GeForce GT 650M graphics card. We excluded motion compensation, but retained median blurring and the CUDA-parallelized Dual-mode SGM background detection for all versions that we ran. We found as we previously did with TBB that OpenCV Gaussian and Median filters are significantly faster overall due the heavy optimizations done within the code. Additionally, though the CUDA parallelized version of separable Gaussian filtering comes closer to comparing to the OpenCV method, but still cannot compete with its optimizations. As such, for further tests we retain the OpenCV pre-processing methods.

\pbox20cmOur Serial Gaussian Filter
and Median Filter \pbox20cm.
OpenCV Serial
Gaussian Filter
and Median Filter
\pbox20cmCUDA 2-D Implementation
and CUDA Median Filter \pbox20cmCUDA Separable Filter
and CUDA Median Filter
50.74 seconds 9.35 seconds 18.26 seconds 13.03 seconds
Figure 17: A comparison of CUDA 2-Dimensional and separable Gaussian filter implementation runtimes to our serial Gaussian Filter and OpenCV’s serial Gaussian filter. Note: these numbers were taken from the average of 20 runs using an NVIDIA GeForce GT 650M graphics card and a 2.6 GHz Intel Core i7 processor. Includes CUDA speedup of all other parts except the filtering. Excludes motion compensation altogether. 121 threads per block for CUDA kernels.

4.3.3 Dual-mode SGM and Thread Block Optimization

Overall, by parallelizing the Dual-Mode SGM we see significant speedup from the serial version of our code. To test the speedup for this part, we use an OpenCV Gaussian Filter and Median Filter and exclude motion compensation. Furthermore, we attempt to demonstrate thread block size optimization on the NVIDIA Kepler architecture with CUDA. As seen in Figures 18 and 19, we attain a significant maximal speedup of about 2.5 using CUDA parallelization with 121 threads per block (a square block of size ). As seen in Figure 19, where we consider communication time of parallel processing to be transfer of data between GPU memory and main memory, for all block size the communication time remains constant, as we only copy over the image once to GPU memory. Processing time, however, significantly drops to an optimal speedup at 121 threads. This correlates greatly with expectations. In the Kepler architecture and the NVIDIA GeForce GT 650M graphics card, the warp size is 32 with a quad-warp scheduler. That means that 128 threads are scheduled at once. At 121 threads, nearly all warps are filled and scheduled at once as soon as a block is brought into the multiprocessor. This is the reason we expect this to be an optimal thread block size. With more threads, however, all warps may not be scheduled or made use of at once and hence leaving some processors idle. This is why we see decreases in speedup both with more threads and less threads per block. It is important to note that for this test we displayed each frame using the OpenCV imshow function, as such there is a larger serial overhead.

1

1

1

1

1

1

1

1

1

1

1

Threads per block

Speedup
Figure 18: Here we see the speedup of the CUDA implementation when compared to the unparallelized version. Both use the OpenCV preprocessing methods. Tests run on NVIDIA GeForce GT 650M graphics card.

1

1

1

1

1

1

1

1

1

1

1

Threads per block

Time (seconds)
Figure 19: Here we see the proportional parts of the code which run in Serial and Parallel as well as the breakdown of parallel communication time vs. parallel processing time. Communication and processing was determined as follows. A CPU clock was used to measure the total time in parallel (including memory operations). Subsequently, the GPU clock (through CUDA library event calls) was used to determine to amount of time spent processing on the GPU. The two were subtracted to gain insight into parallel vs. computation time. Test run on NVIDIA GeForce GT 650M graphics card.

4.3.4 GPU Comparison

We also acquired another GPU for comparison under the Fermi architecture. The second card used was a GeForce GTX 570 with full specifications found in Appendix B. The main difference between the two cards (emphasized due to the differences in architecture) is the number of multiprocessors and CUDA cores in this one. There are 15 multiprocessors with 32 CUDA Cores each for a total of 480 CUDA Cores. The warp size is also 32, but there is only a dual warp scheduler. We ran the same tests as on the previous card with various amounts of threads per block (though a smaller subset) which can be found in Figures 20 and 21. Here it is visible that we reach a speedup wall with this processor. While there is some improvement from 1 thread per block to 64 threads per block. The serial portion of the code (OpenCV preprocessing, which showed to be faster than our parallelized preprocessing, and displaying of images through the OpenCV library) proved to be much more overhead than the parallel processing. As such we see a speedup of about 2.7 at maximum. Additionally, because the GTX 570 has more blocks scheduled at once (among 15 multiprocessors, so 15 blocks at once) with two warp schedulers of 32 threads each. It makes sense that 64 threads per block would be the most efficient. As a block is scheduled all threads are immediately scheduled by the two warp schedulers and 15 blocks can be handled almost simultaneously. However, the overall time of processing on the GPU is nearly negligible and hence speedup does not change drastically for varying numbers of threads (except for 1 and 4 threads per block, in which case too many CUDA cores are wasted during scheduling of a warp). Because this is a real time algorithm and the output of the image takes more time than the processing on a GPU with a reasonable thread block size, running it on more powerful GPUs is unnecessary. As it is, the algorithm has become real time.

1

1

1

1

1

1

1

1

1

1

1

Threads per block

Speedup
Figure 20: Here we see the speedup of the CUDA implementation when compared to the unparallelized version. Both use the OpenCV preprocessing methods. Tests run on NVIDIA GeForce GTX 570 graphics card.

1

1

1

1

1

1

1

1

1

1

1

Threads per block

Time (seconds)
Figure 21: Here we see the same test as the original CUDA tests ran previously with varying threads per block on the GTX 570 card. We use a smaller subset of tests and see little variation across the number of threads per block. We used a Windows machine in this case so the timing information only goes to 3 decimal places for CPU based timing due to the Windows timing library. Communication is negligible at a value of 0.001 seconds.

5 Conclusion

We successfully implemented the method in Yi et al. for detecting and segmenting motion in a series of images555Our implementation can be found at: https://github.com/Breakend/MotionDetection.. While we had poor results in achieving motion compensation, the results with a static camera are promising and show more detail than OpenCV’s MoG implementation. We successfully achieved speedup with both CUDA and TBB, however, for preprocessing, OpenCV’s implementation was much more optimized and thus resulted in no improvement from the OpenCV implementation in overall running time. Additionally, on a somewhat powerful GPU like the GTX 570 with many multiprocessors (per the Fermi architecture), we see that the speedup of the algorithm through parallelization hits a wall. The time to read and display an image using OpenCV functions (and the slight time for preprocessing) overtakes all other functionality. As such, this is essentially a real time algorithm.

5.1 Issues and Usability of TBB

While we chose TBB for its ease of installation and lack of compilation issues with our systems (Macbook Pro laptops with Intel processors running OS X 10.9), it is helpful in its abstraction of many small optimizations relating to multiprocessor use. Once the learning curve of TBB was surpassed, it was relatively simple to formulate different functions as tasks for the library to divide among processors.

5.2 Issues and Usability of CUDA

CUDA is an extremely helpful tool in parallelization with the GPU, we achieved significant speedup using the tool. While more speedup may be possible by optimizing distribution of global memory into shared memory caches, we found previous work that indicates this would not be helpful with the size of images we are using (as previously mentioned). CUDA itself is a tool that is difficult to debug, so issues (including with invalid memory corruption in the case of non-contiguously allocated matrices) took a long time to trace. Overall, CUDA makes GPU programming more accessible, assuming you are able to successfully install and compile it. The abstractions of thread blocks make parallelization relatively simple once you have some core base code complete. However, the learning curve for CUDA is steep.

5.3 Future Work

In the future, we hope to optimized and modify Yi et al.’s method to work with more robust motion compensation systems to improve and parallelize those results. We also hope to implement some parallelizations of the basic algorithm on the Raspberry Pi’s modest GPU so that low cost mobile systems (as in robotics) are possible.

References

  • [1] S.-C. Huang, “An advanced motion detection algorithm with video quality analysis for video surveillance systems,” Circuits and Systems for Video Technology, IEEE Transactions on, vol. 21, no. 1, pp. 1–14, 2011.
  • [2] I. Haritaoglu, D. Harwood, and L. S. Davis, “W 4: Real-time surveillance of people and their activities,” Pattern Analysis and Machine Intelligence, IEEE Transactions on, vol. 22, no. 8, pp. 809–830, 2000.
  • [3] Z. Yu and Y. Chen, “A real-time motion detection algorithm for traffic monitoring systems based on consecutive temporal difference,” in Asian Control Conference, 2009. ASCC 2009. 7th.   IEEE, 2009, pp. 1594–1599.
  • [4] T. Senoo, Y. Yamakawa, Y. Watanabe, H. Oku, and M. Ishikawa, “High-speed vision and its application systems,” Journal ref: Journal of Robotics and Mechatronics, vol. 26, no. 3, pp. 287–301, 2014.
  • [5] W. Hu, T. Tan, L. Wang, and S. Maybank, “A survey on visual surveillance of object motion and behaviors,” Systems, Man, and Cybernetics, Part C: Applications and Reviews, IEEE Transactions on, vol. 34, no. 3, pp. 334–352, 2004.
  • [6] C. R. Wren, A. Azarbayejani, T. Darrell, and A. P. Pentland, “Pfinder: Real-time tracking of the human body,” Pattern Analysis and Machine Intelligence, IEEE Transactions on, vol. 19, no. 7, pp. 780–785, 1997.
  • [7] C. Stauffer and W. E. L. Grimson, “Adaptive background mixture models for real-time tracking,” in Computer Vision and Pattern Recognition, 1999. IEEE Computer Society Conference on., vol. 2.   IEEE, 1999.
  • [8] A. J. Lipton, H. Fujiyoshi, and R. S. Patil, “Moving target classification and tracking from real-time video,” in Applications of Computer Vision, 1998. WACV’98. Proceedings., Fourth IEEE Workshop on.   IEEE, 1998, pp. 8–14.
  • [9] B. D. Lucas, T. Kanade et al., “An iterative image registration technique with an application to stereo vision.” in IJCAI, vol. 81, 1981, pp. 674–679.
  • [10] B. K. Horn and B. G. Schunck, “Determining optical flow,” in 1981 Technical Symposium East.   International Society for Optics and Photonics, 1981, pp. 319–331.
  • [11] K. M. Yi, K. Yun, S. W. Kim, H. J. Chang, and J. Y. Choi, “Detection of moving objects with non-stationary cameras in 5.8 ms: Bringing motion detection to your mobile device,” in Computer Vision and Pattern Recognition Workshops (CVPRW), 2013 IEEE Conference on.   IEEE, 2013, pp. 27–34.
  • [12] S. W. Kim, K. Yun, K. M. Yi, S. J. Kim, and J. Y. Choi, “Detection of moving objects with a moving camera using non-panoramic background model,” Machine vision and applications, vol. 24, no. 5, pp. 1015–1028, 2013.
  • [13] Intel. TBB Features. [Online]. Available: https://software.intel.com/en-us/intel-tbb
  • [14] ——. TBB Reference Manual. [Online]. Available: https://software.intel.com/en-us/node/506130
  • [15] The OpenMP ARB. About OpenMP. [Online]. Available: http://openmp.org/wp/about-openmp/
  • [16] NVIDIA. About CUDA. [Online]. Available: https://developer.nvidia.com/about-cuda
  • [17] ——. NVIDIA’s Next Generation CUDA Compute Architecture: Kepler GK110. [Online]. Available: http://www.nvidia.com/content/PDF/kepler/NVIDIA-kepler-GK110-Architecture-Whitepaper.pdf
  • [18] ——. NVIDIA’s Next Generation CUDA Compute Architecture: Fermi. [Online]. Available: http://www.nvidia.com/content/pdf/fermi_white_papers/nvidia_fermi_compute_architecture_whitepaper.pdf
  • [19] H. Bay, T. Tuytelaars, and L. Van Gool, “Surf: Speeded up robust features,” in Computer Vision–ECCV 2006.   Springer, 2006, pp. 404–417.
  • [20] C. Tomasi and T. Kanade, Detection and tracking of point features.   School of Computer Science, Carnegie Mellon Univ. Pittsburgh, 1991.
  • [21] M. A. Fischler and R. C. Bolles, “Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography,” Communications of the ACM, vol. 24, no. 6, pp. 381–395, 1981.
  • [22] StackOverflow. 2D CUDA Median Filter Optimization. [Online]. Available: http://stackoverflow.com/questions/19634328/2d-cuda-median-filter-optimization
  • [23] V. Podlozhnyuk, “Image convolution with cuda,” 2007.
  • [24] Y. Wang, P.-M. Jodoin, F. Porikli, J. Konrad, Y. Benezeth, and P. Ishwar, “Cdnet 2014: an expanded change detection benchmark dataset,” in Computer Vision and Pattern Recognition Workshops (CVPRW), 2014 IEEE Conference on.   IEEE, 2014, pp. 393–400.
  • [25] W. Kim and M. Voss, “Multicore desktop programming with intel threading building blocks,” IEEE software, vol. 28, no. 1, pp. 23–31, 2011.

Appendix A Device Specifications: GeForce GT 650M

{Verbatim}

[commandchars=
{},codes=, fontsize=] Device 0: ”GeForce GT 650M” CUDA Driver Version / Runtime Version 6.5 / 6.5 CUDA Capability Major/Minor version number: 3.0 Total amount of global memory: 1024 MBytes (1073414144 bytes) ( 2) Multiprocessors, (192) CUDA Cores/MP: 384 CUDA Cores GPU Clock rate: 405 MHz (0.41 GHz) Memory Clock rate: 2000 Mhz Memory Bus Width: 128-bit L2 Cache Size: 262144 bytes Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096) Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 65536 Warp size: 32 Maximum number of threads per multiprocessor: 2048 Maximum number of threads per block: 1024 Max dimension size of a thread block (x,y,z): (1024, 1024, 64) Max dimension size of a grid size (x,y,z): (2147483647, 65535, 65535) Maximum memory pitch: 2147483647 bytes Texture alignment: 512 bytes Concurrent copy and kernel execution: Yes with 1 copy engine(s) Run time limit on kernels: Yes Integrated GPU sharing Host Memory: No Support host page-locked memory mapping: Yes Alignment requirement for Surfaces: Yes Device has ECC support: Disabled Device supports Unified Addressing (UVA): Yes Device PCI Bus ID / PCI location ID: 1 / 0

Appendix B Device Specifications: GeForce GTX 570

{Verbatim}

[commandchars=
{},codes=, fontsize=]

Device 0: ”GeForce GTX 570” CUDA Driver Version / Runtime Version 6.5 / 6.5 CUDA Capability Major/Minor version number: 2.0 Total amount of global memory: 1280 MBytes (1342177280 bytes) (15) Multiprocessors, ( 32) CUDA Cores/MP: 480 CUDA Cores GPU Clock rate: 1464 MHz (1.46 GHz) Memory Clock rate: 1900 Mhz Memory Bus Width: 320-bit L2 Cache Size: 655360 bytes Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65535), 3D=(2048, 2048, 2048) Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 32768 Warp size: 32 Maximum number of threads per multiprocessor: 1536 Maximum number of threads per block: 1024 Max dimension size of a thread block (x,y,z): (1024, 1024, 64) Max dimension size of a grid size (x,y,z): (65535, 65535, 65535) Maximum memory pitch: 2147483647 bytes Texture alignment: 512 bytes Concurrent copy and kernel execution: Yes with 1 copy engine(s) Run time limit on kernels: Yes Integrated GPU sharing Host Memory: No Support host page-locked memory mapping: Yes Alignment requirement for Surfaces: Yes Device has ECC support: Disabled CUDA Device Driver Mode (TCC or WDDM): WDDM (Windows Display Driver Model) Device supports Unified Addressing (UVA): Yes Device PCI Bus ID / PCI location ID: 1 / 0

Appendix C Preprocessing Gaussian Blur Code Snippet

{Verbatim}

[commandchars=
{}] float blur = 0.f; //Average pixel color summing up adjacent pixels. for (int i = -half; i ¡= half; ++i) – for (int j = -half; j ¡= half; ++j) – // Clamp filter to the image border int h = min(max(r + i, 0), height); int w = min(max(c + j, 0), width);

// Blur is a product of current pixel value and weight of that pixel. // Remember that sum of all weights equals to 1, // so we are averaging sum of all pixels by their weight. float pixel = frame.at¡uchar¿(h,w); // (row,col) int idx = (i + half) * size.width + (j + half); // width float weight = gaussian˙filter[idx]; blur += pixel * weight; ˝ ˝ destination.at¡uchar¿(r,c) = static˙cast¡unsigned char¿(blur);

Appendix D Preprocessing Median Blur Code Snippet

{Verbatim}

[commandchars=
{}] int idx = 0; //Average pixel color summing up adjacent pixels. for (int i = -half; i ¡= half; ++i) – for (int j = -half; j ¡= half; ++j) – // Clamp filter to the image border int h = min(max(r + i, 0), height); int w = min(max(c + j, 0), width); window[idx] = frame.at¡uchar¿(h,w); // (row,col) idx++; ˝ ˝

// sort the window to find median insertionSort(window, window˙len);

// assign the median to centered element of the matrix destination.at¡uchar¿(r,c) = window[idx / 2];

Appendix E Dual-mode SGM Inner Update Code Snippet

{Verbatim}

[commandchars=
{}] cv::Scalar i˙sclr = next˙frame-¿at¡uchar¿(y,x); cv::Scalar app˙u˙sclr = app˙u˙mat-¿at¡uchar¿(y,x); cv::Scalar app˙var˙sclr = app˙var˙mat-¿at¡uchar¿(y,x); cv::Scalar can˙u˙sclr = can˙u˙mat-¿at¡uchar¿(y,x); cv::Scalar can˙var˙sclr = can˙var˙mat-¿at¡uchar¿(y,x);

// Get the differences for the candidate and apparent background models float adiff = i˙sclr.val[0] - app˙u˙sclr.val[0]; float cdiff = i˙sclr.val[0] - can˙u˙sclr.val[0];

if (pow(adiff, 2) ¡ MEAN˙THRESH * max(app˙var˙sclr.val[0], .1))– i = 0; alpha = 1.0 / (double)app˙ages[x][y]; app˙u˙sclr.val[i] = (1.0-alpha) * app˙u˙sclr.val[i] + (alpha) * i˙sclr.val[i]; V = pow((app˙u˙sclr.val[i] - i˙sclr.val[i]),2); app˙var˙sclr.val[i] = (1.0-alpha) * app˙var˙sclr.val[i] + alpha * V;

//write into matrix app˙u˙mat-¿at¡uchar¿(y,x) = app˙u˙sclr.val[i]; app˙var˙mat-¿at¡uchar¿(y,x) = app˙var˙sclr.val[i];

if (app˙ages[x][y] ¡ AGE˙THRESH) – app˙ages[x][y]++; ˝

˝ else if (pow(cdiff, 2) ¡ MEAN˙THRESH * max(can˙var˙sclr.val[0], .1)) – i = 0; alpha = 1.0 / (double)can˙ages[x][y]; can˙u˙sclr.val[i] = (1.0-alpha) * can˙u˙sclr.val[i] + (alpha) * i˙sclr.val[i]; V = pow((can˙u˙sclr.val[i] - i˙sclr.val[i]),2); can˙var˙sclr.val[i] = (1.0-alpha) * can˙var˙sclr.val[i] + alpha * V;

//write into matrix can˙u˙mat-¿at¡uchar¿(y,x) = can˙u˙sclr.val[i]; can˙var˙mat-¿at¡uchar¿(y,x) = can˙var˙sclr.val[i];

// Cap ages if (can˙ages[x][y] ¡ AGE˙THRESH) – can˙ages[x][y]++; ˝

˝ else – can˙u˙mat-¿at¡uchar¿(y, x) = i˙sclr.val[0]; can˙var˙mat-¿at¡uchar¿(y, x) = VAR˙INIT; can˙ages[x][y] = 1; ˝

if (can˙ages[x][y] ¿ app˙ages[x][y]) – // Swap the models app˙u˙mat-¿at¡uchar¿(y,x) = can˙u˙sclr.val[0]; app˙var˙mat-¿at¡uchar¿(y,x) = can˙var˙sclr.val[0]; app˙ages[x][y] = can˙ages[x][y];

//candidateBackgroundModel-¿setPixel(next˙frame, y, x); can˙u˙mat-¿at¡uchar¿(y, x) = i˙sclr.val[0]; can˙var˙mat-¿at¡uchar¿(y, x) = VAR˙INIT; can˙ages[x][y] = 1; ˝

cv::Scalar app˙diff = app˙u˙mat-¿at¡uchar¿(y,x) - next˙frame-¿at¡uchar¿(y,x);

if (pow(app˙diff.val[0], 2) ¡= THETA˙D*max(0.25, i˙sclr.val[0])) – //background bin˙mat-¿at¡uchar¿(y, x) = 0; ˝ else//foreground bin˙mat-¿at¡uchar¿(y, x) = 255; ˝

Appendix F Motion Compensation Code Snippets

{Verbatim}

[commandchars=
{}] cv::goodFeaturesToTrack(m˙prevImg, m˙prevPts, maxCorners, qualityLevel, minDistance, mask, blockSize, useHarrisDetector, k);

if(m˙prevPts.size() ¿= 1) – cv::calcOpticalFlowPyrLK(m˙prevImg, m˙nextImg, m˙prevPts, m˙nextPts, m˙status, m˙error, Size(20,20), 5);

// compute homography using RANSAC cv::Mat mask; vector ¡Point2f¿ prev˙corner2, cur˙corner2; n = next˙frame-¿clone();

// weed out bad matches for(size˙t i=0; i ¡ m˙status.size(); i++) – if(m˙status[i]) – prev˙corner2.push˙back(m˙prevPts[i]); cur˙corner2.push˙back(m˙nextPts[i]); ˝ ˝ // apply motion compensation cv::Mat H = cv::findHomography(prev˙corner2,cur˙corner2, CV˙RANSAC); warpPerspective(m˙nextImg, n, H, m˙prevImg.size(), INTER˙LINEAR WARP˙INVERSE˙MAP); ˝

Comments 0
Request Comment
You are adding the first comment!
How to quickly get a good reply:
  • Give credit where it’s due by listing out the positive aspects of a paper before getting into which changes should be made.
  • Be specific in your critique, and provide supporting evidence with appropriate references to substantiate general statements.
  • Your comment should inspire ideas to flow and help the author improves the paper.

The better we are at sharing our knowledge with each other, the faster we move forward.
""
The feedback must be of minimum 40 characters and the title a minimum of 5 characters
   
Add comment
Cancel
Loading ...
29291
This is a comment super asjknd jkasnjk adsnkj
Upvote
Downvote
""
The feedback must be of minumum 40 characters
The feedback must be of minumum 40 characters
Submit
Cancel

You are asking your first question!
How to quickly get a good answer:
  • Keep your question short and to the point
  • Check for grammar or spelling errors.
  • Phrase it like a question
Test
Test description