简体   繁体   中英

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.

You can:

1) create a mask from your contour

在此输入图像描述

2) Compute the distanceTransform on the mask

在此输入图像描述

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

在此输入图像描述

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;
}

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).

@Miki's answer is great and extremely useful, I just spent a bit of time translating it into python, thought I should leave it here as well

#get maximum inscribed circle
#my input image is called "frame"
#get threshold image from frame

ret, thresh = cv2.threshold(frame, 100, 255, cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(thresh, 1, cv2.CHAIN_APPROX_NONE)

#create blank mask
mask = np.zeros(frame.shape[:2], dtype="uint8")
cv2.drawContours(mask, contours, -1, 255, -1)
dist = cv2.distanceTransform(mask, cv2.DIST_L2, 0)
NULL,max_val,NULL,max_indx=cv2.minMaxLoc(dist)

(x,y),radius = max_indx, max_val

#draw circle on original image
cv2.circle(frame, (x,y), radius, (0,255,0), 2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM