Calculate multiple areas with opencv
Question:
I’m trying to calculate different areas within a picture using opencv’s contourArea
without much success. The picture I’m using as an example is the following one:
My objective is to calculate the table’s free area (greyish) and the occupied area (orange objects), and so far managed to print the contours with the following code:
img = cv2.imread('table.jpg', 1)
b,g,r = cv2.split(img)
imgRGB = cv2.merge([r,g,b])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hsv_channels = cv2.split(hsv)
rows = img.shape[0]
cols = img.shape[1]
for i in range(0, rows):
for j in range(0, cols):
h = hsv_channels[1][i][j]
if h > 90 and h < 120:
hsv_channels[2][i][j] = 255
else:
hsv_channels[2][i][j] = 0
image, contours, hierarchy = cv2.findContours(hsv_channels[2],cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
img1 = cv2.drawContours(imgRGB, contours, -1, (0,255,0), 3)
However, I’m facing two issues:
1- The code detects contours inside the circle.
2- Given the multiple contours I don’t know if the area returned is the table’s, the objects’ or both.
Any suggestion?
Thanks a million.
Answers:
Since you transforming to HSV colorspace have you thought about cv2.inRange()
? After that you can find contours with cv2.findContours()
and draw them out of the image, leaving only the gray area.
Example:
import cv2
import numpy as np
img = cv2.imread('tablest.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0,0,50])
upper = np.array([160,255,255])
mask = cv2.inRange(hsv, lower, upper)
res = cv2.bitwise_and(hsv,hsv, mask= mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for i in contours:
cnt = cv2.contourArea(i)
if cnt > 1000:
cv2.drawContours(img, [i], 0, (0,0,0), -1)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
area = cv2.contourArea(cnt)
cv2.putText(img,'Gray area ='+str(area),(60,90), cv2.FONT_HERSHEY_COMPLEX, 0.5,(0,255,0),1,cv2.LINE_AA)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT
For calculating percentage:
import cv2
import numpy as np
img = cv2.imread('tablest.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0,0,50])
upper = np.array([160,255,255])
# Calculate whole area
h,w = img.shape[:2]
whole_area_mask = np.ones((h, w), np.uint8)
ret, thresh = cv2.threshold(whole_area_mask,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
whole_area = cv2.contourArea(cnt)
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower, upper)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(hsv,hsv, mask= mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
other_area = []
table_area = []
for i in contours:
cnt = cv2.contourArea(i)
M = cv2.moments(i)
cx = int(M['m10']/M['m00'])
if cnt > 1000:
cv2.drawContours(img, [i], 0, (0,0,0), -1)
if w-100 > cx > 100:
other_area.append(cnt)
else:
table_area.append(cnt)
# Percentage table/napkin/object 1/object 2
table_per = (100*(table_area[0]+table_area[1]))/whole_area
print('Table percentage: ', table_per)
napkin_per = (100*(whole_area-other_area[0]-other_area[1]-table_area[0]-table_area[1]))/whole_area
print('Napkin percentage: ', napkin_per)
first_object_per = (100*other_area[0])/whole_area
print('First object percentage: ', first_object_per)
second_object_per = (100*other_area[1])/whole_area
print('Second object percentage: ', second_object_per)
print('SUM: ', table_per+napkin_per+first_object_per+second_object_per)
cv2.imshow('img', img)
cv2.imwrite('tablest_res.png', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output:
Table percentage: 9.875440996472028
Napkin percentage: 58.93872849017208
First object percentage: 28.05565555475556
Second object percentage: 3.1301749586003313
SUM: 100.0
I’m trying to calculate different areas within a picture using opencv’s contourArea
without much success. The picture I’m using as an example is the following one:
My objective is to calculate the table’s free area (greyish) and the occupied area (orange objects), and so far managed to print the contours with the following code:
img = cv2.imread('table.jpg', 1)
b,g,r = cv2.split(img)
imgRGB = cv2.merge([r,g,b])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hsv_channels = cv2.split(hsv)
rows = img.shape[0]
cols = img.shape[1]
for i in range(0, rows):
for j in range(0, cols):
h = hsv_channels[1][i][j]
if h > 90 and h < 120:
hsv_channels[2][i][j] = 255
else:
hsv_channels[2][i][j] = 0
image, contours, hierarchy = cv2.findContours(hsv_channels[2],cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
img1 = cv2.drawContours(imgRGB, contours, -1, (0,255,0), 3)
However, I’m facing two issues:
1- The code detects contours inside the circle.
2- Given the multiple contours I don’t know if the area returned is the table’s, the objects’ or both.
Any suggestion?
Thanks a million.
Since you transforming to HSV colorspace have you thought about cv2.inRange()
? After that you can find contours with cv2.findContours()
and draw them out of the image, leaving only the gray area.
Example:
import cv2
import numpy as np
img = cv2.imread('tablest.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0,0,50])
upper = np.array([160,255,255])
mask = cv2.inRange(hsv, lower, upper)
res = cv2.bitwise_and(hsv,hsv, mask= mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for i in contours:
cnt = cv2.contourArea(i)
if cnt > 1000:
cv2.drawContours(img, [i], 0, (0,0,0), -1)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
area = cv2.contourArea(cnt)
cv2.putText(img,'Gray area ='+str(area),(60,90), cv2.FONT_HERSHEY_COMPLEX, 0.5,(0,255,0),1,cv2.LINE_AA)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT
For calculating percentage:
import cv2
import numpy as np
img = cv2.imread('tablest.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0,0,50])
upper = np.array([160,255,255])
# Calculate whole area
h,w = img.shape[:2]
whole_area_mask = np.ones((h, w), np.uint8)
ret, thresh = cv2.threshold(whole_area_mask,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
whole_area = cv2.contourArea(cnt)
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower, upper)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(hsv,hsv, mask= mask)
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
other_area = []
table_area = []
for i in contours:
cnt = cv2.contourArea(i)
M = cv2.moments(i)
cx = int(M['m10']/M['m00'])
if cnt > 1000:
cv2.drawContours(img, [i], 0, (0,0,0), -1)
if w-100 > cx > 100:
other_area.append(cnt)
else:
table_area.append(cnt)
# Percentage table/napkin/object 1/object 2
table_per = (100*(table_area[0]+table_area[1]))/whole_area
print('Table percentage: ', table_per)
napkin_per = (100*(whole_area-other_area[0]-other_area[1]-table_area[0]-table_area[1]))/whole_area
print('Napkin percentage: ', napkin_per)
first_object_per = (100*other_area[0])/whole_area
print('First object percentage: ', first_object_per)
second_object_per = (100*other_area[1])/whole_area
print('Second object percentage: ', second_object_per)
print('SUM: ', table_per+napkin_per+first_object_per+second_object_per)
cv2.imshow('img', img)
cv2.imwrite('tablest_res.png', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output:
Table percentage: 9.875440996472028
Napkin percentage: 58.93872849017208
First object percentage: 28.05565555475556
Second object percentage: 3.1301749586003313
SUM: 100.0