0

I want to draw the ellipse contour around the given figure append below. I am not getting the correct result since the figure consist of two lines.

I have tried the following:-

  1. Read the Image
  2. Convert the BGR to HSV
  3. Define the Range of color blue
  4. Create the inRange Mask to capture the value of between lower and upper blue
  5. Find the contour & Draw the fit ellipse.

Here is the source code-

import cv2
import numpy as np

image=cv2.imread('./source image.jpg')

hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

lower_blue= np.array([75, 0, 0])
upper_blue= np.array([105, 255, 255])

mask = cv2.inRange(hsv, lower_blue, upper_blue)
res=cv2.bitwise_and(image,image,mask=mask)
_,contours,_=cv2.findContours(close,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

ellipse = cv2.fitEllipse(max(contours,key=cv2.contourArea))
cv2.ellipse(image,ellipse,(0,255,0),2)

cv2.imshow('mask',image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The figure/Image below show the Expected & Actual Output-

Expected & Actual display image

Source Image Source Image

Output Contour Array Contour file

Community
  • 1
  • 1
Monk247uk
  • 1,170
  • 1
  • 8
  • 15
  • 1
    Can you add the source image for us to try with? Also, why are you sorting the contours just to pull a single one out? Use `max()` instead, it can also take a `key` function :) – alkasm Feb 12 '19 at 06:38
  • Try to visualize mask image and drawContours on it. – Nuzhny Feb 12 '19 at 06:39
  • 1
    You have the expected and actual result image, which is great, but I meant the input image with neither circle drawn on it. – alkasm Feb 12 '19 at 07:36
  • @AlexanderReynolds Source/ Input Image added below – Monk247uk Feb 12 '19 at 07:47
  • Try to apply cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) before findContours. And don't use bitwise_and – Nuzhny Feb 12 '19 at 09:16
  • @Nuzhny I have used bitwise_and for the general case scenario as if we are dealing with colored concentric ellipses. – Monk247uk Feb 12 '19 at 09:25
  • can you upload a contour image? fitEllipse will expect the whole input being an ellipse, just as line fitting will have problems with outliers, ellipse fitting will have, too. Maybe you can use the code of the answer here to prepocess your contour, to get better input data for ellipse fitting? https://stackoverflow.com/questions/35226993/how-to-crop-away-convexity-defects – Micka Feb 12 '19 at 09:38
  • @Micka Source/Input, Actual and Excepted image with contour are appended below. – Monk247uk Feb 12 '19 at 10:01
  • @NuzhnyI have updated the source/input to get a generalized result. Try to run the code with this image – Monk247uk Feb 12 '19 at 10:04
  • 1
    Note that your current set of code doesn't run; `close` is not defined. – alkasm Feb 12 '19 at 10:17
  • @AlexanderReynolds try with edited code and input image for better interpretation. – Monk247uk Feb 12 '19 at 10:23
  • 1
    Yes---it doesn't run. There are multiple undefined variables; please copy and paste the code in your post and see :) – alkasm Feb 12 '19 at 10:25
  • @AlexanderReynolds Copy the code again and use the correct Input image path. Then Run the code and check whether it's working or not – Monk247uk Feb 12 '19 at 10:33
  • 1
    @MayankPratapSingh I have seen the input images, but not the contours (I don't have time to compile/run your code atm, sorry) - the result of bitwise-operation and findContours, drawn on an empty image, or at least the input that you send to findContours. This will give more information about, that kind of input to fitEllipse is presented. – Micka Feb 12 '19 at 10:33
  • @Micka Appended contour output file. – Monk247uk Feb 12 '19 at 11:13
  • @MayankPratapSingh I'm adding convexHull and update my C++ code with new result – Nuzhny Feb 13 '19 at 11:43

1 Answers1

-1

I try to run your code on C++ and add erosion, dilatation and convexHull for result contour:

auto DetectEllipse = [](cv::Mat rgbImg, cv::Mat hsvImg, cv::Scalar fromColor, cv::Scalar toColor)
{
    cv::Mat threshImg;
    cv::inRange(hsvImg, fromColor, toColor, threshImg);
    cv::erode(threshImg, threshImg, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)), cv::Point(-1, -1), 2);
    cv::dilate(threshImg, threshImg, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)), cv::Point(-1, -1), 2);

    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(threshImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);

    int areaThreshold = (rgbImg.cols * rgbImg.rows) / 100;

    std::vector<cv::Point> allContours;
    allContours.reserve(10 * areaThreshold);

    for (size_t i = 0; i < contours.size(); i++)
    {
        if (contours[i].size() > 4)
        {
            auto area = cv::contourArea(contours[i]);
            if (area > areaThreshold)
            {
                allContours.insert(allContours.end(), contours[i].begin(), contours[i].end());
            }
        }
    }
    if (allContours.size() > 4)
    {
        std::vector<cv::Point> hull;
        cv::convexHull(allContours, hull, false);

        cv::ellipse(rgbImg, cv::fitEllipse(hull), cv::Scalar(255, 0, 255), 2);
    }
};

cv::Mat rgbImg = cv::imread("h8gx3.jpg", cv::IMREAD_COLOR);
cv::Mat hsvImg;
cv::cvtColor(rgbImg, hsvImg, cv::COLOR_BGR2HSV);

DetectEllipse(rgbImg, hsvImg, cv::Scalar(75, 0, 0), cv::Scalar(105, 255, 255));
DetectEllipse(rgbImg, hsvImg, cv::Scalar(10, 100, 20), cv::Scalar(25, 255, 255));

cv::imshow("rgbImg", rgbImg);
cv::waitKey(0);

Result looks correct: enter image description here

Nuzhny
  • 1,869
  • 1
  • 7
  • 13