Home > database >  how can we calculate the area of root image?
how can we calculate the area of root image?

Time:06-24

in my project i need to calculate the area of small plant root image.

rootimage

i have used the following two codes but i still doubt these:

import cv2
image = cv2.imread('D:/R4-15.TIF')
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 180, 255, cv2.THRESH_BINARY)
cv2.imshow('Binary', thresh)
contours, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
image_copy = image.copy()
cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=-1, lineType=cv2.LINE_AA)
               
cv2.imshow('Contour_image', image_copy)
cv2.waitKey(0)
cv2.imwrite('contours_image1.jpg', image_copy)
cv2.destroyAllWindows()

cnt = contours[0]
area= cv2.contourArea(cnt)
print(area)      

cv2.waitKey(0)
cv2.destroyAllWindows()

import cv2
import numpy as np
img = cv2.imread('D:/R4-16.TIF')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,165,255,cv2.THRESH_BINARY)
cv2.imshow("Mask", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
area2 = cv2.countNonZero(thresh)
print(area2)

CodePudding user response:

If your thresholded image has no noise, then countNonZero is fine.

But if after threshold you still have some noise, which is usually small black dots scattered here and there, then better to filter them out.

One of possible ways is to apply morphological opening, see Morphological operations. But it definately also alters ground truth root image.

I propose to use connectedComponentsWithStats

Call it against your thresholded root image.

One of returned values is stats which will also hold area for each connected component. Then you can drop all small components which is a noise, and pickup one or few largest black components and take their area.

More about connected components in wiki

Call example


# ...
# Put it at the end of you second snippet,
# where you get thresholded image

num_components, labels, stats, centroids = \
    cv2.connectedComponentsWithStats(thresh)

# Here you can also use something like this:
# total_area = list(itertools.accumulate(
#    stats, lambda t, x: t   x[cv2.CC_STAT_AREA])
# )[-1]

areas = stats[:, cv2.CC_STAT_AREA]
areas = list(sorted(areas))

assert \
    len(areas) >= 2, \
    "We expect at least two components: white area" \
    " and at least one root fragment."

# We suppose that white area is the biggest one, thus
# we have to count everything except the last item in sorted
# list.

total_area = 0
noise_threshold = 5 # If area is less than 5 pixels we drop it
for i, area in enumerate(areas[:-1]):
    print(f"Area of root part #{i} is: {area}")
    if area > noise_threshold:
        total_area  = area

print(f"Total area is: {total_area}")
  • Related