Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

opencv c++ find inscribing circle of a contour

I want to find the maximum inscribing circle of contour.

I have detected the contour with cv::findContours and it is there as a vector<Point>.

I know how to detect the minimum enclosing circle (cv::minEnclosingCircle), but not how to get the maximum inclosing circle. How to do this?

Question2: How do i get the inscribing and circumscribing circles centered on the center of mass?


For clarification, i try to describe, what i mean with these circels:

  1. min enclosing circle: touching object from outside, center position doesn't matter, minimum area.
  2. circumscribing circle: touching object from outside, center position on the center of mass of the object, minimum area.
  3. max inclosing circle: touching object from inside, center position doesn't matter, maximum area.
  4. inscribing circle: touching object from inside, center position on the center of mass of the object, maximum area.
like image 690
Kemendil Avatar asked Jan 01 '23 13:01

Kemendil


2 Answers

You can:

1) create a mask from your contour

enter image description here

2) Compute the distanceTransform on the mask

enter image description here

3) The highest value is the radius, its position is the center

enter image description here

Code:

#include <opencv2\opencv.hpp>

int main()
{
    // Load image
    cv::Mat1b img = cv::imread("path_to_img", cv::IMREAD_GRAYSCALE);

    // Correct image
    cv::Mat1b bin = img < 127;

    // Find contour
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // Draw on mask
    cv::Mat1b mask(bin.rows, bin.cols, uchar(0));
    cv::drawContours(mask, contours, 0, cv::Scalar(255), cv::FILLED);

    // Distance Trasnsform
    cv::Mat1f dt;
    cv::distanceTransform(mask, dt, cv::DIST_L2, 5, cv::DIST_LABEL_PIXEL);

    // Find max value
    double max_val;
    cv::Point max_loc;
    cv::minMaxLoc(dt, nullptr, &max_val, nullptr, &max_loc);

    // Output image
    cv::Mat3b out;
    cv::cvtColor(img, out, cv::COLOR_GRAY2BGR);
    cv::circle(out, max_loc, max_val, cv::Scalar(0, 255, 0));

    return 0;
}
like image 200
Miki Avatar answered Jan 26 '23 19:01

Miki


At least i solved the calculation of the two circles with the center on the center of mass (in a way similar to @Grillteller suggested):

Point2f p_Contour_first = vp_Contour[0];
double circumCirc_Radius  = norm(p_Centroid - p_Contour_first);
double inscriCirc_Radius  = norm(p_Centroid - p_Contour_first);
for(int p = 0; p < vp_Contour.size(); p++)
{
    Point2f p_Contour_current = vp_Contour[p];
    double r = norm(p_Centroid - p_Contour_current);
    if(r < inscriCirc_Radius) inscriCirc_Radius = r;
    if(r > circumCirc_Radius) circumCirc_Radius = r;
}

But the original question remeains (max area, center pos doesn't matter).

like image 45
Kemendil Avatar answered Jan 26 '23 19:01

Kemendil