Created
December 10, 2021 05:10
-
-
Save AdamDimech/197828ff38a4f803478d40e1c7083807 to your computer and use it in GitHub Desktop.
A procedure to perform a blob analysis in OpenCV using Python. Details at https://code.adonline.id.au/blob-analysis-with-opencv-in-python/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import matplotlib as mpl | |
import matplotlib.pyplot as plt | |
import cv2 | |
import numpy as np | |
import csv | |
colours = [(230, 63, 7), (48, 18, 59), (68, 81, 191), (69, 138, 252), (37, 192, 231), (31, 233, 175), (101, 253, 105), (175, 250, 55), (227, 219, 56), (253, 172, 52), (246, 108, 25), (216, 55, 6), (164, 19, 1), (90, 66, 98), (105, 116, 203), (106, 161, 253), (81, 205, 236), (76, 237, 191), (132, 253, 135), (191, 251, 95), (233, 226, 96), (254, 189, 93), (248, 137, 71), (224, 95, 56), (182, 66, 52), (230, 63, 7), (48, 18, 59), (68, 81, 191), (69, 138, 252), (37, 192, 231), (31, 233, 175), (101, 253, 105), (175, 250, 55), (227, 219, 56), (253, 172, 52), (246, 108, 25), (216, 55, 6), (164, 19, 1), (90, 66, 98), (105, 116, 203), (106, 161, 253), (81, 205, 236), (76, 237, 191), (132, 253, 135), (191, 251, 95), (233, 226, 96), (254, 189, 93), (248, 137, 71), (224, 95, 56), (182, 66, 52)] | |
img = cv2.imread('/path/to/australian_states.png') #Read image | |
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert to greyscale | |
grey_inv = cv2.bitwise_not(grey) #Inverse | |
ret,thresh_au = cv2.threshold(grey_inv,20,255,cv2.THRESH_BINARY) #Threshold | |
def blob_properties(contours): | |
cont_props= [] | |
i = 0 | |
for cnt in contours: | |
area= cv2.contourArea(cnt) | |
perimeter = cv2.arcLength(cnt,True) | |
convexity = cv2.isContourConvex(cnt) | |
x1,y1,w,h = cv2.boundingRect(cnt) | |
x2 = x1+w | |
y2 = y1+h | |
aspect_ratio = float(w)/h | |
rect_area = w*h | |
extent = float(area)/rect_area | |
hull = cv2.convexHull(cnt) | |
hull_area = cv2.contourArea(hull) | |
solidity = float(area)/hull_area | |
(xa,ya),(MA,ma),angle = cv2.fitEllipse(cnt) | |
rect = cv2.minAreaRect(cnt) | |
(xc,yc),radius = cv2.minEnclosingCircle(cnt) | |
ellipse = cv2.fitEllipse(cnt) | |
rows,cols = img.shape[:2] | |
[vx,vy,xf,yf] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01) | |
lefty = int((-xf*vy/vx) + yf) | |
righty = int(((cols-xf)*vy/vx)+yf) | |
# Add parameters to list | |
add = i+1, area, round(perimeter, 1), convexity, round(aspect_ratio, 3), round(extent, 3), w, h, round(hull_area, 1), round(angle, 1), x1, y1, x2, y2,round(radius, 6), xa, ya, xc, yc, xf[0], yf[0], rect, ellipse, vx[0], vy[0], lefty, righty | |
cont_props.append(add) | |
i += 1 | |
return cont_props | |
# Sort contours | |
sorted_contours= sorted(contours, key=cv2.contourArea, reverse= True) | |
blobs_data = blob_properties(sorted_contours) | |
# Plot contours | |
image_plot = img.copy() | |
i = 0 | |
for rows in blobs_data: | |
pos = blobs_data[i] | |
inverted_colours = (255-colours[i][0],255-colours[i][1],255-colours[i][2]) | |
cv2.drawContours(image_plot, [sorted_contours[i]], -1, colours[i], -1) #, colours[i], thickness=cv2.FILLED) | |
#cv2.rectangle(image_plot, (pos[10], pos[11]), (pos[12], pos[13]), inverted_colours, 2) | |
cv2.putText(image_plot, str(pos[0]), (int(pos[19]), int(pos[20])), cv2.FONT_HERSHEY_SIMPLEX, 1, inverted_colours, 2, cv2.LINE_AA) | |
i += 1 | |
plt.imshow(image_plot) | |
# Save image | |
cv2.imwrite("/path/to/australian_states_blobs_ids.png", image_plot) | |
# Collect data | |
header = ['blob_id','area','perimeter','convexity','aspect_ratio','extent','width','height','hull_area','ellipse_angle','rect_x1','rect_y1','rect_x2','rect_y2','radius','xa','ya','xc','yc','xf','yf','min_area_rectangle','ellipse','vx','vy','left_y','right_y'] | |
with open("path/to/australian_states.csv", 'w', newline='') as file: | |
dw = csv.DictWriter(file, delimiter=',', fieldnames=header) | |
dw.writeheader() | |
writer = csv.writer(file) | |
writer.writerows(blobs_data) | |
# Grab stats to plot for biggest blob | |
# Rotated rectangle | |
rect = blobs_data[0][21] | |
box = cv2.boxPoints(rect) | |
box = np.int0(box) | |
# Mimimum enclosing circle | |
centre = (int(blobs_data[0][17]),int(blobs_data[0][18])) | |
radius = int(blobs_data[0][14]) | |
# Plot the parameters on the biggest blob | |
image_plot2 = img.copy() | |
pos = blobs_data[0] | |
rows,cols = img.shape[:2] | |
cv2.rectangle(image_plot2, (pos[10], pos[11]), (pos[12], pos[13]), colours[1], 2) # Bounding rectangle | |
cv2.drawContours(image_plot2,[box],0,colours[4],2) # Rotated rectangle | |
cv2.circle(image_plot2,centre,radius,colours[7],2) # Minimum Enclosing Circle | |
cv2.ellipse(image_plot2,pos[22],colours[10],2) # Fitted ellipse | |
cv2.line(image_plot2,(cols-1,pos[26]),(0,pos[25]),colours[14],2) # Fitted line | |
plt.imshow(image_plot2) | |
# Save image | |
cv2.imwrite("/path/to/australian_states_blobs_biggest.png", image_plot2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment