Blob detection

One approach for blob detection is the detection of local maxima of the Laplacian filter response in the scale space of the input image.

This means that you:

  • you first construct a scale-space = image pyramid with N levels (= 'octaves') and on each level of the image pyramid you generate blurred version of the image with different blurring levels
  • you filter each such blurred image with the Laplacian filter
  • you detect local maxima (minima) of these filter responses, where a blob has to be a local maximum not only in the same image (8 neighbours), but also compared to neighboured scales (2×9 neighbours), i.e. in total 8+18=26 neighbours are considered

I recommend this very intuitive introduction by AIShack

Scale Space

  • the image is resized within an image pyramid (each resize level is called octave)
  • on each image pyramid level the image is blurred with different sigmas for the Gaussian blur kernel (nr of blur levels)

For SIFT e.g. typically 4 octaves + 5 blur levels are used.

Intros to scale space

  • 1
  • 2
  • 3 (with code)
  • 4 (best intro I could find)


Difference of Gaussians

  • the Laplacian of an image can be approximated by the difference of two Gaussians with different sigmas

Scale Space + Laplacian Filter Response Demo

input images:

blurred images:

Laplacian filter responses:

C++ code for the Laplacian demo

inline void getGaussKernelSizeAndSigmaForLevel(int l, int& gaussian_kernel_size, int& gauss_sigma)
	gauss_sigma = l;
	gaussian_kernel_size = gauss_sigma * 5;
	if (gaussian_kernel_size % 2 == 0)
void MyKeypointDetector::start()
	cv::VideoCapture cap;;
	double minVal,maxVal;
	const int NrLevels = 10;
	cv::Mat scaleSpace_blurredImages[NrLevels];
	cv::Mat scaleSpace_laplacianResponses[NrLevels];
	cv::Mat scaleSpace_laplacianResponses_normalized[NrLevels];
	int showLevelNr = 1;
	int screenshot_counter = 0;
	while (true)
		// measure time
		long start_time = clock();
		// get next camera image + convert it to gray scale
                cv::Mat frameRGB;
                cap >> frameRGB;
                if( frameRGB.empty() )
		cv::Mat frame;
		cv::cvtColor( frameRGB, frame, CV_RGB2GRAY );
		/// compute scale space + Laplacian filter responses
		/// note: here only one octave = image pyramid level
		for (int l=0; l<NrLevels; l++)
			// compute gauss kernel size + sigma for blurring
			int gauss_kernel_size;
			int gauss_sigma;
			getGaussKernelSizeAndSigmaForLevel(l, gauss_kernel_size, gauss_sigma);
			// blur image
			cv::GaussianBlur( frame, scaleSpace_blurredImages[l], cv::Size(gauss_kernel_size,gauss_kernel_size), gauss_sigma, gauss_sigma );
			// do Laplacian transform
			int ddepth = CV_16S;
			int laplacian_kernel_size = 5;
			int scale = 1;
			int delta = 0;			
			cv::Laplacian( scaleSpace_blurredImages[l], scaleSpace_laplacianResponses[l], ddepth, laplacian_kernel_size, scale, delta );
			// normalize image to 8 bit
			cv::convertScaleAbs( scaleSpace_laplacianResponses[ l ], scaleSpace_laplacianResponses_normalized[ l ], (gauss_sigma+1)*0.25 );
		// stop time
		long elapsed_time = clock() - start_time;
		float fps = 1000.0/(float)elapsed_time;
		char txt[100];
		sprintf_s(txt, "%d ms / %.1f fps", elapsed_time, fps);
		cv::putText( frameRGB, txt, cv::Point(5,25), CV_FONT_HERSHEY_SIMPLEX, 0.7f, CV_RGB(0,255,0) );
		/// show images
		// show camera image		
		cv::imshow( "cam", frameRGB );
		// show blurred image		
		int gauss_kernel_size;
		int gauss_sigma;
		getGaussKernelSizeAndSigmaForLevel(showLevelNr, gauss_kernel_size, gauss_sigma);
		sprintf_s( txt, "smoothed with gauss_kernel_size=%d + gauss_sigma=%d", gauss_kernel_size, gauss_sigma );
		cv::putText( scaleSpace_blurredImages[ showLevelNr ], txt, cv::Point(5,30), CV_FONT_HERSHEY_SIMPLEX, 0.5f, CV_RGB(0,255,0) );
		cv::imshow( "blurred image", scaleSpace_blurredImages[ showLevelNr ] );
		// show Laplacian filter response image
		cv::imshow( "laplacian filter response", scaleSpace_laplacianResponses_normalized[ showLevelNr ] );
		/// save images
		char fname[500];
		sprintf_s( fname, "W:\\tmp\\lapdemo_input_img_%05d.png", screenshot_counter);
		cv::imwrite( fname, frameRGB );
		sprintf_s( fname, "W:\\tmp\\lapdemo_blurred_img_%05d.png", screenshot_counter);
		cv::imwrite( fname, scaleSpace_blurredImages[ showLevelNr ] );
		sprintf_s( fname, "W:\\tmp\\lapdemo_laplacian_response_%05d.png", screenshot_counter);
		cv::imwrite( fname, scaleSpace_laplacianResponses_normalized[ showLevelNr ] );
		// show another scale-space level in the next loop
		if (showLevelNr==NrLevels)
	} // while (forever)

Other blob detection approaches using OpenCV

public/blob_detection.txt · Last modified: 2013/07/18 10:20 (external edit) · []
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki