# Buggy code
def ellipse(img, x, y, r1, r2, angle):
    """Create an elliptical ROI.

    Inputs:
    img           = An RGB or grayscale image to plot the ROI on in debug mode.
    x             = The x-coordinate of the center of the ellipse.
    y             = The y-coordinate of the center of the ellipse.
    r1            = The radius of the major axis.
    r2            = The radius of the minor axis.
    angle         = The angle of rotation in degrees of the major axis.

    Outputs:
    roi_contour   = An ROI set of points (contour).
    roi_hierarchy = The hierarchy of ROI contour(s).

    :param img: numpy.ndarray
    :param x: int
    :param y: int
    :param r1: int
    :param r2: int
    :param angle: double
    :return roi_contour: list
    :return roi_hierarchy: numpy.ndarray
    """
    # Autoincrement the device counter
    params.device += 1

    # Get the height and width of the reference image
    height, width = np.shape(img)[:2]

    # Initialize a binary image of the ellipse
    bin_img = np.zeros((height, width), dtype=np.uint8)
    # Draw the ellipse on the binary image
    cv2.ellipse(bin_img, (x, y), (r1, r2), angle, 0, 360, 255, -1)

    if (
        np.sum(bin_img[0, :])
        + np.sum(bin_img[-1, :])
        + np.sum(bin_img[:, 0])
        + np.sum(bin_img[:, -1])
        > 0
    ):
        fatal_error("The ROI extends outside of the image!")

    # Use the binary image to create an ROI contour
    roi_contour, roi_hierarchy = cv2.findContours(
        np.copy(bin_img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE
    )[-2:]

    # Draw the ROI if requested
    if params.debug is not None:
        _draw_roi(img=img, roi_contour=roi_contour)

    return roi_contour, roi_hierarchy


# Traceback (RuntimeError)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-143-af286afe5707> in <module>
4                              spacing=(0, 1150),
5                              ncols=1,
----> 6                              nrows=2)

~\Miniconda3\envs\test-environment\lib\site-packages\plantcv-3.6.1+51.g90ef8d0.dirty-py3.7.egg\plantcv\plantcv\roi\roi_methods.py in multi(img, coord, radius, spacing, nrows, ncols)
262                 x = coord[0] + j * spacing[0]
263                 # Create a chip ROI
--> 264                 rois.append(circle(img=img, x=x, y=y, r=radius))
265                 # Draw the circle on the binary image
266                 cv2.circle(bin_img, (x, y), radius, 255, -1)

~\Miniconda3\envs\test-environment\lib\site-packages\plantcv-3.6.1+51.g90ef8d0.dirty-py3.7.egg\plantcv\plantcv\roi\roi_methods.py in circle(img, x, y, r)
120     # Check whether the ROI is correctly bounded inside the image
121     if x - r < 0 or x + r > width or y - r < 0 or y + r > height:
--> 122         fatal_error("The ROI extends outside of the image!")
123
124     # Initialize a binary image of the circle

~\Miniconda3\envs\test-environment\lib\site-packages\plantcv-3.6.1+51.g90ef8d0.dirty-py3.7.egg\plantcv\plantcv\fatal_error.py in fatal_error(error)
12     """
13
---> 14     raise RuntimeError(error)

RuntimeError: The ROI extends outside of the image!

# Fixed code
def ellipse(img, x, y, r1, r2, angle):
    """Create an elliptical ROI.

    Inputs:
    img           = An RGB or grayscale image to plot the ROI on in debug mode.
    x             = The x-coordinate of the center of the ellipse.
    y             = The y-coordinate of the center of the ellipse.
    r1            = The radius of the major axis.
    r2            = The radius of the minor axis.
    angle         = The angle of rotation in degrees of the major axis.

    Outputs:
    roi_contour   = An ROI set of points (contour).
    roi_hierarchy = The hierarchy of ROI contour(s).

    :param img: numpy.ndarray
    :param x: int
    :param y: int
    :param r1: int
    :param r2: int
    :param angle: double
    :return roi_contour: list
    :return roi_hierarchy: numpy.ndarray
    """
    # Autoincrement the device counter
    params.device += 1

    # Get the height and width of the reference image
    height, width = np.shape(img)[:2]

    # Initialize a binary image of the ellipse
    bin_img = np.zeros((height, width), dtype=np.uint8)
    # Draw the ellipse on the binary image
    cv2.ellipse(bin_img, (x, y), (r1, r2), angle, 0, 360, 255, -1)

    # Use the binary image to create an ROI contour
    roi_contour, roi_hierarchy = cv2.findContours(
        bin_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE
    )[-2:]

    # Draw the ROI if requested
    if params.debug is not None:
        _draw_roi(img=img, roi_contour=roi_contour)

    # Checks ellipse goes outside the image by checking row and column sum of edges
    if (
        np.sum(bin_img[0, :])
        + np.sum(bin_img[-1, :])
        + np.sum(bin_img[:, 0])
        + np.sum(bin_img[:, -1])
        > 0
    ) or len(roi_contour) == 0:
        fatal_error("The ROI extends outside of the image, or ROI is not on the image!")

    return roi_contour, roi_hierarchy