How to crop the inside of a path?

I am working on retinal images. Image consists of a circular retina on a black background. With OpenCV, I managed to get a circuit that surrounds the entire circular retina. I need to cut a circular retina from a black background.

+17
source share
3 answers

It is not clear in your question whether you really want to trim the information defined in the circuit, or to mask information that is not related to the selected circuit. I will find out what to do in both situations.


Information masking

Assuming you run cv2.findContours on your image, you get a structure that lists all the paths available on your image. I also assume that you know the outline index that was used to surround the object you want. Assuming this is stored in idx , first use cv2.drawContours to draw a filled version of this path on a blank image, and then use this image to index it to extract outside the object. This logic masks any irrelevant information and stores only what is important - what is defined in the circuit you choose. The code for this would look something like this, assuming your image is a grayscale image stored in img :

 import numpy as np import cv2 img = cv2.imread('...', 0) # Read in your image # contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x _, 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] # Show the output image cv2.imshow('Output', out) cv2.waitKey(0) cv2.destroyAllWindows() 

If you really want to crop ...

If you want to crop the image, you need to define the minimum bounding bounding rectangle of the area defined by the path. You can find the upper left and lower right angular of the bounding box, and then use indexing to cut what you need. The code will be the same as before, but there will be an additional trimming step:

 import numpy as np import cv2 img = cv2.imread('...', 0) # Read in your image # contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x _, 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] # Now crop (y, x) = np.where(mask == 255) (topy, topx) = (np.min(y), np.min(x)) (bottomy, bottomx) = (np.max(y), np.max(x)) out = out[topy:bottomy+1, topx:bottomx+1] # Show the output image cv2.imshow('Output', out) cv2.waitKey(0) cv2.destroyAllWindows() 

The cropping code works so that when we define a mask to select the area defined by the path, we additionally find the smallest horizontal and vertical coordinates that define the upper left corner of the path. We also find the largest horizontal and vertical coordinates that define the bottom left angular contour. Then we use indexing with these coordinates to crop what we really need. Note that cropping a masked image is an image that erases everything except the information contained in the largest outline.

Note with OpenCV 3.x

It should be noted that the above code assumes that you are using OpenCV 2.4.x. Note that in OpenCV 3.x, the definition of cv2.drawContours has changed. In particular, the output is a three-element tuple in which the first image is the original and the other two parameters are the same as in OpenCV 2.4.x. So just change the cv2.findContours in the above code to ignore the first output:

 _, contours, _ = cv2.findContours(...) # Your call to find contours 
+34
source

Here's another approach to crop a rectangular area of โ€‹โ€‹interest. The basic idea is to find the edges of the retina using Canny edge detection, find the contours, and then extract the ROI using a Numpy slice. Assuming you have an input image like this:

Extracted ROI

 import cv2 # Load image, convert to grayscale, and find edges image = cv2.imread('1.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1] # Find contour and sort by contour area cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # Find bounding box and extract ROI for c in cnts: x,y,w,h = cv2.boundingRect(c) ROI = image[y:y+h, x:x+w] break cv2.imshow('ROI',ROI) cv2.imwrite('ROI.png',ROI) cv2.waitKey() 
+1
source

This is a pretty easy way. Image mask with transparency.

 Read the image Make a grayscale version. Otsu Threshold Apply morphology open and close to thresholded image as a mask Put the mask into the alpha channel of the input Save the output 


Entrance:

enter image description here

 import cv2 import numpy as np # load image as grayscale img = cv2.imread('retina.jpeg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # threshold input image using otsu thresholding as mask and refine with morphology ret, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) kernel = np.ones((9,9), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # put thresh into result = img.copy() result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA) result[:, :, 3] = mask # save resulting masked image cv2.imwrite('retina_masked.png', result) 


enter image description here

0
source

Source: https://habr.com/ru/post/983085/


All Articles