1 | initial version |
You are mixing contours and circles from HoughCircles in a obscure way. Detected circles OR contours and select your favourite.
circularity = 4 * PI * area / perimeter^2
CV_RETR_EXTERNAL
and forget forget about hierarchyobjectFound
id bad managed because it can become false after it has been true.here is a ready to use function for contour circularity
/**
* @brief Calculates circularity measure of a contour using common standard method
* The circularity is calculated with common method as relation between area and perimeter as:
*
* Circularity = (4 * PI * area) / (perimeter^2)
*
* @param [in]contour a vector of cv::Point
* @returns ranges over [0, 1] where 1 means that the contour is a perfect circle
* if area or perimeter is 0 than circularity will be 0
*
* @note this returns 0.785 for squares
*/
double CircularityStandard(double area,double perimeter)
{
if((area*perimeter)==0) return 0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
double CircularityStandard(const vector<cv::Point> &contour)
{
double area = cv::contourArea(contour);
if (area == 0) return 0.0;
double perimeter = cv::arcLength(contour, true);
if (perimeter == 0) return 0.0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
here is a code I could write
void trackFilteredObject(int &x, int &y, const Mat &threshold, Mat &cameraFeed)
{
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours ignores holes
cv::findContours(threshold, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if (contours.size() > MAX_NUM_OBJECTS)
{
putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
return;
}
double refArea = 0;
bool objectFound = false;
double circularity;
int largest = -1;
double minCircularity = 0.9; //use something > 0.85
for (int i = 0; i < contours.size(); i++)
{
// draw all contours in red
cv::drawContours(dst, contours, i, cv::Scalar(0, 0, 255), 1);
cv::Moments moment = moments(contours[i]);
double area = moment.m00;
double perimeter = cv::arcLength(contour[i], true);
//circularity = CircularityStandard(contours[i]); //alternative overload
circularity = CircularityStandard(area,perimeter);
if (circularity < minCircularity) //use something > 0.85
continue;
// draw all circles in blue
int cx = cvRound(moment.m10 / area);
int cy = cvRound(moment.m01 / area);
cv::Point center(x, y);
int radius = cvRound(sqrt(refArea / CV_PI));
// circle center
circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);
//if the area is less than 20 px by 20px then it is probably just noise
//if the area is the same as the 3/2 of the image size, probably just a bad filter
//object wanted with the largest area so a reference area is stored each
//iteration and compare it to the area in the next iteration.
if (area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA)
{
objectFound = true;
x = cx;
y = cy;
refArea = area;
}
}
//let user know you found an object
if (objectFound == true)
{
putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
//draw object location on screen
drawObject(x, y, cameraFeed);
}
}
Or you could use BlobDetector (as answerd here)
2 | No.2 Revision |
You are mixing contours and circles from HoughCircles in a obscure way. Detected circles OR contours and select your favourite.
circularity = 4 * PI * area / perimeter^2
CV_RETR_EXTERNAL
and forget forget about hierarchyobjectFound
id bad managed because it can become false after it has been true.here is a ready to use function for contour circularity
/**
* @brief Calculates circularity measure of a contour using common standard method
* The circularity is calculated with common method as relation between area and perimeter as:
*
* Circularity = (4 * PI * area) / (perimeter^2)
*
* @param [in]contour a vector of cv::Point
* @returns ranges over [0, 1] where 1 means that the contour is a perfect circle
* if area or perimeter is 0 <=0 than circularity will be 0
*
* @note this returns 0.785 for squares
*/
double CircularityStandard(double area,double perimeter)
{
if((area*perimeter)==0) if( (area<=0) || (perimeter<=0)) return 0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
double CircularityStandard(const vector<cv::Point> &contour)
{
double area = cv::contourArea(contour);
if (area == 0) return 0.0;
double perimeter = cv::arcLength(contour, true);
if (perimeter == 0) return 0.0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
here is a code I could write
void trackFilteredObject(int &x, int &y, const Mat &threshold, Mat &cameraFeed)
{
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours ignores holes
cv::findContours(threshold, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if (contours.size() > MAX_NUM_OBJECTS)
{
putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
return;
}
double refArea = 0;
bool objectFound = false;
double circularity;
int largest = -1;
double minCircularity = 0.9; //use something > 0.85
for (int i = 0; i < contours.size(); i++)
{
// draw all contours in red
cv::drawContours(dst, contours, i, cv::Scalar(0, 0, 255), 1);
cv::Moments moment = moments(contours[i]);
double area = moment.m00;
double perimeter = cv::arcLength(contour[i], true);
//circularity = CircularityStandard(contours[i]); //alternative overload
circularity = CircularityStandard(area,perimeter);
if (circularity < minCircularity) //use something > 0.85
continue;
// draw all circles in blue
int cx = cvRound(moment.m10 / area);
int cy = cvRound(moment.m01 / area);
cv::Point center(x, y);
int radius = cvRound(sqrt(refArea / CV_PI));
// circle center
circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);
//if the area is less than 20 px by 20px then it is probably just noise
//if the area is the same as the 3/2 of the image size, probably just a bad filter
//object wanted with the largest area so a reference area is stored each
//iteration and compare it to the area in the next iteration.
if (area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA)
{
objectFound = true;
x = cx;
y = cy;
refArea = area;
}
}
//let user know you found an object
if (objectFound == true)
{
putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
//draw object location on screen
drawObject(x, y, cameraFeed);
}
}
Or you could use BlobDetector (as answerd here)
3 | No.3 Revision |
You are mixing contours and circles from HoughCircles in a obscure way. Detected circles OR contours and select your favourite.
circularity = 4 * PI * area / perimeter^2
CV_RETR_EXTERNAL
and forget forget about hierarchyobjectFound
id bad managed because it can become false after it has been true.here is a ready to use function for contour circularity
/**
* @brief Calculates circularity measure of a contour using common standard method
* The circularity is calculated with common method as relation between area and perimeter as:
*
* Circularity = (4 * PI * area) / (perimeter^2)
*
* @returns ranges over [0, 1] where 1 means that the contour is a perfect circle
* if area or perimeter is <=0 than circularity will be 0
*
* @note this returns 0.785 for squares
*/
double CircularityStandard(double area,double perimeter)
{
if( (area<=0) || (perimeter<=0)) return 0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
double CircularityStandard(const vector<cv::Point> &contour)
{
double area = cv::contourArea(contour);
if (area == 0) return 0.0;
double perimeter = cv::arcLength(contour, true);
if (perimeter == 0) return 0.0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
here is a code I could writewrite (EDIT: small bug removed)
void trackFilteredObject(int &x, int &y, const Mat &threshold, Mat &cameraFeed)
{
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours ignores holes
cv::findContours(threshold, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if (contours.size() > MAX_NUM_OBJECTS)
{
putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
return;
}
double refArea = 0;
bool objectFound = false;
double circularity;
int largest = -1;
double minCircularity = 0.9; 0.85; //use something > 0.85
0.80
for (int i = 0; i < contours.size(); i++)
{
// draw all contours in red
cv::drawContours(dst, contours, i, cv::Scalar(0, 0, 255), 1);
cv::Moments moment = moments(contours[i]);
double area = moment.m00;
double perimeter = cv::arcLength(contour[i], true);
//circularity = CircularityStandard(contours[i]); //alternative overload
circularity = CircularityStandard(area,perimeter);
if (circularity < minCircularity) //use something > 0.85
0.80
continue;
// draw all circles in blue
int cx = cvRound(moment.m10 / area);
int cy = cvRound(moment.m01 / area);
cv::Point center(x, y);
center(cx, cy);
int radius = cvRound(sqrt(refArea cvRound(sqrt(area / CV_PI));
// circle center
circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);
//if the area is less than 20 px by 20px then it is probably just noise
//if the area is the same as the 3/2 of the image size, probably just a bad filter
//object wanted with the largest area so a reference area is stored each
//iteration and compare it to the area in the next iteration.
if (area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA)
{
objectFound = true;
x = cx;
y = cy;
refArea = area;
}
}
//let user know you found an object
if (objectFound == true)
{
putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
//draw object location on screen
drawObject(x, y, cameraFeed);
}
}
Or you could use BlobDetector (as answerd here)
4 | No.4 Revision |
You are mixing contours and circles from HoughCircles in a obscure way. Detected circles OR contours and select your favourite.
circularity = 4 * PI * area / perimeter^2
CV_RETR_EXTERNAL
and forget forget about hierarchyobjectFound
id bad managed because it can become false after it has been true.here is a ready to use function for contour circularity
/**
* @brief Calculates circularity measure of a contour using common standard method
* The circularity is calculated with common method as relation between area and perimeter as:
*
* Circularity = (4 * PI * area) / (perimeter^2)
*
* @returns ranges over [0, 1] where 1 means that the contour is a perfect circle
* if area or perimeter is <=0 than circularity will be 0
*
* @note this returns 0.785 for squares
*/
double CircularityStandard(double area,double perimeter)
{
if( (area<=0) || (perimeter<=0)) return 0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
double CircularityStandard(const vector<cv::Point> &contour)
{
double area = cv::contourArea(contour);
if (area == 0) return 0.0;
double perimeter = cv::arcLength(contour, true);
if (perimeter == 0) return 0.0;
return (4 * CV_PI*area) / (perimeter*perimeter);
}
here is a code I could write (EDIT: small bug removed)
result
void trackFilteredObject(int &x, int &y, const Mat &threshold, Mat &cameraFeed)
{
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours ignores holes
holes
cv::findContours(threshold, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if (contours.size() > MAX_NUM_OBJECTS)
{
putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
return;
}
double refArea = 0;
bool objectFound = false;
double circularity;
int //int largest = -1;
double minCircularity = 0.85; //use something > 0.80
0.85
for (int (size_t i = 0; i < contours.size(); i++)
{
// Mat src;
// Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
// draw all contours in red
cv::drawContours(dst, cv::drawContours(cameraFeed, contours, i, cv::Scalar(0, 0, 255), 1);
cv::Scalar(255, 255, 0), 2);
cv::Moments moment = moments(contours[i]);
double area = moment.m00;
double perimeter = cv::arcLength(contour[i], cv::arcLength(contours[i], true);
//circularity = CircularityStandard(contours[i]); //alternative overload
circularity = CircularityStandard(area,perimeter);
CircularityStandard(area, perimeter);
putText(cameraFeed, "Circularity="+to_string(circularity),
contours[i][0], 2, 1, Scalar(255, 255, 0), 1);
if (circularity < minCircularity) //use something > 0.80
0.85
continue;
// draw all circles in blue
int cx = cvRound(moment.m10 / area);
int cy = cvRound(moment.m01 / area);
cv::Point center(cx, cy);
int radius = cvRound(sqrt(area / CV_PI));
// circle center
circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);
//if the area is less than 20 px by 20px then it is probably just noise
//if the area is the same as the 3/2 of the image size, probably just a bad filter
//object wanted with the largest area so a reference area is stored each
//iteration and compare it to the area in the next iteration.
iteration.
if (area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA)
{
objectFound = true;
x = cx;
y = cy;
refArea = area;
}
}
//let user know you found an object
if (objectFound == true)
{
putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
//draw object location on screen
drawObject(x, y, cameraFeed);
}
imwrite("cameraFeed.jpg", cameraFeed);
}
Or you could use BlobDetector (as answerd here)