Pages - Menu

Saturday, July 26, 2014

OpenCV: 'FAST' like Corner detection with scanning window

    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
 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

OpenCV: Implementation of Threshold by OTSU method





Here is a simple example showing implementation of OTSU thresholding in OpenCV.

Note: OTSU threshold available in  OpenCV via the function threshold() and by using the pre-defined operand THRESH_OTSU
http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#threshold

Compatibility  > OpenCV 1.0

Files:
Download from DsynFLO box folder - https://app.box.com/s/zzpm5yawbkin5fdbqutl
 
Source Code:
//______________________________________________________________________________________
// Program : OpenCV Otsu Thresholding
// Author  : Bharath Prabhuswamy
//______________________________________________________________________________________

#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main ( int argc, char **argv )
{
 CvCapture* capture = 0;
 IplImage* img = 0;

 capture = cvCaptureFromCAM( 0 );
 if ( !capture )            // Check for Camera capture
  return -1;

 cvNamedWindow("Camera",CV_WINDOW_AUTOSIZE);
 cvNamedWindow("Threshold",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;

 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

  cvShowImage( "Camera",img);
  cvShowImage( "Threshold",thres);

  key = cvWaitKey(1); // OPENCV: wait for 1ms before accessing next frame

 } // End of while loop

 cvDestroyWindow( "Camera" ); // Release various parameters
 cvReleaseImage(&img);
 cvReleaseImage(&gray);
 cvReleaseImage(&thres);
     return 0;
}
// End of Main Loop
//------------------------------------------------------------------------------------------------------------------------

OpenCV: Build a simple OpenCV program using CMake in Ubuntu


Building on our progress with usage of OpenCV, a demo on how to build and run a C++ based OpenCV program is described below.

To understand whats happing under the hood we shall dig up some basics -
g++ is GNU compiler for C++. Capable of generating both program object files and Executables
Make is a Build Tool that generates executables also by invoking g++
CMake , I would prefer to call it as Build Environment Tool that manages and assists the Build Process

CMake is a tool that takes care of managing what are the key requisites for the source to be compiled. More often than not, the source are dependent on other sources that have their own stipulations and methods to build them.  Usually the build requirements of these components are mentioned in their respective 'CMakeLists'. Thus combining the 'CMakeLists' of the program and dependent sources,  CMake makes it easier to manage and mitigate the task of providing and maintaining these component specific build requirements. This way the programmer can focus more on the necessities of the program rather than the needs of its dependent components. Further more, a well written CMake file makes the sources portable for building across platforms.

Quick Bullets:
Author --> Creates a program and CMakeList.txt
CMake and CMakeList.txt --> Generates Build Parameters [Makefile] for Build tools
Make and Makefile --> Generates Compiler Parameters and Invokes g++
g++ and Compiler Options --> Generates Object files and Executables

A simple diagram  might provide more clarity. See below -



Let us call our sample program as 'display_code.cpp' and the executable as 'display'

Create simple OpenCV program named 'display_code.cpp' [Note: Using legacy OpenCV 1.0 API]
#include <cv.h>
#include <highgui.h>

int main(int argc, char** argv )
{
 IplImage* img = cvLoadImage("nexus.jpg");
 cvNamedWindow("Image",CV_WINDOW_AUTOSIZE);
 cvShowImage( "Image",img);
 int key = cvWaitKey(0);

 cvDestroyWindow( "Image" );
 cvReleaseImage(&img);
}

Create 'CMakeLists.txt'
cmake_minimum_required(VERSION 2.8)
project( display )
find_package( OpenCV REQUIRED )
add_executable( display display_code.cpp )
target_link_libraries( display ${OpenCV_LIBS} )

Build the application
cmake .

make

Run the application
./display

OR
Using g++ directly
g++ display_code.cpp -o display `pkg-config --cflags --libs opencv`
./display

Result:


Files:
Download from DsynFLO box folder - https://app.box.com/s/yn3lwcmx1sv4slz0wfru

Further Reading:
GCC and Make : http://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
Writing Makefiles : https://www.cs.bu.edu/teaching/cpp/writing-makefiles/
Follow the informative answer explaining  'CMake' and 'Make' here - http://stackoverflow.com/a/19266355

Sunday, July 20, 2014

Installing OpenCV 2.4.9 in Ubuntu 14.04


In the previous post information on Ubuntu installation was shared, in this post we shall see how to install OpenCV in Ubuntu 14.04.

Note : The Instructions are from the site below. The same has been posted here for reference -
http://www.sysads.co.uk/2014/05/install-opencv-2-4-9-ubuntu-14-04-13-10/

Step 1 The first step here is the most important step. And the first step is to update the list of package repositories. This will come in handy while installing latest packages and their dependencies described in upcoming steps.
sudo apt-get update
This will take a while. I would suggest a cup of coffee.

Step 2 Remove previously installed FFMPEG and x264 libraries
sudo apt-get remove ffmpeg x264 libx264-dev

Step 3 Once this is completed, install the necessary packages for compiling openCV sources
Note: The package “ocl-icd-libopencl1” is selected for the following installation as my system does not contain NVIDIA graphics card. If your system has NVIDIA card then install ‘libopencv-dev’ instead of
‘ocl-icd-libopencl1’.
sudo apt-get install ocl-icd-libopencl1 build-essential checkinstall cmake pkg-config 
yasm libjpeg-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev 
libdc1394-22-dev libxine-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev 
libv4l-dev python-dev python-numpy libtbb-dev libqt4-dev libgtk2.0-dev libfaac-dev 
libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev 
libxvidcore-dev x264 v4l-utils 

Notice most of the packages are already installed during Ubuntu Installation. If not it will be installed now anyway.

Note: In this sample, the system contains AMD [ATI Radeon] graphics card


Step 4 Make a directory to download and build OpenCV
mkdir opencv
cd /opencv/

Step 5 Download the OpenCV sources for linux or Click here to start download. Unzip the OpenCV Sources.
wget -O OpenCV-2.4.9.zip http://fossies.org/linux/misc/opencv-2.4.9.zip
unzip OpenCV-2.4.9.zip
cd opencv-2.4.9

Step 6 Create a directory for compiling the sources
mkdir build
cd build

Step 7 Start building sources using CMAKE and install.

Important !! Make sure that the hierarchical path to the OpenCV sources does not contain any spaces.
Ex:
/home/bhp/my stuff/opencv src compilation/opencv2.4.9 <<--incorrect
/home/bhp/my_stuff/opencv/opencv2.4.9/                <<--better

Now compile the sources with all support and install
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON 
-D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D INSTALL_C_EXAMPLES=ON 
-D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..

The next step will take a while. Use multiple jobs to 'make' faster. [Ex: make -j8]
make
sudo make install

sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig

Step 8 Reboot the system for everything to take effect.

Step 9 Run an example C++ code provided with OpenCV Sources
cd /usr/local/share/OpenCV/samples/cpp
g++ houghlines.cpp -o application `pkg-config --cflags --libs opencv`
./application

Result

Saturday, July 19, 2014

Installing Ubuntu 14.04 LTS


Before we get on to the exciting stuff (- coming soon!!), we shall get started with installation of Ubuntu. So head over to Ubuntu site to download the CD/DVD image and follow the official guide for installation.

Ubuntu Desktop Images
http://www.ubuntu.com/download/desktop

Ubuntu Official Installation Guide
http://www.ubuntu.com/download/desktop/install-ubuntu-desktop

For installing Ubuntu alongside Windows follow the video tutorial below -


Caution: In case you have multiple Hard disk drives in your system, and you falter while picking the right Hard disk for Ubuntu installation, you can still recover the NTFS partition table and some of the partitions other than the region where Ubuntu was installed. You can do that by using “MiniTool Partition Wizard” which will allow you to restore lost partitions by scanning entire drive space.

Note: If the data is not overwritten on the disk space but if the partitions are lost, then the data is still intact and only the partition table needs to be restored.
Note 2: MiniTool is a shareware, it allows users to restore partitions but does not allow recovery of files with trail version. However restoring of Partition table is possible with trail version.

Links:
MiniTool Partition Wizard (Shareware)
http://www.partitionwizard.com/free-partition-manager.html

Ubuntu + Windows Dual boot video tutorial
https://www.youtube.com/watch?v=hOz66FC0pWU

Wednesday, July 9, 2014

Enter the Orange: Xiaomi finally enters India with MI3


    After waiting for an eternity, Xiaomi have decided to launch MI3 in India starting on July 15th 2014. I have been a big fan of MIUI and availability of official MIUI supported device locally is thing to cheer for. I have to proclaim that MIUI group has been more creative community from very early stages. MIUI has been the top variety of Android Custom Skin. Vanilla version on its own and Cyanogenmod do not bring the appeal to use Android much, neither have Samsung TouchWiz and Sony's skin [Xperia?]. Off late, HTC Sense and LG Optimus UI have given some sort of direction for Android L to progress with. But MIUI's blend of iOS elegance and Android's versatility has a special place and a highly devoted fanclub.
 The segment (between Rs.10k to Rs.26k) was initially dominated by Samsung with Grand variants is now smeared by Micromax which is seeded to become India's top mobile vendors. Xiaomi's entry into Indian market at the price of  Rs.14999 will be highly competitive.

Xiaomi Mi3 India: http://www.mi.com/in/
Xiaomi Mi3 Global: http://www.mi.com/en/mi3
MIUI ROMS: http://en.miui.com