Face parsing segments faces into semantic components or face regions.
BiSeNet face parsing with 19 semantic component classes XSeg face region segmentation mask
Available Models
Model
Backbone
Size
Output
BiSeNet ResNet18
ResNet18
51 MB
19 classes
BiSeNet ResNet34
ResNet34
89 MB
19 classes
XSeg
-
67 MB
Mask
Basic Usage
importcv2fromuniface.parsingimportBiSeNetfromuniface.drawimportvis_parsing_maps# Initialize parserparser=BiSeNet()# Load face image (cropped)face_image=cv2.imread("face.jpg")# Parse facemask=parser.parse(face_image)print(f"Mask shape: {mask.shape}")# (H, W)# Visualize (BGR in, BGR out — same convention as cv2)vis_result=vis_parsing_maps(face_image,mask,save_image=False)# Save resultcv2.imwrite("parsed.jpg",vis_result)
importcv2fromuniface.detectionimportRetinaFacefromuniface.parsingimportBiSeNetfromuniface.drawimportvis_parsing_mapsdetector=RetinaFace()parser=BiSeNet()image=cv2.imread("photo.jpg")faces=detector.detect(image)fori,faceinenumerate(faces):# Crop facex1,y1,x2,y2=map(int,face.bbox)face_crop=image[y1:y2,x1:x2]# Parsemask=parser.parse(face_crop)# Visualize (BGR in, BGR out)vis_result=vis_parsing_maps(face_crop,mask,save_image=False)# Savecv2.imwrite(f"face_{i}_parsed.jpg",vis_result)
Extract Specific Components
Get Single Component Mask
importnumpyasnp# Parse facemask=parser.parse(face_image)# Extract specific componentSKIN=1HAIR=17LEFT_EYE=4RIGHT_EYE=5# Binary mask for skinskin_mask=(mask==SKIN).astype(np.uint8)*255# Binary mask for hairhair_mask=(mask==HAIR).astype(np.uint8)*255# Binary mask for eyeseyes_mask=((mask==LEFT_EYE)|(mask==RIGHT_EYE)).astype(np.uint8)*255
importcv2importnumpyasnpdefapply_lip_color(image,mask,color=(180,50,50)):"""Apply lip color using parsing mask."""result=image.copy()# Get lip mask (upper lip=12, lower lip=13)lip_mask=((mask==12)|(mask==13)).astype(np.uint8)# Create color overlayoverlay=np.zeros_like(image)overlay[:]=color# Alpha blend lip regionalpha=0.4mask_3ch=lip_mask[:,:,np.newaxis]result=np.where(mask_3ch,(image*(1-alpha)+overlay*alpha).astype(np.uint8),result)returnresult
Background Replacement
defreplace_background(image,mask,background):"""Replace background using parsing mask."""# Create foreground mask (everything except background)foreground_mask=(mask!=0).astype(np.uint8)# Resize background to match imagebackground=cv2.resize(background,(image.shape[1],image.shape[0]))# Combineresult=image.copy()result[foreground_mask==0]=background[foreground_mask==0]returnresult
Hair Segmentation
defget_hair_mask(mask):"""Extract clean hair mask."""hair_mask=(mask==17).astype(np.uint8)*255# Clean up with morphological operationskernel=np.ones((5,5),np.uint8)hair_mask=cv2.morphologyEx(hair_mask,cv2.MORPH_CLOSE,kernel)hair_mask=cv2.morphologyEx(hair_mask,cv2.MORPH_OPEN,kernel)returnhair_mask
Visualization Options
fromuniface.drawimportvis_parsing_maps# Default visualization (BGR in, BGR out)vis_result=vis_parsing_maps(face_image,mask)# With different parametersvis_result=vis_parsing_maps(face_image,mask,save_image=False,# Don't save to file)
XSeg
XSeg outputs a mask for face regions. Unlike BiSeNet which works on bbox crops, XSeg requires 5-point landmarks for face alignment.
Basic Usage
importcv2fromuniface.detectionimportRetinaFacefromuniface.parsingimportXSegdetector=RetinaFace()parser=XSeg()image=cv2.imread("photo.jpg")faces=detector.detect(image)forfaceinfaces:ifface.landmarksisnotNone:mask=parser.parse(image,landmarks=face.landmarks)print(f"Mask shape: {mask.shape}")# (H, W), values in [0, 1]
Parameters
fromuniface.parsingimportXSeg# Default settingsparser=XSeg()# Custom settingsparser=XSeg(align_size=256,# Face alignment sizeblur_sigma=5,# Gaussian blur for smoothing (0 = raw))
Parameter
Default
Description
align_size
256
Face alignment output size
blur_sigma
0
Mask smoothing (0 = no blur)
Methods
# Full pipeline: align -> segment -> warp back to original spacemask=parser.parse(image,landmarks=landmarks)# For pre-aligned face cropsmask=parser.parse_aligned(face_crop)# Get mask + crop + inverse matrix for custom warpingmask,face_crop,inverse_matrix=parser.parse_with_inverse(image,landmarks)