The key to building many important OpenCV application, is to extract robust features from the image.
Depending on the application we tend to extract features such as corners, haar cascades, contours etc in both spatial and/or temporal dimensions.
The code here was initially implemented using OpenCV 1.0, the code works with latest version (2.4.9) as well.
The program basically checks the neighboring pixels lying on a 'Window' around the pixel under test. Consider a sample image thresholded and is under process. The Pixel A as we see from the image below contains optimum number of 'Black Pixels' in the Scanning Window - 5 in total. Whereas Pixels B and C have 3 and 10 respectively. Based on the Window size and a series of tests and inspection we can safely assume that A is a corner while B and C are not. So depending on the Window size and Optimal number if Black or White pixels around the pixel under test, we can mark them as corners.
The Image below is a representative of the code that has been implemented.
Notice that in the same code below, the number of 'Black Pixels' are being counted.
Also try and experiment by changing
Note: FAST has been ported to OpenCV. It is available natively in OpenCV.
http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html#fast
Compatibility > OpenCV 1.0
Files:
Download from DsynFLO box folder - https://app.box.com/s/h49lu1ht6mjbapym726z
Source Code:
Depending on the application we tend to extract features such as corners, haar cascades, contours etc in both spatial and/or temporal dimensions.
The code here was initially implemented using OpenCV 1.0, the code works with latest version (2.4.9) as well.
The program basically checks the neighboring pixels lying on a 'Window' around the pixel under test. Consider a sample image thresholded and is under process. The Pixel A as we see from the image below contains optimum number of 'Black Pixels' in the Scanning Window - 5 in total. Whereas Pixels B and C have 3 and 10 respectively. Based on the Window size and a series of tests and inspection we can safely assume that A is a corner while B and C are not. So depending on the Window size and Optimal number if Black or White pixels around the pixel under test, we can mark them as corners.
The Image below is a representative of the code that has been implemented.
Notice that in the same code below, the number of 'Black Pixels' are being counted.
Also try and experiment by changing
if((sum > 2 ) && (sum < 5))to
if((sum >= 8 ) && (sum < 9))or
if((sum >= 10 ) && (sum <= 11))
Note: FAST has been ported to OpenCV. It is available natively in OpenCV.
http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html#fast
Compatibility > OpenCV 1.0
Files:
Download from DsynFLO box folder - https://app.box.com/s/h49lu1ht6mjbapym726z
Source Code:
//______________________________________________________________________________________ // Program : Corner Detection using OpenCV // Author : Bharath Prabhuswamy //______________________________________________________________________________________ #include <cv.h> #include <highgui.h> #include <stdio.h> bool find_corner(char* img_data,int img_width,int x,int y); // Routine to check whether a particular pixel is an Edgel or not // Start of Main Loop //------------------------------------------------------------------------------------------------------------------------ int main() { CvCapture* capture = 0; IplImage* img = 0; //IplImage* img = cvLoadImage("test3.jpg"); // for still image capture = cvCaptureFromCAM( 0 ); if ( !capture ) // Check for Camera capture return -1; cvNamedWindow("Camera",CV_WINDOW_AUTOSIZE); IplImage* gray = 0; IplImage* thres = 0; bool init = false; // Flag to identify initialization of Image objects if(init == false) { img = cvQueryFrame( capture ); // Query for the frame if( !img ) // Exit if camera frame is not obtained return -1; // Creation of Intermediate 'Image' Objects required later gray = cvCreateImage( cvGetSize(img), 8, 1 ); // To hold Grayscale Image thres = cvCreateImage( cvGetSize(img), 8, 1 ); // To hold OTSU thresholded Image init = true; } int ihist[256]; // Array to store Histogram values float hist_val[256]; // Array to store Normalised Histogram values int pos ; // Position or pixel value of the image float prbn; // First order cumulative float meanitr; // Second order cumulative float meanglb; // Global mean level int OPT_THRESH_VAL; // Optimum threshold value float param1,param2; // Parameters required to work out OTSU threshold algorithm double param3; int h,w; // Variables to store Image Height and Width h = img->height; // Height and width of the Image w = img->width; CvPoint corner; bool corner_flag; int key = 0; while(key != 'q') { //Step : Capture Image from Camera //Info : Inbuit function from OpenCV //Note : img = cvQueryFrame( capture ); // Query for the frame //Step : Convert Image captured from Camera to GrayScale //Info : Inbuit function from OpenCV //Note : Image from Camera and Grayscale are held using seperate "IplImage" objects cvCvtColor(img,gray,CV_RGB2GRAY); // Convert RGB image to Gray //Step : Threshold the image using optimum Threshold value obtained from OTSU method //Info : //Note : memset(ihist, 0, 256); for(int j = 0; j < gray->height; ++j) // Use Histogram values from Gray image { uchar* hist = (uchar*) (gray->imageData + j * gray->widthStep); for(int i = 0; i < gray->width; i++ ) { pos = hist[i]; // Check the pixel value ihist[pos] += 1; // Use the pixel value as the position/"Weight" } } //Parameters required to calculate threshold using OTSU Method prbn = 0.0; // First order cumulative meanitr = 0.0; // Second order cumulative meanglb = 0.0; // Global mean level OPT_THRESH_VAL = 0; // Optimum threshold value param1,param2; // Parameters required to work out OTSU threshold algorithm param3 = 0.0; //Normalise histogram values and calculate global mean level for(int i = 0; i < 256; ++i) { hist_val[i] = ihist[i] / (float)(w * h); meanglb += ((float)i * hist_val[i]); } // Implementation of OTSU algorithm for (int i = 0; i < 255; i++) { prbn += (float)hist_val[i]; meanitr += ((float)i * hist_val[i]); param1 = (float)((meanglb * prbn) - meanitr); param2 = (float)(param1 * param1) /(float) ( prbn * (1.0f - prbn) ); if (param2 > param3) { param3 = param2; OPT_THRESH_VAL = i; // Update the "Weight/Value" as Optimum Threshold value } } cvThreshold(gray,thres,OPT_THRESH_VAL,255,CV_THRESH_BINARY); //Threshold the Image using the value obtained from OTSU method int c = 0; for( int y = 0; y < thres->height; ++y) //Start full scan of the image by incrementing y { for(int x = 0; x < thres->width; ++x ) //Start full scan of the image by incrementing x { // Number of edgels in a particular blob corner_flag = find_corner(thres->imageData,thres->widthStep,x,y); if(corner_flag == true) // Check for the Edgel and update Edgel storage { c++; corner.x = x; corner.y = y; cvCircle(img,corner,1,CV_RGB(255,0,0),1,8); corner_flag = false; } } } cvShowImage( "Camera",img); key = cvWaitKey(1); // OPENCV: wait for 1ms before accessing next frame //key = cvWaitKey(50000); // for still image } // End of while loop cvDestroyWindow( "Camera" ); // Release various parameters cvReleaseImage(&img); cvReleaseImage(&gray); cvReleaseImage(&thres); return 0; } // End of Main Loop //------------------------------------------------------------------------------------------------------------------------ // Routine to check whether a particular pixel is an Edgel or not bool find_corner(char* img_data,int img_width,int x,int y) { const int wind_sz = 5 ; int wind_bnd = (wind_sz - 1) / 2; int sum = 0; bool result = false; uchar* ptr[wind_sz]; int index =0; for(int k = (0-wind_bnd); k <= wind_bnd; ++k) { ptr[index] = (uchar*)(img_data + (y + k) * img_width); index = index + 1 ; } for(int i = 0; i <= (wind_sz-1); ++i) { if((i == 0) || (i==(wind_sz-1))) { for (int j = (0-wind_bnd); j <= wind_bnd; ++j) { if(ptr[i][x+j] == 0) sum += 1; else continue; } } else { if(ptr[i][x-wind_bnd] == 0) sum += 1; else continue; if(ptr[i][x+wind_bnd] == 0) sum += 1; else continue; } } if((sum > 2 ) && (sum < 5)) { result = true; } return result; } // EOF