preamble
With the arrival of Christmas, everyone has @official weibo to add a Christmas hat to their avatar. Of course this kind of thing can be done with a lot of P picture software. But as a technical person who learns image processing, still feel we need to write a program to do this thing. And this can be completely as a practice small project, the workload is not big, and it is very interesting.
Tools used
- OpenCV (after all, that's what we're mostly about...)
- dlib (dlib's face detection works better than OpenCV, and dlib has keypoint detection that OpenCV doesn't have.)
The language used is Python, but it is possible to change it to C++, so I won't write about it because of time constraints. If you are interested, you can use it to practice.
workflows
I. Material preparation
First of all, we need to prepare a Christmas hat material, the format is best for the PNG, because PNG, we can directly use the Alpha channel as a mask. We use the Christmas hat as shown below:
We can get the alpha channel of the Christmas hat image by channel separation. The code is as follows:
r,g,b,a = (hat_img) rgb_hat = ((r,g,b)) ("hat_alpha.jpg",a)
In order to be able to operate with the rgb channel header image, we combine the rgb three channels into one rgb colored hat image. the Alpha channel image is shown below.
II. Face Detection and Face Keypoint Detection
We use the image below as our test image.
In the following, we use dlib's positive face detector for face detection and extract the five key points of the face using the model provided by dlib. The code is as follows:
# dlibFace Keypoint Detector predictor_path = "shape_predictor_5_face_landmarks.dat" predictor = dlib.shape_predictor(predictor_path) # dlib face detector detector = dlib.get_frontal_face_detector() # Face detection dets = detector(img, 1) # If a face is detected if len(dets)>0: for d in dets: x,y,w,h = (),(), ()-(), ()-() # x,y,w,h = faceRect (img,(x,y),(x+w,y+h),(255,0,0),2,8,0) # Critical point detection, 5 critical points shape = predictor(img, d) for point in (): (img,(,),3,color=(0,255,0)) ("image",img) ()
The effect of this part is shown below:
III. Adjusting the size of the hat
We select the points at the corners of the two eyes and seek the center as the reference coordinate in the x-direction for placing the hat, and the coordinate in the y-direction is represented by the y-coordinate on the upper line of the face frame. Then we adjust the size of the hat according to the size of the face obtained from the face detection to make the hat the right size.
# Pick the points at the corners of the left and right eyes point1 = (0) point2 = (2) # Find the center of two points eyes_center = ((+)//2,(+)//2) # (img,eyes_center,3,color=(0,255,0)) # ("image",img) # () # Adjust hat size to face size factor = 1.5 resized_hat_h = int(round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor)) resized_hat_w = int(round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor)) if resized_hat_h > y: resized_hat_h = y-1 # Adjust hat size to face size resized_hat = (rgb_hat,(resized_hat_w,resized_hat_h))
IV. Extracting hats and areas where hats need to be added
Go to the Alpha channel as mask as described previously. and invert it. One of these two masks is used to take the hat area out of the hat map, and one is used to empty out the area of the character map that needs to be filled with hats. You will see that later.
Use the alpha channel as a mask
mask = (a,(resized_hat_w,resized_hat_h)) mask_inv = cv2.bitwise_not(mask)
Take the area from the original image where the hat needs to be added, here we are using bitwise operations.
# Offset of the hat relative to the upper line of the face frame dh = 0 dw = 0 # Original ROI # bg_roi = img[y+dh-resized_hat_h:y+dh, x+dw:x+dw+resized_hat_w] bg_roi = img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]] center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)] # Extract the area where the hat was placed from the original ROI. bg_roi = bg_roi.astype(float) mask_inv = ((mask_inv,mask_inv,mask_inv)) alpha = mask_inv.astype(float)/255 # Ensure that they are the same size before multiplying (may not be consistent due to rounding) alpha = (alpha,(bg_roi.shape[1],bg_roi.shape[0])) # print("alpha size: ",) # print("bg_roi size: ",bg_roi.shape) bg = (alpha, bg_roi) bg = ('uint8')
This is the background area (bg) shown below. You can see that just the area that needs to be filled in for the hat is missing.
Then we extract the hat area.
# Extract the hat area hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)
The hat region obtained from the extraction is shown below. The hat region is exactly complementary to the previous background region.
V. Adding Christmas hats
Finally we add the two areas together. And then put back to the original picture, you can get the Christmas hat we want. Here you need to pay attention to is that, before adding resize to ensure that the size of the two consistent, because it may be due to rounding reasons are not consistent.
# Ensure both are the same size before adding (may not be due to rounding) hat = (hat,(bg_roi.shape1,bg_roi.shape[0])) # Add two ROI regions together add_hat = (bg,hat) # ("add_hat",add_hat) # Put the area where the hat was added back into the original image img[y+dh-resized_hat_h:y+dh,(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)] = add_hat
Finally we get the effect image shown below.
Source code address:/LiuXiaolong19920720/Add-Christmas-Hat
This is the whole content of this article.