I have multiple images with darks bands and I want to draw a rectangle over all of the darker bands. I have tried using HSV color detection, it works reasonably well but it picks up darker regions Current output of the code, code below.
import cv2 import numpy as np import matplotlib.pyplot as plt stretch = frames.copy() #Frame is the imported image #Increasing the contrast of the image # CLAHE (Contrast Limited Adaptive Histogram Equalization) clahe = cv2.createCLAHE(clipLimit=2., tileGridSize=(8,8)) lab = cv2.cvtColor(stretch, cv2.COLOR_BGR2LAB) # convert from BGR to LAB color space l, a, b = cv2.split(lab) # split on 3 different channels l2 = clahe.apply(l) # apply CLAHE to the L-channel lab = cv2.merge((l2,a,b)) # merge channels img2 = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) # convert from LAB to BG # convert to gray gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY) # blur smooth = cv2.GaussianBlur(gray, (11,11), 0) img2 = cv2.cvtColor(smooth,cv2.COLOR_GRAY2BGR) frame_HSV = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) frame_threshold = cv2.inRange(frame_HSV, (0, 0, 10), (180, 255, 80)) contours,hierarchy, = cv2.findContours(frame_threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) areas = [cv2.contourArea(c) for c in contours] sorted_areas = np.sort(areas) #cnt=contours[areas.index(sorted_areas[-1])] #the biggest contour largestContourArea = sorted_areas[-1]*0.1 largestContour = 0 for cnt in contours: contourArea = cv2.contourArea(cnt) if( contourArea > largestContourArea): #cv2.drawContours(frames, cnt, -1, (255,0,132), thickness=4) x,y,w,h = cv2.boundingRect(cnt) cv2.rectangle(frames, (x, y), (x+w, y+h), (255,0,0), 4) ROI = frames[y:y+h,x:x+w] plt.imshow(ROI) plt.show() cv2.drawContours(frames, contours, -1, (0,150,132), thickness=4) plt.imshow(frames) plt.show()
I have tried Canny detection but I couldn’t get it to work, I do have limited experience with it. Is there another way to draw a box around the dark bands?
Otsu thresholding does a pretty good job of that image. IMHO, there’s little point converting a near-grey to HSL as there is no colour, so I load it as greyscale:
import cv2 # Load as greyscale - no colour anyway im = cv2.imread('9uu2H.jpg', cv2.IMREAD_GRAYSCALE) # Otsu threshold _, thr = cv2.threshold(im,127,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
Note: I cropped off your black border because I didn’t want to confuse Otsu thresholding with an additional, third class of grey, i.e. black.
Note: I added a red border artificially so you can see the extent on Stack Overflow’s background.
Note: You can add blurring, or filtering, or morphology to fill holes to taste.