This can be done with OpenCV by detecting the green areas, then picking out the biggest area. There are several ways to go about detecting the green area, including cv2.inRange
and cv2.threshold
.
1. Identifying Green Regions
cv2.inRange
With inRange
, you can identify colors within a certain range. For example:
lower_bound = (0,100,0)
upper_bound = (10,255,10)
So pixels with colors between lower_bound
and upper_bound
can be identified to create a mask with
mask = cv2.inRange(im, lower_bound, upper_bound)
Here's the mask
of green areas:

cv2.threshold
Similarly, thresholding will create a mask of green areas. First, turn the image into grayscale.
imgray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)

However, if you threshold this image, it will identify the white areas, so we want the inverse of the threshold found by cv2.THRESH_BINARY_INV
ok, thresh = cv2.threshold(imgray, 200, 255, cv2.THRESH_BINARY_INV)
Here is the threshold image:

As can be seen, thresh
and mask
identify the green regions.
2. Contours
Once we have the mask or threshold image, we can identify the white regions by looking for contours. I will use the mask
image (thresh
could be used just as well).
(im2, contours, hierarchy) = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
We specifically want the contours
, which give a set of points that can be used to outline the green areas. We want the contour that creates the largest contour area, which we can find by first putting them in order from largest to smallest, then taking the first one.
ordered_cnts = sorted(contours, key=cv2.contourArea, reverse=True)
largest_cnt = ordered_cnts[0]
largest_cnt
is the following set of points:
[[[ 0 701]]
[[ 0 999]]
[[298 999]]
[[298 701]]
[[289 701]]
[[288 702]]
[[287 701]]]
Those points can be used to outline the green box in the bottom left of the image. We just want a single rectangle, so we can outline the entire contour by finding the smallest rectangle that would surround all those points.
rect = cv2.minAreaRect(largest_cnt)
box = cv2.boxPoints(rect)
box
gives a list of points that are the four corners of rect
. We can use numpy
to convert to integer points and get the limits of the box to crop the image.
box = np.array(box, dtype=int)
x0, y0 = np.min(box,axis=0)
x1, y1 = np.max(box,axis=0)
crop = im[y0:y1, x0:x1]
The crop
image:

Combined Code
lower_bound = (0,100,0)
upper_bound = (10,255,10)
mask = cv2.inRange(im, lower_bound, upper_bound)
(im2, cnts, hierarchy) = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
ordered_cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
largest_cnt = ordered_cnts[0]
rect = cv2.minAreaRect(largest_cnt)
box = cv2.boxPoints(rect)
box = np.array(box, dtype=int)
x0, y0 = np.min(box,axis=0)
x1, y1 = np.max(box,axis=0)
crop = im[y0:y1, x0:x1]