Drawing inscribing circle into thresholded image

杀马特。学长 韩版系。学妹 提交于 2021-01-28 12:47:42

问题


I am trying to draw max inscribing circle into thresholded (contoured) image to extract the palmar part of the hand.

Original image 1:

My code:

import cv2
import imutils

pathToThePhoto = 'hand.jpg'

#Load the photo
img = cv2.imread(pathToThePhoto)

#Converting the image into gray colour
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Thresholding the image
thresh = cv2.threshold(gray, 100 , 255, cv2.THRESH_BINARY)[1]

cv2.imshow("thresholded", thresh)

#Find contours in thresholded image
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

#Draw the contours into the gray image 
c = max(cnts, key=cv2.contourArea)
mask = cv2.drawContours(gray, [c], -1, (0,255,0), 2)

cv2.imshow("contours", mask)

#Apply the distance transform for mask 
out = cv2.distanceTransform(mask, distanceType=cv2.DIST_L2, maskSize=5)
out = cv2.normalize(out, out, 0.0, 1.0, cv2.NORM_L2)

cv2.imshow("distanceTransform", out)

#Get the information about position 
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(out) #Actual values 0.0 0.0 (0, 0) (0, 0)

#Draw the circle into original image
img = cv2.circle(img, max_loc , int(max_val) , (255, 255, 0), 10)

cv2.imshow("img_with_circle", img)

Full code:

import cv2
import imutils

pathToThePhoto = 'hand.jpg'

img = cv2.imread(pathToThePhoto)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 100 , 255, cv2.THRESH_BINARY)[1]

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

c = max(cnts, key=cv2.contourArea)
mask = cv2.drawContours(gray, [c], -1, (0,255,0), 2)
out = cv2.distanceTransform(mask, distanceType=cv2.DIST_L2, maskSize=5)
out = cv2.normalize(out, out, 0.0, 1.0, cv2.NORM_L2)

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(out)

print(min_val, max_val, min_loc, max_loc)
img = cv2.circle(img, max_loc , int(max_val) , (255, 255, 0), 10)

cv2.imshow("thresholded", thresh)
cv2.imshow("contours", mask)
cv2.imshow("distanceTransform", out)
cv2.imshow("img_with_circle", img)

cv2.waitKey(0)
cv2.destroyAllWindows()

Result should be:

But the distanceTransform function isn't working. What is wrong?

1 Ajay Kumar. IIT Delhi Palmprint Image Database version 1.0. 2007


回答1:


distanceTransform assumes 0 input = 0 distance. Not sure whether it works with your input image (where you've drawn the black outline, I typically use masks as input.

Here's C++ code, but it is similar to your python code, but used a mask with solid drawn biggest conotur as input to distance transform:

int main()
{
    cv::Mat in = cv::imread("C:/StackOverflow/Input/dtInput.png", cv::IMREAD_GRAYSCALE);

    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(in.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    if (contours.size() == 0) return 0;
    int cIndex = 0;

    for (int i = 1; i < contours.size(); ++i)
    {
        if (cv::contourArea(contours[i]) > cv::contourArea(contours[cIndex]))
            cIndex = i;
    }

    cv::Mat tmp = cv::Mat::zeros(in.size(), CV_8UC1);
    cv::drawContours(tmp, contours, cIndex, cv::Scalar::all(255), -1);

    cv::Mat dist;

    cv::distanceTransform(tmp, dist, CV_DIST_L2, 5);

    double minVal, maxVal;
    cv::Point minLoc, maxLoc;
    cv::minMaxLoc(dist, &minVal, &maxVal, &minLoc, &maxLoc);


    cv::Mat bgr;
    cv::cvtColor(in, bgr, cv::COLOR_GRAY2BGR);
    cv::circle(bgr, maxLoc, maxVal, cv::Scalar(0, 0, 255), 3);

    cv::imshow("dist", 1.0/255.0 *dist);
    cv::imshow("result", bgr);


    cv::imwrite("C:/StackOverflow/Input/dtInput_res.png", bgr);
    cv::imwrite("C:/StackOverflow/Input/dtInput_dt.png", dist);

    cv::waitKey(0);
}

Giving these results:

dt input:

distance transform:

result:



来源:https://stackoverflow.com/questions/61211151/drawing-inscribing-circle-into-thresholded-image

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!