Hello Folks!!!! Bored with the old hairstyle and cannot go to your favorite salon during this lockdown?? Then, why don’t you create your own hairdresser at home. You must be wondering how is this possible?

Let’s check the below tutorial and it will surely amaze you !!!!!

Overview

In today’s tutorial, we are going our own OpenCV program to append a hairwig on your head.

The trick is quite simple. Firstly, we will be going to detect our face. Then crop the hair wig image and add it to your hairs and saving your filtered image at the end.

The underlying concept used here is Computer Vision and Image Processing.

Computer Vision:
In Computer Vision, computers or machines are made to gain high-level understanding from the input digital images or videos with the purpose of automating tasks that the human visual system can do. It uses many techniques and Image Processing is just one of them.

Image Processing:
Image Processing is the field of enhancing the images by tuning many parameter and features of the images. So Image Processing is the subset of Computer Vision. Here, transformations are applied to an input image and an the resultant output image is returned. Some of these transformations are- sharpening, smoothing, stretching etc.

Here we will be using haar cascade file and OpenCV library.

Haar cascade can be used for  face detection which is a machine learning algorithm where a cascade function is trained from a lot of positive and negative images. It is then used to detect objects in other images.

OpenCV already contains many pre-trained Haar classifiers such as smile which is used in this model.

To apply these pre-trained classifiers, follow the following steps:

  1. Load the XML file of required classifiers.
  2. Load image in gray-scale mode as OpenCV mostly operates in gray scale.
  3. Apply necessary classifiers on the image.

Importing the necessary files

We’ll be using four main libraries of python.

  • “cv2” for video capturing, frame reading, pixel management, color management of the video,
  • “NumPy” is used to do mathematical manipulation with the pixels of the video, flipping the order of matrices and
  • “datetime” for delays and imported os library.
  • “os” for performing operations on directory
import cv2 
import date time 
import os 
import numpy as np

Detecting Face

Now, I’ll be detecting the face and smile using the cascade file. For this, we need to load the required XML classifiers and our input image (or video) in grayscale mode.

cascade_face = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 
# if you want to add sticker on image
img = cv2.imread('image.png')

Function to detect the face

Now, we’ll find the face in the image. If faces are found, it returns the positions of detected faces as Rect(x,y,w,h). Once we get these locations, we can create a ROI for the face and apply smile detection on this ROI.

I have created a detection function that takes two arguments: the image and the grayscale i.e. black and white image. I have used haar cascade to detect the face and stored the result in face variable. x_face, y_face, w_face, h_face are 2 top coordinates and width , depth of face respectively. In the loop, we are importing the ear image and defining the area of interest in grayscale and coloured image.

# gray image of our face, original image:
def detection(grayscale, img):
    
    #1.3 is the scale factor , 5 is te min neighbours
    face = cascade_face.detectMultiScale(grayscale, 1.3, 5)
    
    #4 corrdinates in faces
    for (x_face, y_face, w_face, h_face) in face:
        

        img_wig= cv2.imread('hair2.png',-1)
        
        ## adjusing the width & dept
        width, depth, _= img_wig.shape
        width= int(w_face + 0.1* width)
        depth= int(h_face* 2/3)
        img_wig= cv2.resize(img_wig, (width, depth))
        
        ## coordinates
        centre_x= x_face+ w_face/2
        x_wig= int(centre_x-width/2)
        
        y_wig= int(y_face- (depth*2/3) )
        
        ##cropping 
        
        if x_wig<0:
            x_wig=0
        if y_wig<0    :
            y_wig=0
        y2=int(y_wig+depth)
        if(y2>= img.shape[0]):
            y2= img.shape[0]
        x2= int(x_wig+width)
        if(x2>= img.shape[1]):
            x2= img.shape[1]
           
           
        img_wig= img_wig[0: y2-y_wig, 0:x2-x_wig] 
        bg=  img[y_wig: y2, x_wig: x2]
        sg = np.atleast_3d(255 - img_wig[:, :,3])/255.0
        np.multiply(bg, sg, out=bg, casting="unsafe")
        np.add(bg, 255-img_wig[:, :,0:3] * np.atleast_3d(img_wig[:, :,3]), out=bg)
        img[y_wig: y2, x_wig: x2] = bg
        
        return img 
    #return image        

Here we are importing the hair image and resizing the image according to the required dimensions. We are finding the centre of face and the x,y coordinates to place wig at the desired location.

Functions Used

cv2.imread() method loads an image from the specified file. If the image cannot be read (because of missing file, improper permissions, unsupported or invalid format) then this method returns an empty matrix.

cv2.resize() method resizes the image. Resizing an image means changing the dimensions of it, be it width alone, height alone or both. Also, the aspect ratio of the original image could be preserved in the resized image.and opencv provides cv2.resize function to resize the image.

Numpy provides the powerful data structure known as n-d array and function to manipulate that n-d array. This data structure is used by other library to represent complex data such as images. Therefore we have used numpy function to parse the image of tongue and replace the white colour by black. Note that white coordinates are [255,255,255] and black coordinates as [0, 0, and 0]. It will create a 3d array of all the pixel values. We are then multiplying both images and adding them, then saving back in the bg variable and storing the values in the image variable.

Functions of Numpy Used in computation :–

numpy.atleast_3d() function is used when we want to Convert inputs to arrays with at least three dimension. Scalar, 1 and 2 dimensional inputs are converted to 3-dimensional arrays, whilst higher-dimensional inputs are preserved. Input includes scalar, lists, lists of tuples, tuples, tuples of tuples, tuples of lists and ndarrays.

numpy.multiply() function is used when we want to compute the multiplication of two array. It returns the product of arr1 and arr2, element-wise.

numpy.add() function is used when we want to compute the addition of two array. It add arguments element-wise. If shape of two arrays are not same, that is arr1.shape != arr2.shape, they must be broadcastable to a common shape (which may be the shape of one or the other).

Capturing the Image and calling the function to add sticker

Now, I have created a variable to capture the video and set the path to store the output file. If the file already exists, then we will update the path therefore, the code is placed in try catch block to handle these exceptions.

vc = cv2.VideoCapture(0) 
#path
path= os.getcwd()

# Create directory
dirName = 'tempimage_folder'
try:
        os.mkdir(dirName)
except FileExistsError:
        print("Directory " , dirName ,  " already exists")
path= path+'/'+dirName

Now, after creating the directory, we have to capture the image and convert it into grayscale using cv2.cvtColour() function.Then, we’ll pass the arguments in detection function and store the result in final variable.

After getting the result we’ll display the image using cv2.imshow() function and then save image with name and current date and time appended. We’ll save the file using the cv2.imwrite() function which writes the next video frame.

cv2.waitKey()  is a keyboard binding function. Its argument is the time in milliseconds. The function waits for specified milliseconds for any keyboard event. If you press any key in that time, the program continues. If 0 is passed, it waits indefinitely for a key stroke. It can also be set to detect specific key strokes like, if key a is pressed etc which we will discuss below.

cv2.destroyallWindows()  simply destroys all the windows we created. If you want to destroy any specific window, use the function  cv2.destroyWindow() where you pass the exact window name as the argument.

cnt=0
while cnt<500:
    #read status of camera and frame
    _, img = vc.read() 
    
    #convert image ot grayscale
    grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
    
    #reuslt from detection function
    final = detection(grayscale, img) 
    
    if final is not None:
        cv2.imshow('Video', final) 
    
    #name of our image, wiht current time , so that it has new name each time.
    string = "pic"+str(datetime.datetime.now())+".jpg"
    
    
    #save image
    cv2.imwrite(os.path.join(path, string),final)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break 
    
    cnt+=1

vc.release() 
cv2.destroyAllWindows() 

Implementation

Conclusion

So guys, we have successfully created our own python program to add hair wig on our face using OpenCV and Image Processing.

Feel free to share your thoughts in the comments section.

-Suniti Jain


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert