Goal
My goal is to detect PV modules on the dataset of infrared images. After the preprocessing phase, which is mainly removing noisy background, I want to find edges so they can be used for further processing (HoughLinesP
etc.). I get already quite satisfying results, however, I’d like to verify my approach and ask for tips.
Attention images (preprocessed, background removed)
Then I increase contrast (that gives me slightly better results)
And then apply Canny Edge detection with some erosion and dilatation.
Final results
I would like to improve detection for images looking similar to the 3rd image - the edges are not detected on the left and right on both rectangles (middle is fine). I tried to increase the contrast and it worked fine on that particular image but it also resulted in more false edges to be detected on other images from my dataset. Is there a way to tackle it better?
Code
In case my approach makes sense there is my code.
import cv2
import numpy as np
def increase_contrast(input_image):
bgr_image = cv2.cvtColor(input_image, cv2.COLOR_GRAY2BGR)
lab = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl = clahe.apply(l)
limg = cv2.merge((cl, a, b))
increased_contrast_image = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
return increased_contrast_image
def detect_edges(input_image):
hysteresis_min_thresh = 35
hysteresis_max_thresh = 45
canny_image = cv2.Canny(image=input_image, threshold1=hysteresis_min_thresh, threshold2=hysteresis_max_thresh,
apertureSize=3)
kernel_size = (7, 7)
kernel_shape = cv2.MORPH_CROSS
kernel = cv2.getStructuringElement(kernel_shape, kernel_size)
dilation_steps = 4
dilated = cv2.dilate(canny_image, (3, 3), iterations=dilation_steps)
size = np.size(dilated)
skel = np.zeros(dilated.shape, np.uint8)
img = dilated
done = False
while not done:
eroded = cv2.erode(img, kernel)
temp = cv2.dilate(eroded, kernel)
temp = cv2.subtract(img, temp)
skel = cv2.bitwise_or(skel, temp)
img = eroded.copy()
zeros = size - cv2.countNonZero(img)
if zeros == size:
done = True
return skel
def process_image(img_path):
input_image = cv2.imread(img_path)
input_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
increased_contrast_image = increase_contrast(input_image)
cv2.imshow('increased_contrast_image', increased_contrast_image)
image_scaling = 3
scaled_image = cv2.resize(src=increased_contrast_image, dsize=(0, 0), fx=image_scaling, fy=image_scaling)
gaussian_blur = 7
blurred_image = cv2.blur(scaled_image, (gaussian_blur, gaussian_blur))
canny_image = detect_edges(blurred_image)
cv2.imshow('canny_image', canny_image)
cv2.waitKey()
# DON'T FORGET TO VERIFY THIS PATH
img_path = "data/plasma_results/background/9.JPG"
process_image(img_path)
Questions
Is my approach (Canny) valid and sensical approach for this case?
How can I improve my algorithm so it works better on images with less visible edges between modules?
Edit
Original images
As requested in the comments these are unprocessed infrared images in plasma palette.