Reputation: 244
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
Reputation: 46600
To get the exact edges of the shape you can do this
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