Hi I am a newbie in computer vision. I am working on crack detection on material surface using canny. Here, I will have to find out area occupied by cracks (pixels and mm), number of cracks, max crack area or length (pixels and mm), area of each crack and percentage of crack area in the following image.
I have used following code to detect the edges where I used cv2.dilate to fill the area inside the cracks.
image = cv2.imread('./crack_img.jpg')
image_height = image.shape[0]
image_width = image.shape[1]
resized_image_area = (image_height * image_width)
#Convert img to gray
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray,(11,11),5)
edged = cv2.Canny(img_blur, 50, 200, 1)
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (16, 16))
edged = cv2.morphologyEx((cv2.dilate(edged,kernel1,1)),cv2.MORPH_CLOSE, kernel1) # for bigger cracks
# or
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 1))
edged = cv2.morphologyEx((cv2.dilate(edged,kernel2,1)),cv2.MORPH_CLOSE, kernel2) # for smaller cracks
# find contours
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# loop over the contours individually to find largest contours
canny_contrd_area = []
for c in cnts:
canny_area = cv2.contourArea(c)
canny_contrd_area.append(canny_area)
# print('Canny Contrd Area is:', canny_contrd_area)
if range(len(canny_contrd_area)) == 0:
max_crack_length == 0
elif range(len(canny_contrd_area)) != 0:
max_crack_length = int(max(canny_contrd_area, default=0))
print('Max Canny_Cont_Area is:', max_crack_length)
# find all the contours
canny_contrd_area = 0
for c in cnts:
canny_contrd_area = cv2.contourArea(c)
if canny_contrd_area > 10:
peri=cv2.arcLength(c,True)
approx=cv2.approxPolyDP(c, 0.009 * peri, True)
image_contours1= cv2.drawContours(image.copy(), cnts, -1,
(0,255,0), 2)
image_contours = cv2.drawContours(image, cnts, -1, (0,255,0), 3)
# calcualte the metrics to find ozone crack%
canny_number_of_cracks = len(cnts)
print('Canny Detected Cracks', canny_number_of_cracks)
canny_nonzero = round(cv2.countNonZero(edged),3)
canny_percent_area = round(((canny_nonzero)/(image_area))*100,3)
cv2.putText(image, str(canny_number_of_cracks),(50,30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
cv2.putText(image, str(canny_nonzero),(50,50),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
cv2.putText(image, str("%s%%"%canny_percent_area),(50,70),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
cv2.imshow('Edged', edged)
cv2.imshow('Final Image', image)
The problem is that if I use large kernel, then it fills up the big crack, but at the same time it includes the small crack as a part of a big crack as shown in the following image.
On the other hand, if I use small kernels, then it considers one big cracks as multiple cracks as it detects multiple edges as shown in the following image.
I have looked into different sources and tried different image processing techniques, but it seems that the algorithm is not giving me accurate representation of number of cracks, area of each crack and max crack length because of the having both small and big cracks in the same image.