Skip to content

Instantly share code, notes, and snippets.

@Benjit87
Created February 13, 2013 14:14
Show Gist options
  • Save Benjit87/4944898 to your computer and use it in GitHub Desktop.
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. */
/*
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