Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

findContours() does not find accurately contours (Python)

I am using OpenCV+Python to detect and extract eyeglasses from a (face) image. My line of reasoning is the following:

1) Detect the face

2) Find the largest contour in the face area which must be the outer frame of the glasses

3) Find the second and third largest contours in the face area which must be the frame of the two lenses

4) Extract the area between these contours which essentially represents the eyeglasses

However, findContours() does find the outer frame of the glasses as contour but it does not accurately find the frame of the two lenses as contours.

My results are the following:

image descriptionimage description

What can I do to fix this?

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('Luc_Marion.jpg')

RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)    
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect the face in the image
haar_face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = haar_face_cascade.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=8);

# Loop in all detected faces - in our case it is only one
for (x,y,w,h) in faces:
        cv2.rectangle(RGB_img,(x,y),(x+w,y+h),(255,0,0), 1)

        # Focus on the face as a region of interest
        roi = img[int(y+h/4):int(y+2.3*h/4), x:x+w]
        roi_gray = gray_img[int(y+h/4):int(y+2.3*h/4), x:x+w]

        # Apply smoothing to roi
        roi_blur = cv2.GaussianBlur(roi_gray, (5, 5), 0)

        # Use Canny to detect edges
        edges = cv2.Canny(roi_gray, 250, 300, 3)

        # Dilate and erode to thicken the edges
        kernel = np.ones((3, 3), np.uint8)
        edg_dil = cv2.dilate(edges, kernel, iterations = 3)
        edg_er = cv2.erode(edg_dil, kernel, iterations = 3)

        # Thresholding instead of Canny does not really make things better
        # ret, thresh = cv2.threshold(roi_blur, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
        # thresh = cv2.adaptiveThreshold(blur_edg, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)

        # Find and sort contours by contour area
        cont_img, contours, hierarchy = cv2.findContours(edg_er, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
        print("Number of contours: ", len(contours))
        cont_sort = sorted(contours, key=cv2.contourArea, reverse=True)

        # Draw n-th contour on original roi
        cv2.drawContours(roi, cont_sort[0], -1, (0, 255, 0), 2)

        mask_roi = mask[int(y+h/4):int(y+2.3*h/4), x:x+w]
        cv2.drawContours(mask_roi, cont_sort[0], -1, (255,255,255), 2)

plt.imshow(RGB_img)
plt.show()

findContours() does not find accurately contours (Python)

I am using OpenCV+Python to detect and extract eyeglasses from a (face) image. My I followed the line of reasoning of this post(https://stackoverflow.com/questions/26418558/glasses-detection) which is the following:

1) Detect the face

2) Find the largest contour in the face area which must be the outer frame of the glasses

3) Find the second and third largest contours in the face area which must be the frame of the two lenses

4) Extract the area between these contours which essentially represents the eyeglasses

However, findContours() does find the outer frame of the glasses as contour but it does not accurately find the frame of the two lenses as contours.

My results are the following:

image descriptionimage description

What can I do to fix this?

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('Luc_Marion.jpg')

RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)    
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect the face in the image
haar_face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = haar_face_cascade.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=8);

# Loop in all detected faces - in our case it is only one
for (x,y,w,h) in faces:
        cv2.rectangle(RGB_img,(x,y),(x+w,y+h),(255,0,0), 1)

        # Focus on the face as a region of interest
        roi = img[int(y+h/4):int(y+2.3*h/4), x:x+w]
        roi_gray = gray_img[int(y+h/4):int(y+2.3*h/4), x:x+w]

        # Apply smoothing to roi
        roi_blur = cv2.GaussianBlur(roi_gray, (5, 5), 0)

        # Use Canny to detect edges
        edges = cv2.Canny(roi_gray, 250, 300, 3)

        # Dilate and erode to thicken the edges
        kernel = np.ones((3, 3), np.uint8)
        edg_dil = cv2.dilate(edges, kernel, iterations = 3)
        edg_er = cv2.erode(edg_dil, kernel, iterations = 3)

        # Thresholding instead of Canny does not really make things better
        # ret, thresh = cv2.threshold(roi_blur, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
        # thresh = cv2.adaptiveThreshold(blur_edg, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)

        # Find and sort contours by contour area
        cont_img, contours, hierarchy = cv2.findContours(edg_er, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
        print("Number of contours: ", len(contours))
        cont_sort = sorted(contours, key=cv2.contourArea, reverse=True)

        # Draw n-th contour on original roi
        cv2.drawContours(roi, cont_sort[0], -1, (0, 255, 0), 2)

        mask_roi = mask[int(y+h/4):int(y+2.3*h/4), x:x+w]
        cv2.drawContours(mask_roi, cont_sort[0], -1, (255,255,255), 2)

plt.imshow(RGB_img)
plt.show()

findContours() does not find accurately contours (Python)

I am using OpenCV+Python to detect and extract eyeglasses from a (face) image. I followed the line of reasoning of this post(https://stackoverflow.com/questions/26418558/glasses-detection) which is the following:

1) Detect the face

2) Find the largest contour in the face area which must be the outer frame of the glasses

3) Find the second and third largest contours in the face area which must be the frame of the two lenses

4) Extract the area between these contours which essentially represents the eyeglasses

However, findContours() does find the outer frame of the glasses as contour but it does not accurately find the frame of the two lenses as contours.

My results are the following:

image descriptionimage description

The original image is here: image description

What can I do to fix this?

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('Luc_Marion.jpg')

RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)    
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect the face in the image
haar_face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = haar_face_cascade.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=8);

# Loop in all detected faces - in our case it is only one
for (x,y,w,h) in faces:
        cv2.rectangle(RGB_img,(x,y),(x+w,y+h),(255,0,0), 1)

        # Focus on the face as a region of interest
        roi = img[int(y+h/4):int(y+2.3*h/4), x:x+w]
        roi_gray = gray_img[int(y+h/4):int(y+2.3*h/4), x:x+w]

        # Apply smoothing to roi
        roi_blur = cv2.GaussianBlur(roi_gray, (5, 5), 0)

        # Use Canny to detect edges
        edges = cv2.Canny(roi_gray, 250, 300, 3)

        # Dilate and erode to thicken the edges
        kernel = np.ones((3, 3), np.uint8)
        edg_dil = cv2.dilate(edges, kernel, iterations = 3)
        edg_er = cv2.erode(edg_dil, kernel, iterations = 3)

        # Thresholding instead of Canny does not really make things better
        # ret, thresh = cv2.threshold(roi_blur, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
        # thresh = cv2.adaptiveThreshold(blur_edg, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)

        # Find and sort contours by contour area
        cont_img, contours, hierarchy = cv2.findContours(edg_er, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
        print("Number of contours: ", len(contours))
        cont_sort = sorted(contours, key=cv2.contourArea, reverse=True)

        # Draw n-th contour on original roi
        cv2.drawContours(roi, cont_sort[0], -1, (0, 255, 0), 2)

        mask_roi = mask[int(y+h/4):int(y+2.3*h/4), x:x+w]
        cv2.drawContours(mask_roi, cont_sort[0], -1, (255,255,255), 2)

plt.imshow(RGB_img)
plt.show()