Created
February 13, 2013 14:14
-
-
Save Benjit87/4944898 to your computer and use it in GitHub Desktop.
/* http://benjithian.sg/2013/02/simple-convex-defect-opencv/
Simple Convex hull with Convex Defect. Simple stuff.
*/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
http://benjithian.sg/2013/02/simple-convex-defect-opencv/ | |
Simple Convex hull with Convex Defect. Simple stuff. | |
*/ | |
#include <stdio.h> | |
#include <curl/curl.h> | |
#include <sstream> | |
#include <iostream> | |
#include <vector> | |
#include <opencv2/opencv.hpp> | |
struct convexhull { | |
std::vector<std::vector<cv::Point> >hull; | |
std::vector<cv::Vec4i> defect; | |
int empty; | |
} ; | |
//curl writefunction to be passed as a parameter | |
size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata) { | |
std::ostringstream *stream = (std::ostringstream*)userdata; | |
size_t count = size * nmemb; | |
stream->write(ptr, count); | |
return count; | |
} | |
//Some of the Convex Hull Code from http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/hull/hull.html | |
convexhull contourImg(cv::Mat src) { | |
convexhull convexhull1; | |
std::vector<std::vector<cv::Point> > contours; | |
std::vector<cv::Vec4i> hierarchy; | |
cv::findContours(src, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); | |
/// Find the convex hull object for each contour | |
std::vector<std::vector<cv::Point> >hull( contours.size() ); | |
for( int i = 0; i < contours.size(); i++ ) | |
{ | |
cv::convexHull( cv::Mat(contours[i]), hull[i], false ); // false as i want clockwise | |
} | |
int largestarea = 0; // to hold the convex with largest area | |
int areaCount = -1; // hold the hull number with the largest area | |
for(int i = 0; i < hull.size();i++) | |
{ | |
std::vector<cv::Point> hull1 = hull[i]; | |
int area = 0; | |
// I use trapezium formula to find the area of each 2 points | |
// the top trapezium will the + and the bottom trapezium will be - | |
// the difference will be the area | |
for ( int j = 0 ; j < hull1.size()-1 ; j++ ) | |
{ | |
cv::Point point1 = hull1[j]; // current point | |
cv::Point point2 = hull1[j+1]; // next point | |
int area1 = (point1.y + point2.y) * (point1.x-point2.x); // area | |
area += area1; // add them up | |
} | |
if ( largestarea < area ) { largestarea = area;areaCount=i; } //find largest area | |
} | |
if ( areaCount == -1 ) //return an empty vector if there is no hull | |
{ | |
convexhull1.empty = 1; // hull empty | |
return convexhull1; | |
} | |
//Convex Defect | |
std::vector<cv::Vec4i> defect; | |
std::vector<int> convexHull_IntIdx; | |
if (largestarea > 0 && contours[areaCount].size() > 3) // if there is a largest area and the size of it is have more than 3 points | |
{ | |
cv::convexHull(contours[areaCount], convexHull_IntIdx, true); // generate indices of convex hull | |
cv::convexityDefects(contours[areaCount],convexHull_IntIdx,defect); // get the defects | |
} | |
std::vector<std::vector<cv::Point> >hull1(0); //create a vector to hold the hull with the largest area | |
hull1.push_back(hull[areaCount]);// insert the largest hull | |
hull1.push_back(contours[areaCount]); // insert the largest contour | |
convexhull1.defect = defect; | |
convexhull1.hull = hull1; | |
convexhull1.empty = 2; // hull not empty | |
return convexhull1; | |
} | |
//function to retrieve the image as Cv::Mat data type | |
cv::Mat curlImg() | |
{ | |
CURL *curl; | |
CURLcode res; | |
std::ostringstream stream; | |
curl = curl_easy_init(); | |
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.0.104:8080/shot.jpg"); //the JPEG Frame url | |
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // pass the writefunction | |
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); // pass the stream ptr when the writefunction is called | |
res = curl_easy_perform(curl); // start curl | |
std::string output = stream.str(); // convert the stream into a string | |
curl_easy_cleanup(curl); // cleanup | |
std::vector<char> data = std::vector<char>( output.begin(), output.end() ); //convert string into a vector | |
cv::Mat data_mat = cv::Mat(data); // create the cv::Mat datatype from the vector | |
cv::Mat image = cv::imdecode(data_mat,1); //read an image from memory buffer | |
return image; | |
} | |
int main(void) | |
{ | |
cv::namedWindow( "Image output", CV_WINDOW_AUTOSIZE ); | |
int i = 1; | |
cv::Mat image = curlImg(); // get the image frame | |
while(1) | |
{ | |
if ( i == 1 ) // Update the background every 100*33ms | |
{ | |
i = 100; | |
image = curlImg(); // get the image frame | |
cv::cvtColor(image,image, CV_BGR2GRAY);//Convert to GreyScale | |
} | |
i--; | |
char c = cvWaitKey(33); // sleep for 33ms or till a key is pressed (put more then ur camera framerate mine is 30ms) | |
cv::Mat image2 = curlImg(); // the image that is constantly being updated | |
cv::Mat image3 = image2.clone(); | |
cv::cvtColor(image2,image2, CV_BGR2GRAY);//Convert to GreyScale | |
cv::absdiff(image,image2,image2);// Absolute differences between the 2 images | |
cv::blur(image2,image2,cv::Size(10,10)); // Try to elimite stray patch | |
cv::threshold(image2,image2,5,255,CV_THRESH_BINARY); // set threshold to ignore small differences you can also use inrange function | |
convexhull hull = contourImg(image2); | |
/// Draw contours + hull results | |
if (hull.empty == 2 ) | |
{ | |
cv::Scalar color1 = cv::Scalar( 255, 0, 0 ); // blue | |
cv::drawContours( image3, hull.hull, 0, color1, 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point() ); // draw the hull | |
cv::Scalar color2 = cv::Scalar( 0, 255, 0 ); // green | |
cv::drawContours( image3, hull.hull, 1, color2, 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point() ); // draw the contours | |
cv::Scalar color3 = cv::Scalar( 0, 0, 255 ); // red | |
for ( int i = 0; i < hull.defect.size() ; i++) | |
{ | |
cv::Matx<int,4,1> defectVector = hull.defect[i]; // get the 4x1 vector | |
std::vector<cv::Point> hull1 = hull.hull[1]; // get the contour | |
cv::Point point1 = hull1[defectVector.val[2]]; | |
if ( defectVector.val[3] <= 1000 ) { continue; } // skip defects that are shorter than 100 pixel | |
cv::circle(image3, point1, 5, color3); // draw a circle on the defect which has the furthest distance | |
} | |
cv::imshow("Image output",image3); // display image | |
} // end of hullempty = 1 | |
c = cvWaitKey(33); | |
if ( c == 27 ) break; // break if ESC is pressed | |
} | |
cv::destroyWindow("Image output"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment