Friday, June 14, 2013

OpenCV - Canny Edge, Finding Contours, and Blending example

Intro

This is my first OpenCV example.  I want to learn more about how to manipulate images or data in images.  As with almost all projects, it is easiest to learn through application.  Through small amounts of searching, I was directed to OpenCV.  The whole project has been fun.

// For those of you who want to skip to the code section, scroll down to the last section named, "Code Section"

Goal

The goal is to gain some very basic familiarity with OpenCV, its types, and its setup and demonstrate this by combining several tutorials/examples.  As a source of input, I used a video file.  For each frame, we will make two copies of the frame.  In one frame, we will use the Canny Edge tutorial (listed below) in order to find edges in the frame.  In the other frame, we will use the Finding Contours in Your Image tutorial (listed below) in order to find contours in the frame.  After we have manipulated the two frames, we will blend them together (add both frames to a new frame) and present this blended frame to the user as the output.  

Hiccups

There were some minor problems encountered when setting up OpenCV and also getting my first programs running.  While I said that the whole project was fun, sometimes it was fun yet frustrating (funstrating?).  Fortunately, all problems that I encountered have been solved before by others and posted online.  I would post the issues, but they were all minor environment related issues.    

The Other Section 

I am using Ubuntu 13.04 on an i3.  Everything was written using gedit.  As the source for my video, a Mass Effect 3 trailer was used.  It was downloaded from YouTube using the Firefox add-on "Video DownloadHelper".

Mass Effect 3 Trailer
http://www.youtube.com/watch?v=eBktyyaV9LY&feature=share&list=PLBF461FAE966EAF93

Video DownloadHelper
https://addons.mozilla.org/en-US/firefox/addon/video-downloadhelper/


Reapers...

Its everyone's favorite time, demo time!  Below are the four versions for demo: the original (from bioware), canny edges, contour detection, and blended version (my favorite).

Original (from Bioware)


Canny Edges



Contour Detection



Blended (finished product)



Corrections?

This isn't a tutorial, it's an example of examples for the purpose of learning.  If there is something that is incorrect or could use improvement, let me know.  Thanks!

All Sources Used

There were many source and examples followed (listed below) in order to get to this point.  Thank you to anyone involved in making these.

OpenCV tutorials
http://docs.opencv.org/doc/tutorials/tutorials.html

Installation in Linux
http://docs.opencv.org/doc/tutorials/introduction/linux_install/linux_install.html#linux-installation

Using OpenCV with gcc and CMake
http://docs.opencv.org/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.html#linux-gcc-usage

Learning OpenCV: Computer Vision with the OpenCV Library
     by Gary Bradski and Adrian Kaehler
     Published by O'Reilly Media, October 3, 2008
   AVAILABLE AT:
     http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
     Or: http://oreilly.com/catalog/9780596516130/
     ISBN-10: 0596516134 or: ISBN-13: 978-0596516130

OpenCV tutorials
http://docs.opencv.org/doc/tutorials/tutorials.html

Canny Edge Detector
http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.html#canny-detector

Finding Contours in your Image  
http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html#find-contours

Adding (blending) two images using OpenCV
http://docs.opencv.org/doc/tutorials/core/adding_images/adding_images.html

Code Section

To use, pass in the name of the video file as an argument. (Example:  ./combinedDemo me3.mp4 )

 /**  
  * @file combinedDemo.cpp  
  * @date 14 June, 2013  
  * @author S. O'Bryan ( based on the sources below )  
  * @brief Created for learning purposes. Combining the tutorials and examples from the below sources to find edges and contours in an image    
  * and blend the two images together into one output image. Image source is a video file.   
  * @sources   
  * Learning OpenCV: Computer Vision with the OpenCV Library  
    by Gary Bradski and Adrian Kaehler  
    Published by O'Reilly Media, October 3, 2008   
   
   AVAILABLE AT:   
    http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134  
    Or: http://oreilly.com/catalog/9780596516130/  
    ISBN-10: 0596516134 or: ISBN-13: 978-0596516130    
        
   OpenCV tutorials (OpenCV 2.4.5)  
   http://docs.opencv.org/doc/tutorials/tutorials.html  
   
   Canny Edge Detector  
   http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.html#canny-detector  
   
   Finding Contours in your Image    
   http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html#find-contours  
   
   Adding (blending) two images using OpenCV  
   http://docs.opencv.org/doc/tutorials/core/adding_images/adding_images.html  
   
  */  
 #include "opencv2/objdetect/objdetect.hpp"  
 #include "opencv2/highgui/highgui.hpp"  
 #include "opencv2/imgproc/imgproc.hpp"  
 #include "opencv2/core/core.hpp"  
   
 #include "opencv2/highgui/highgui_c.h"  
   
 #include <iostream>  
 #include <stdio.h>  
   
 using namespace std;  
 using namespace cv;  
   
 /** All Function Headers */  
 void CannyThreshold(int, void*);  
 void thresh_callback(int, void* );  
   
 /// Global variables  
 char* target_window = "Output";  
   
 /// Edge detection globals  
 Mat srcEdge, srcEdge_gray;  
 Mat dstEdge, detected_edges;  
   
 int edgeThresh = 1;  
 int lowThreshold;  
 int const max_lowThreshold = 100;  
 int ratio = 3;  
 int kernel_size = 3;  
   
   
 /// contour detection globals  
 Mat srcContour; Mat srcContour_gray, drawing;  
 int thresh = 100;  
 int max_thresh = 255;  
 RNG rng(12345);  
   
 /// blend globals  
 Mat output;  
 double alpha = 0.5;   
 double beta = ( 1.0 - alpha );  
   
   
 /**  
  * @function main  
  */  
 int main( int argc, char** argv ) {   
     
   namedWindow( target_window, CV_WINDOW_AUTOSIZE );  
   CvCapture* capture = cvCreateFileCapture( argv[1] );  
   IplImage* frame;  
   
   while(1) {  
     frame = cvQueryFrame( capture );  
        
      // convert frame to Mat object used for edge detection  
      srcEdge = cv::cvarrToMat(frame);  
        
      // convert frame to Mat object used for contour detection  
      srcContour = cv::cvarrToMat(frame);  
        
      // frame check  
     if( !frame ) break;  
   
      /// contour detection  
      /// Convert image to gray and blur it  
      cvtColor( srcContour, srcContour_gray, CV_BGR2GRAY );  
       blur( srcContour_gray, srcContour_gray, Size(3,3) );  
       createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );  
       thresh_callback( 0, 0 );  
   
   
      /// edge detection  
      /// Create a matrix of the same type and size as src (for dst)  
       dstEdge.create( srcEdge.size(), srcEdge.type() );  
   
       /// Convert the image to grayscale  
       cvtColor( srcEdge, srcEdge_gray, CV_BGR2GRAY );  
   
       /// Show the image  
       CannyThreshold(0, 0);      
    
      // we have two Mat objects to blend - dstEdge and drawing  
       addWeighted( dstEdge, alpha, drawing, beta, 0.0, output);  
   
      // Show the final output       
      imshow( target_window, output );  
   
      // esc for escape  
      char c = cvWaitKey(33);  
     if( c == 27 ) break;  
   }  
   cvReleaseCapture( &capture );  
   cvDestroyWindow( target_window );  
 }  
   
 /** @function thresh_callback */  
 void thresh_callback(int, void* )  
 {  
  Mat canny_output;  
  vector<vector<Point> > contours;  
  vector<Vec4i> hierarchy;  
   
  /// Detect edges using canny  
  Canny( srcContour_gray, canny_output, thresh, thresh*2, 3 );  
  /// Find contours  
  findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );  
   
  /// Draw contours  
  drawing = Mat::zeros( canny_output.size(), CV_8UC3 );  
  for( int i = 0; i< contours.size(); i++ )  
    {  
     Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );  
     drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );  
    }  
 }  
   
 /**  
  * @function CannyThreshold  
  * @brief Trackbar callback - Canny thresholds input with a ratio 1:3  
  */  
   
 void CannyThreshold(int, void*)  
 {  
  /// Reduce noise with a kernel 3x3  
  blur( srcEdge_gray, detected_edges, Size(3,3) );  
   
  /// Canny detector - number has replaced lowThreshold  
  Canny( detected_edges, detected_edges, 50, lowThreshold*ratio, kernel_size );  
   
  /// Using Canny's output as a mask, we display our result  
  dstEdge = Scalar::all(0);  
   
  srcEdge.copyTo( dstEdge, detected_edges);  
   
  }  
   


No comments:

Post a Comment