Reputation: 328
I would like to crop an image which has a hand drawn highlighted area in orange as shown below,
The result should be a cropped image along the major axis of the blob or contour with a rectangular bounding box, as shown below,
Here's what i have tried,
import numpy as np
import cv2
# load the image
image = cv2.imread("frame50.jpg", 1)
#color boundaries [B, G, R]
lower = [0, 3, 30]
upper = [30, 117, 253]
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype="uint8")
upper = np.array(upper, dtype="uint8")
# find the colors within the specified boundaries and apply
# the mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask=mask)
ret,thresh = cv2.threshold(mask, 50, 255, 0)
if (int(cv2.__version__[0]) > 3):
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
else:
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if len(contours) != 0:
# find the biggest countour (c) by the area
c = max(contours, key = cv2.contourArea)
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
cv2.imshow('ROI',ROI)
cv2.imwrite('ROI.png',ROI)
cv2.waitKey(0)
This does not seem to work most of the time.For some images, the following happens,
I would like to know if there is better way to go about this or how i can fix what i have right now.Note that the highlighted area is hand drawn and can be of any shape but it is closed and not left open and the colour of the highlight is that shade of orange itself in all cases. And is there a way to only retain content inside the circle and blackout everything outside it?
EDIT1: I was able to fix the wrong clipping by varying the threshold more. But my main query now is: is there a way to only retain content inside the circle and blackout everything outside it? I can see the mask as show below,
How do I fill this mask and retain content inside the circle and blackout everything outside it, with the same rectangular bounding box?
Upvotes: 0
Views: 480
Reputation: 1420
First of all, it is always better to use an HSV image instead of BGR image for masking(extracting a color). You can do this by the following code.
HSV_Image = cv2.cvtColor(Image, cv2.COLOR_BGR2HSV)
ThreshImage = cv2.inRange(HSV_Image, np.array([0, 28, 191]), np.array([24, 255, 255]))
The range numbers here are found for orange color in this case.
Image is the input image and ThreshImage is the output image with the orange region colored as white and everything else as black.
Now finding the contour in ThreshImage with cv2.RETR_EXTERNAL flag will give only one contour that is the outer boundary of the orange region.
Contours, Hierarchy = cv2.findContours(ThreshImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
To crop the orange region:
BoundingRect = cv2.boundingRect(Contours[0])
(x, y, w, h) = BoundingRect
CroppedImage = Image[y:y+h, x:x+w].copy()
"CroppedImage" will store the cropped orange region as desired.
To get contents of only inside the contour:
Bitwise AND operation will be useful here as we already have detected the contour.
First, we have to create a black image of shape the same as that of input image and draw the contour with white color filled in it.
ContourFilledImage = np.zeros(Image.shape, dtype=np.uint8)
cv2.drawContours(ContourFilledImage, Contours, -1, (255, 255, 255), -1)
Now perform a bitwise AND operation on Input Image and "ContourFilledImage"
OnlyInnerData = cv2.bitwise_and(ContourFilledImage, Image)
"OnlyInnerData" image is the desired output image having only the content of inside the circle.
Upvotes: 0
Reputation: 484
Have you tried
image[x:x+w, y:y+h]
And could you check bbox with below code
cv2.rectangle(thresh,(x,y),(x+w,y+h),(255,0,0),2)
Upvotes: 1