This is a quick implementation of Perona-Malik + Chan-Sandberg-Vese segmentation in C++.
The idea is to reduce noise in the image with Perona-Malik before segmenting the region with Chan-Sandberg-Vese algorithm, as the latter is relatively sensitive to noise. The resulting contour is used to cut out ROI from the original image.
Implementation relies on (version number the code was tested with)
- OpenCV (2.4.8) (
opencv_core
,opencv_imgproc
andopencv_highgui
libs); - Boost libraries (1.59.0) (
program_options
,system
andfilesystem
libs); - OpenMP (4.0);
The compiler must be compatible with the latest C++14 standard (clang
3.6+ or gcc
5.0+ will do ok).
To build, just do make
but make sure that your compiler sees the libs and headers listed above; to read the documentation, do make doc
; to see all possible command line arguments, do bin/chan_vese -h
.
If you want to enable debugging symbols in the binary, build it with DEBUG
variable defined, e.g. DEBUG=1 make
;
If you want to build it with multithreaded boost libraries, build the project with MT
variable defined, e.g. MT=1 make
; or you could edit the library names by hand in the Makefile
.
Both methods summed up in a couple of sentences:
-
Perona-Malik segmentation is an improvement from classical Gaussian blur, the kernel of which is a solution to heat equation. Perona and Malik improved upon it by promoting the diffusion constant c in the heat equation to a function of the image I gradient magnitude aka edge detection function 1:
Thus, when a region contains no edges (image gradient small), it will be Gaussian-smoothed; when the edge detection function encounters an edge it will not be smoothed but even enhanced.
-
Chan-Sandberg-Vese (or Chan-Vese for a single-channel image) formulates optimal contour in the image by defining a functional dependant on zero-level set u
where the 1st term penalizes length of the contour; the 2nd term area enclosed by the contour; the 3rd and 4th terms penalize discrepancy between the intensity averages inside and outside of the contour 2 3. The corresponding equation of motion for the zero level set can be solved implicitly (read: fast).
For further information, see the documentation or check the references given below.
Original image (top left), smoothed with Perona-Malik (top right), segmented with Chan-Sandberg-Vese (bottom left), PM+CSV (bottom right).
Image courtesy: Wikimedia Commons (original).
Command used:
bin/chan_vese -i seastar.png -s -N 70 -S -L 0.25 -T 100 -K 30
Zero level set evolution and the final result, obtained with the following command:
bin/chan_vese -i 640px-Europe_night.png \
-N 132 --dt 0.001 -t 0.000001 --nu -293 --lambda1 1 1 0.1 \
-S -L 0.1 -T 1.5 -K 1000 \
-s -V -f 12 -l red
Image courtesy: Wikimedia Commons (original).
An alternative to initializing the level set with a checkerboard pattern seen above is to let users specify either rectangular or circular contour:
Image courtesy: Wikimedia Commons (original)
[1] Scale-space and edge detection using anisotropic diffusion