pythonopencvroi

python + opencv: how to extract a ROI of unknown shape and analyse it?


I have an issue which I can't work around since I'm not very fluent with python and opencv.

Suppose I have an image, I convert to grayscale, I threshold it, perform some dilate and erode and finally I am able to retrieve a list of contours. Some code:

    imfile = path + f
    origimage = cv.imread(imfile)

    #from RGB to grayscale
    imgray = cv.imread(imfile, cv.IMREAD_GRAYSCALE)

    #thresholding
    ret,thresholded = cv.threshold(imgray,chosenThresh,255,cv.THRESH_BINARY)

    dKernel = np.ones((12,12),np.uint8)
    opened = cv.morphologyEx(thresholded, cv.MORPH_CLOSE, dKernel)

    #the kernel
    sharpkrnl = np.array([[0,-1,0], [-1,5,-1], [0,-1,0]])
    sharpened = cv.filter2D(opened, -1, sharpkrnl)
    sharpened = cv.bitwise_not(sharpened)

    #find contours
    h, w = sharpened.shape[:2]
    _, contours0, hierarchy = cv.findContours(sharpened.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    contours = [cv.approxPolyDP(cnt, 3, True) for cnt in contours0]

now the question is...I run through the found contours and, if some of these does not fit my requirements, in particular if it is too big, I want to get a ROI of the image that is exactly what's inside the contour in order to perform a thresholding and all the above only to this region, in order to see if I can do a better contouring of the cropped image.

This question partially address my issue: How to crop the internal area of a contour?

EDIT

the Masking out the infomation allows me extracting the ROI but I also need the exact image with the same colours of the original in order to perform thresholding and all the other operations. The code provided in the answer I mentioned requires a grayscale image. This the original code:

import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]

I, on the other side, have an imgray as from the code above. Is it the same as in the example I found? What should I do, instead, in order to get a ROI that contains the imgray so that I can perform the same operations as shown above? Ideas?

EDIT II

this code

mask = np.zeros_like(imgray) # Create mask where white is what we want, black otherwise
cv.drawContours(mask, [c], -1, 255, -1) # Draw filled contour in mask
out = np.zeros_like(imgray) # Extract out the object and place into output image
out[mask == 255] = imgray[mask == 255]

seems to, at least, return a grayscale image. But it's showing the whole image and not the countour I am expecting...ideas?


Solution

  • ok, I believe I found the answer I was looking for. What I am doing is the following:

    #by doing so I am getting a ROI over the imgray image
    #which can be used to, later, perform analysis
    mask = np.zeros_like(imgray) # Create mask where white is what we want, black otherwise
    cv.drawContours(mask, [c], -1, 255, -1) # Draw filled contour in mask
    out = np.zeros_like(imgray) # Extract out the object and place into output image
    out[mask == 255] = imgray[mask == 255]
                    
    #then simply proceed with the analysis:
    chosenThresh = 120
    ret,thresholded = cv.threshold(out,chosenThresh,255,cv.THRESH_BINARY)
                        
    dKernel = np.ones((12,12),np.uint8)
    opened = cv.morphologyEx(thresholded, cv.MORPH_CLOSE, dKernel)