4

Apologies in advance as i am newbie to OpenCV-Python. I set myself a task to create a Passport type image from the video capture.

Using a head and shoulders Haar Cascade i was able to create a portrait photo but i now want to turn the background to a white background (leaving the head and shoulders portrait in the foreground).

Just not sure how/ best way to do this. Any help would be welcome.

Many thanks in advance.

Here is the code:

import numpy as np
import cv2

# face file
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# eye file
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
# head shoulders file
hs_cascade = cv2.CascadeClassifier('HS.xml')

cap = cv2.VideoCapture(1)

while 1:
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    headshoulders = hs_cascade.detectMultiScale(gray, 1.3, 3)

    # find the head and shoulders
    for (x,y,w,h) in headshoulders:
        # variable change to make portrait orientation
        x = int(x*1.5)
        w = int(w/1.5)
        cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

        # crop the image
        crop_img = img[y: y + h, x: x + w]

        # show original and crop
        cv2.imshow('crop', crop_img)
        cv2.imshow('img', img)

    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
    elif k == ord('s'):
        # save out the portrait image
        cv2.imwrite('cropimage.png',crop_img)

# release the camera
cap.release()
cv2.destroyAllWindows()
J Elliot
  • 43
  • 1
  • 6
  • can you post some code you have done ? and have a look to http://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html and also http://scikit-image.org/ – Dadep Jul 24 '17 at 13:34
  • Code has been added to my original question. – J Elliot Jul 24 '17 at 14:17
  • have a look : https://stackoverflow.com/questions/31133903/opencv-remove-background and http://docs.opencv.org/3.1.0/d8/d83/tutorial_py_grabcut.html – Dadep Jul 24 '17 at 14:56
  • Many thanks for the guidance. I shall try and see if i can get the outcome i am looking for. :-) – J Elliot Jul 24 '17 at 17:20
  • Dadep. Once again i thank you. After some tweaking of code, i got a result that is very close to what i wanted. :-) – J Elliot Jul 24 '17 at 19:42
  • your welcome, if you have some script working, you can answer your own post, it maybe help someone in the future ! – Dadep Jul 24 '17 at 19:52

1 Answers1

0

I got it to work. Here is my solution.

PLEASE NOTE: This worked for HI-RES images (Nikon D7100 - JPEG). LOW-RES did NOT work when i tried a Webcam (Logitech C615).

I used some of the code from a link that was suggested.

# import numpy
import numpy as np
# import cv2
import cv2
# import Matplitlib
from matplotlib import pyplot as plt


# Fill any holes function
def get_holes(image, thresh):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    im_bw = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)[1]
    im_bw_inv = cv2.bitwise_not(im_bw)

    im_bw_inv, contour, _ = cv2.findContours(im_bw_inv, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contour:
        cv2.drawContours(im_bw_inv, [cnt], 0, 255, -1)

    nt = cv2.bitwise_not(im_bw)
    im_bw_inv = cv2.bitwise_or(im_bw_inv, nt)
    return im_bw_inv

# Remove background Function
def remove_background(image, thresh, scale_factor=.25, kernel_range=range(1, 15), border=None):
    border = border or kernel_range[-1]

    holes = get_holes(image, thresh)
    small = cv2.resize(holes, None, fx=scale_factor, fy=scale_factor)
    bordered = cv2.copyMakeBorder(small, border, border, border, border, cv2.BORDER_CONSTANT)

    for i in kernel_range:
        #kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*i+1, 2*i+1))
        kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (2*i+1, 2*i+1))
        bordered = cv2.morphologyEx(bordered, cv2.MORPH_CLOSE, kernel)

    unbordered = bordered[border: -border, border: -border]
    mask = cv2.resize(unbordered, (image.shape[1], image.shape[0]))
    fg = cv2.bitwise_and(image, image, mask=mask)
    return fg


# Load a color image in grayscale
img = cv2.imread('original/11.png')
# Start background removal -- Parameters are <image> and <threshold level>
nb_img = remove_background(img, 180)
# Change Black Pixels to WHITE
nb_img[np.where((nb_img==[0,0,0]).all(axis=2))] = [255,255,255]

# resize the viewing size (as the images are too big for the screen
small = cv2.resize(nb_img, (300, 400)) 

# Show the finished image
cv2.imshow('image',small)

k = cv2.waitKey(0) & 0xFF
if k == 27:  #wait for ESC key to exit
    # if ESC pressed close the camera windows
    cv2.destroyAllWindows()
elif k == ord('s'): #wait for 's' key to save and exit
    # Save the img(greyscale version)
    cv2.imwrite('bg_removal/11.png',small)
    cv2.destroyAllWindows()
J Elliot
  • 43
  • 1
  • 6