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:

enter image description here

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.

Asked By: Arduino

||

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()

enter image description here

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

Answered By: kavko
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.