I have an image that i would like to do an edge detection and draw a bounding box to it, my problem is my python code does not draw the bounding box and im not sure if its because it was not able to detect any objects in it or im just drawing the rectangle wrong.
Here is my attempt
import cv2
import numpy as np
img = cv2.imread("image1.jpg")
(B, G, R) = cv2.split(img)
img = cv2.Canny(B, 20, 100) # Blue channel gives the best box so far
# img = cv2.Canny(R, 20, 100)
# img = cv2.Canny(R, 20, 100)
ret,thresh = cv2.threshold(img,20,100,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
for c in contours:
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.intp(box)
img = cv2.drawContours(img,[box],0,(0,0,255),2)
# display the image with bounding rectangle drawn on it
# cv2.namedWindow('Bounding Rectangle', cv2.WINDOW_KEEPRATIO)
cv2.imshow('Bounding Rectangle', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
This produces this image
and I am expecting an image that is something like this:
My approach:
This approach detects all four colored squares.
# you can skip this step by defining `balanced = im * np.float32(1/255)`
# gray = im.mean(axis=(0,1), dtype=np.float32) # gray world
gray = np.median(im, axis=(0,1)).astype(np.float32) # majority vote
print(gray) # [137. 127. 140.]
balanced = (im / gray) * 0.8 # some moderate scaling so it's not "overexposed"
# transform into color space that has a "saturation" axis
hsv = cv.cvtColor(balanced, cv.COLOR_BGR2HSV)
H,S,V = cv.split(hsv)
# squares nicely visible in S
for comparison, the saturation channel of the source, without white balance:
# Otsu finds threshold level automatically
(_, mask) = cv.threshold((S * 255).astype(np.uint8), 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# To remove minor debris/noise. Increase iterations as needed.
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, kernel=None, iterations=5)
(contours, _) = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
hull = cv.convexHull(np.concatenate(contours))
rrect = cv.minAreaRect(hull)
# visualization
canvas = im.copy()
cv.drawContours(image=canvas, contours=contours, contourIdx=-1, color=(255,255,0), thickness=7)
# cv.drawContours(image=canvas, contours=[hull], contourIdx=-1, color=(255,255,0), thickness=7)
rrect_points = cv.boxPoints(rrect).round().astype(int)
cv.polylines(canvas, [rrect_points], isClosed=True, color=(0,255,255), thickness=3)
The code in one piece, minus some imshow/imwrite:
import numpy as np
import cv2 as cv
im = cv.imread("picture.jpg")
# gray = im.mean(axis=(0,1), dtype=np.float32) # gray world
gray = np.median(im, axis=(0,1)).astype(np.float32) # majority vote
print(gray) # [137. 127. 140.]
balanced = (im / gray) * 0.8 # some moderate scaling so it's not "overexposed"
# transform into color space that has a "saturation" axis
hsv = cv.cvtColor(balanced, cv.COLOR_BGR2HSV)
H,S,V = cv.split(hsv)
# squares nicely visible in S
# Otsu finds threshold level automatically
(_, mask) = cv.threshold((S * 255).astype(np.uint8), 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# To remove minor debris/noise. Increase iterations as needed.
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, kernel=None, iterations=5)
(contours, _) = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
hull = cv.convexHull(np.concatenate(contours))
rrect = cv.minAreaRect(hull)
# visualization
canvas = im.copy()
cv.drawContours(image=canvas, contours=contours, contourIdx=-1, color=(255,255,0), thickness=7)
# cv.drawContours(image=canvas, contours=[hull], contourIdx=-1, color=(255,255,0), thickness=7)
rrect_points = cv.boxPoints(rrect).round().astype(int)
cv.polylines(canvas, [rrect_points], isClosed=True, color=(0,255,255), thickness=3)