Calculating the area covered by the objects of irregular shapes in an image

Faizan Khan

I am working on a project where I'm estimating the wheat yield based on the wheat spikes in the image. After detecting spikes using Faster-RCNN and color based segmentation, the following is the resultant image where there are only spikes in the image.

Image having Wheat spikes only

Now my goal is to estimate the yield produced by the spikes in the image using python. For this, we may have to calculate the area covered by the objects of polygon shapes or we may have to work around the pixel values to calculate the area. But I don't know how we can do this. Please Let me know If anyone has the solution. Thanks

fmw42

The area in pixels of the image that are not black can be found from creating a binary mask. The area in pixels is equal to the total number of white pixels in the mask. One way to get that is to compute the fraction of white pixels in the image. The number of white pixels will then be the fraction * width * height of the image. The fraction is just the average of the image divided by the maximum possible gray level (255). So

area in pixels of white pixels = (average/255)widthheight

Thus, get the fractional average (average/255) of the binary mask image (by thresholding at 0). The result for the average will be one single value. Then multiply that by the Width of the image and then by the Height of the image. That result will be equal to the total number of white pixels in the mask and thus the total pixels that are not black (i.e. are colored) in your image. The number of white pixels is the pixel area of the non-black pixels in your image.

Input:

enter image description here

import cv2
import numpy as np
img = cv2.imread('img.jpg')
height = img.shape[0]
width = img.shape[1]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
cv2.imshow("Mask", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
ave = cv2.mean(thresh)[0]/255
print(ave)
0.310184375
area = ave*height*width
print(area)
198518.0

Note that this is the non-black pixel area. Some of your rectangles have black inside them. So this is not the area of the rectangle. You would have ensure that your image had no black pixels before isolating the rectangles to get the area of the rectangles.

ADDITION

A simpler approach, suggested by Mark Setchell, is to simply count the number of nonzero pixels in the thresholded image. It computes the same number as above.

import cv2
import numpy as np
img = cv2.imread('img.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
cv2.imshow("Mask", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
area2 = cv2.countNonZero(thresh)
print(area2)
198518

ADDITION 2

If you know the ground area or dimensions in meters (0.8 m on aside as per your comment) corresponding to the area covered by the image, then the ground area corresponding to the count of non-zero pixels will be:

area on ground for nonzero pixels = count * 0.8 * 0.8 / (width * height)


where width and height are the pixel dimensions of the image.

import cv2
import numpy as np
img = cv2.imread('img.jpg')
height = img.shape[0]
width = img.shape[1]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
cv2.imshow("Mask", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
count = cv2.countNonZero(thresh)
area = count*0.8*0.8/(width*height)
print(area)
0.19851800000000003


So the result is 0.198518 square meters

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related