The results of some experimentation with and comparison between raw OpenCV functions and the cvBlobsLib library to detect darker coloured spots against lighter backgrounds.
For guidance on how to set up OpenCV / cvBlobsLIb for use in Visual Studio Environments, take a look at this post or this one.
Main program loop:
// DetectBlobs.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "BlobResult.h" #include <cv.h> #include <cxcore.h> #include <highgui.h> int _tmain(int argc, _TCHAR* argv[]) { // Initialise //std::string filepath = "spots.bmp"; std::string filepath = "spots2.bmp"; CBlobResult blobs; int num_blobs = 0; // Load grayscale version of coloured input image IplImage* original = cvLoadImage( filepath.c_str() ); IplImage* grayscale = cvLoadImage( filepath.c_str(), CV_LOAD_IMAGE_GRAYSCALE ); // Check bitmap image exists assert( grayscale ); // Create IplImage struct for a black and // white (binary) image IplImage* img_bw = cvCreateImage( cvGetSize( grayscale ), IPL_DEPTH_8U, 1 ); // Use thresholding to convert grayscale image // into binary cvThreshold( grayscale, // source image img_bw, // destination image 40, // threhold val. 255, // max. val CV_THRESH_BINARY ); // binary // Create IplImage struct for inverted black // and white image IplImage* img_bw_inv = cvCloneImage( img_bw ); IplImage* img_bw_cpy = cvCloneImage( img_bw ); // Find connected components using cvBlobsLib blobs = CBlobResult( img_bw, 0, 255 ); // Exclude all blobs smaller than the given value // The bigger the last parameter, the bigger the // blobs need to be for inclusion blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_GREATER, 3 ); num_blobs = blobs.GetNumBlobs(); // Find connected components using OpenCV CvSeq* seq; CvMemStorage* storage = cvCreateMemStorage( 0 ); cvClearMemStorage( storage ); // cvFindContours the 12 + 1 extra object for // white backgrounds and black spots, hence // subtract 1 num_blobs = cvFindContours( img_bw, storage, &seq, sizeof( CvContour ), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint( 0, 0 ) ) - 1; // Display the input / output windows and images cvNamedWindow( "original" ); cvShowImage( "original", original ); cvNamedWindow( "grayscale" ); cvShowImage( "grayscale", grayscale ); cvNamedWindow( "black_and_white" ); cvShowImage( "black_and_white", img_bw_cpy ); // Wait for user key press and then tidy up cvWaitKey(0); cvReleaseImage( &original ); cvReleaseImage( &grayscale ); cvReleaseImage( &img_bw ); cvReleaseImage( &img_bw_inv ); cvReleaseImage( &img_bw_cpy ); cvDestroyWindow( "greyscale" ); cvDestroyWindow( "black_and_white" ); cvDestroyWindow( "inverted" ); return 0; }
Output windows obtained for the original, grayscale and binary images respectively were as follows:
Spot detection using cvBlobsLib
Object detection using the cvBlobsLib is a straightforward matter of creating a CBlobResult object, by giving it the input black and white image and background colour (255); and detecting the blobs themselves by means of the filter method, which in this example is fairly self-explanatory: exclude any blobs whose area is less than 3; output the number of blobs detected:
// Find connected components using cvBlobsLib blobs = CBlobResult( img_bw, 0, 255 ); // Exclude all blobs smaller than the given value // The bigger the last parameter, the bigger the blobs need // to be for inclusion blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_GREATER, 3 ); num_blobs = blobs.GetNumBlobs();
Spot detection using OpenCV
Using raw OpenCV calls to detect and count the objects is achieved with the cvFindContours function as shown in the following code section:
// Find connected components using OpenCV CvSeq* seq; CvMemStorage* storage = cvCreateMemStorage( 0 ); cvClearMemStorage( storage ); // cvFindContours the 12 + 1 extra object // for white backgrounds and black spots, hence // subtract 1 num_blobs = cvFindContours( img_bw, storage, &seq, sizeof( CvContour ), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint( 0, 0 ) ) - 1;
For some reason as yet unclear to me, the cvFindContours returns a count of 13 objects: 12 + one extra, so I have subtracted one in this instance to give the true count. For images with black backgrounds and white objects this seems to be unnecessary.
Downloadable Visual Studio 2008 Project here.
Other posts related to image detection
Tracking Coloured Objects in Video using OpenCV
Displaying AVI Video using OpenCV
Analyzing FlyCapture2 Images obtained from Flea2 Cameras
Integrating the FlyCapture SDK for use with OpenCV
Getting Started with OpenCV in Visual Studio
Object Detection Using the OpenCV / cvBlobsLib Libraries