I would like to use find the cabbage in the image provided. I already have an implementation with a previous question using colour thresholding, however it required me to manually enter HSV or RGB values, i require an adaptive way of thesholding and thought of using canny edge to find edges and then create a mask.
Below is the implentation from colour thesholding which is the desired output from canny.
# Import the necessary packages
import numpy as np
import argparse
import cv2
import glob
def auto_canny(image, sigma=0.33):
# compute the median of the single channel pixel intensities
v = np.median(image)
# apply automatic Canny edge detection using the computed median
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(image, lower, upper)
# return the edged image
return edged
# Construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
help = "Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Image", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
auto = auto_canny(blurred)
cv2.imshow("Image", auto)
cv2.imwrite("newimage1.jpg", auto)
(_, cnts, _) = cv2.findContours(auto.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
if len(cnts) > 0:
# sort the contours and find the largest one -- we
# will assume this contour correspondes to the area
# of my phone
cnt = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)
cv2.imshow("Tracking", image)
cv2.imwrite("newimage2.jpg", image)
cv2.waitKey(0)
cv2.waitKey(0)
Results:
My thought process is to use canny to find edges and then use findcontours to get the biggest contour and create a mask which should be the cabbage. However, this does not seem to be working as the result from canny output has a lot of edges.
I think i should do some pre processing before applying the canny edge detection but i'm not too sure what what techniques to apply for pre processing.
EDIT:
Read through the few suggestions and tried out those that i have an idea of how to do, first i converted it to HSV and split the image into respective H, s and v. Implemented 2 methods with the results below, any suggestions on how to improve?
# Import the necessary packages
import numpy as np
import argparse
import cv2
import glob
def auto_canny(image, sigma=0.33):
# compute the median of the single channel pixel intensities
v = np.median(image)
# apply automatic Canny edge detection using the computed median
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(image, lower, upper)
# return the edged image
return edged
# Construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
help = "Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("Image", image)
newImage = image.copy()
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
blurred = cv2.GaussianBlur(hsv, (3, 3), 0)
#cv2.imshow("HSV image", blurred)
#now to seperate and only extract hue image
h,s,v = cv2.split(blurred)
cv2.imshow("H", h)
#cv2.imshow("S", s)
#cv2.imshow("V", v)
thresh = cv2.adaptiveThreshold(h, 255,
cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 4)
cv2.imshow("adaptive1", thresh)
cv2.imwrite("adaptive1.jpg", thresh)
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
auto = auto_canny(h)
cv2.imshow("canny", auto)
cv2.imwrite("canny1.jpg", auto)
(_, cnts2, _) = cv2.findContours(auto.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
if len(cnts) > 0:
# sort the contours and find the largest one -- we
# will assume this contour correspondes to the area
# of my phone
cnt = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)
cv2.imshow("adaptive2", image)
cv2.imwrite("adaptive2.jpg", image)
if len(cnts2) > 0:
# sort the contours and find the largest one -- we
# will assume this contour correspondes to the area
# of my phone
cnt = sorted(cnts2, key = cv2.contourArea, reverse = True)[0]
cv2.drawContours(newImage, [cnt], -1, (0, 255, 0), 2)
cv2.imshow("canny2", newImage)
cv2.imwrite("canny2.jpg", newImage)
cv2.waitKey(0)
Adaptive:
Canny: