Reputation: 3
I want to crop the mobile from below image:
For doing that, I am trying to detect a rectangle shape in the image, and then cropping the image using following code:
import cv2
import numpy as np
img = cv2.imread('rt1.jpg')
imgGry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret , thrash = cv2.threshold(imgGry, 240 , 255, cv2.CHAIN_APPROX_NONE)
contours , hierarchy = cv2.findContours(thrash, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
j=0
for contour in contours:
approx = cv2.approxPolyDP(contour, 0.01* cv2.arcLength(contour, True), True)
cv2.drawContours(img, [approx], 0, (0, 0, 0), 5)
if len(approx) == 4 :
x, y , w, h = cv2.boundingRect(approx)
cv2.putText(img, "mobile", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
out = img[y:y+h,x:x+w]
cv2.imwrite('cropped'+str(j)+'.jpg', out)
j = j+1
cv2.imshow('shapes', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
But it is not cropping the mobile phone. Can you suggest any improvement in the code for getting the desired result?
Upvotes: 0
Views: 108
Reputation: 18905
There's no need to do the approximation on the contours. For that specific image, you'll get one large contour, which you can simply get the bounding rectangle from, and crop the desired part. I optionally added setting the background transparent.
import cv2
import numpy as np
# Read image, convert to grayscale
img = cv2.imread('images/2EZyS.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Threshold image, attention: cv2.THRESH_BINARY_INV!
thr = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)[1]
# Find contours w.r.t. the OpenCV version, attention: cv2.RETR_EXTERNAL!
cnts = cv2.findContours(thr, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# Filter contours by size
cnts = [cnt for cnt in cnts if cv2.contourArea(cnt) > 2000]
thr = cv2.drawContours(np.zeros_like(thr), cnts, -1, 255, cv2.FILLED)
# Prepare output
out = img.copy()
# Optional: Set background transparent.
out = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
out[..., 3] = thr
# Crop
x, y, w, h = cv2.boundingRect(thr)
out = out[y:y+h, x:x+w]
# Save with and without transparency
cv2.imwrite('crop_w.png', out)
cv2.imwrite('crop_wo.png', out[..., :3])
That'd be the output image with transparency:
In your original code, you had cv2.CHAIN_APPROX_NONE
in the cv2.threshold
call. By chance, that value equals 1
, which also is cv2.THRESH_BINARY_INV
. Nevertheless, you should pay attention to that details.
Also, I'd use cv2.RETR_EXTERNAL
instead of cv2.RETR_TREE
here, since you only have one object, such that finding the most outer contours is sufficient.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
NumPy: 1.20.2
OpenCV: 4.5.1
----------------------------------------
Upvotes: 1