tHeReaver
tHeReaver

Reputation: 244

How to calculate the area of a shape in an image with Python OpenCV?

I would like to calculate the area of a shape in an image produced from infra red cameras.

I have a large set of matrices which i produce from an infra- red camera. In each matrix/image i have mostly background with an image of a spot, which is a source of infra red radiation. The way i proceeded with it is to use Python OpenCV in order to isolate the image of the source by nullifying the background and calculating the number of pixels in the shape. The problem is that in each image, parts of the image is also turned into background and so i can't get the full image, as i would like.

import cv2
import numpy as np
from matplotlib import pyplot as plt

PPmm = 81/55 #Pixel per mm


img = np.genfromtxt('Image 5 Z_plane = 141.0_contour_plot.csv', delimiter= ',')

img_cv = cv2.resize(img,(81,81))
np.savetxt('testing.csv', img_cv, delimiter= ',')

img = (img_cv*255).astype(np.uint8)









edges = cv2.Canny(img,150,250)

se = np.ones((7,7), dtype='uint8')





# Perform morphology

image_close = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, se)

# Your code now applied to the closed image
cnt = cv2.findContours(image_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
mask = np.zeros(img.shape[:2], np.uint8)
cv2.drawContours(mask, cnt, -1, 255, -1)





non_zero_pixel_count = (np.count_nonzero(mask))

Area_in_mm = non_zero_pixel_count*(1/PPmm)**2
print("Area of shape = {0:1f}mm^2".format(Area_in_mm))






plt.subplot(121)
plt.imshow(img,cmap = 'gray')
plt.title('Original Image')
plt.xticks([])
plt.yticks([])
plt.subplot(122)
plt.imshow(mask,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
[enter image description here][1]
plt.show()

the shape area is: 58.093278mm^2. If i calculate manually, approximatly i will get 68mm^2. In circular images this is even worse and I get an area twice as small

Circular image

Square image

edit: Using cv2.THRESH_BINARY

Upvotes: 6

Views: 2329

Answers (1)

nathancy
nathancy

Reputation: 46600

To get the exact edges of the shape you can do this

  • Threshold
  • Find contours
  • Count all non zero pixels

After finding the contour shape, you can use cv2.countNonZero() to find all white pixels and then calculate the area using your calibrated pixel metric (my area is different since I don't the exact original image)


import cv2

image = cv2.imread('2.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 20, 255, cv2.THRESH_BINARY)[1]

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    cv2.drawContours(image,[c], 0, (36,255,12), 2)

area = cv2.countNonZero(thresh)
cv2.putText(image, "Area: {}".format(area), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (156, 188, 24), 1)

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.imwrite('thresh.png', thresh)
cv2.imwrite('image.png', image)
cv2.waitKey()

Upvotes: 5

Related Questions