Face Callout Effect ✨
The zoom-in circle that explains every meme — FaceCalloutEffect
- image
- modified_image
You know the look: someone's face blown up in a circle, a curly arrow pointing at it, one face suddenly the star of the frame. That's exactly what this node does, automatically. Feed it any image, it finds the face, lifts it into a circular callout, and draws the little Bezier-curved line with an arrowhead connecting face to circle. It's the classic zoom-in annotation you've seen in a million explainer screenshots and meme templates, without you opening an image editor.
It runs entirely on CPU - OpenCV Haar cascades for detection, PIL for drawing - and it ships the detector with it. No model downloads, no API keys, no GPU. For a display/annotation node, that's refreshingly boring in the good way.
How it works
The node takes your image tensor, converts it to a PIL image, then runs OpenCV's CascadeClassifier with the bundled haarcascade_frontalface_default.xml. Detection is the stock detectMultiScale (scale factor 1.1, min neighbors 5, minimum face size 30×30). It grabs a square crop around the face, pads it per your settings, and pastes it as a circle at the callout position. The connecting line is a cubic Bezier - four control points in the curl_control_factor inputs define how much it arcs and curls. The arrowhead is drawn as a polygon at the end of that curve, pointing at the callout.
The inputs that matter
Most of the 17 inputs are cosmetic, and you'll only touch a few:
callout_pos_x_percent/callout_pos_y_percent- where the circle lands, as a fraction of image size. The default 0.8 / 0.15 is the classic top-right spot; that's the placement people actually want.callout_scale_factor- how big the circle is relative to the detected face.callout_border_colorandline_color- hex strings like#FFFFFF. Not color pickers, just plain strings.- The four
curl_control_factorvalues - this is the fiddly part. The defaults give a gentle S-curl; bump the Y factors to exaggerate the loop, drop them toward zero for a near-straight line. Expect to fiddle. fallback_behavior- what happens when no face is found:Return Original(safe default, image passes through untouched),Error, orBlank Image. If you're running this over a batch, keep it on Return Original unless you want the run to explode.multiple_face_behavior-Largest Face(default) orFirst Detected. There's no "pick face #3" option, so if you have a specific person in a group shot, crop them first.
The single output is modified_image, an IMAGE you can wire straight into a Preview or Save Image node.
Install
ComfyUI Manager, search "FaceCallout", hit install, restart. Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/theshubzworld/ComfyUI-FaceCalloutNode
then restart ComfyUI. There are no model files to fetch - the ~900KB Haar cascade ships inside the repo. One real gotcha: the pack doesn't declare opencv-python in a requirements.txt, so if you cloned manually and get an import error about cv2, you need it installed yourself:
pip install opencv-python
Issues you'll actually hit
The Haar cascade is old and simple. It's fast, but it misses small faces (under 30px), hard side profiles, and heavily stylized art - and if it misses, you get your fallback_behavior result, which is usually "nothing happened," which looks like a bug. Also note it's a single-image node: feed it a batch and it silently only processes the first frame. For most callout jobs that's fine - you're annotating one hero shot, not a whole video.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| face_padding_percent | FLOAT | 0.200–1 | — |
| callout_scale_factor | FLOAT | 0.80.1–3 | — |
| callout_pos_x_percent | FLOAT | 0.800–1 | — |
| callout_pos_y_percent | FLOAT | 0.150–1 | — |
| callout_border_thickness | INT | 30–20 | — |
| callout_border_color | STRING | #FFFFFF | — |
| line_color | STRING | #333333 | — |
| line_thickness | INT | 31–20 | — |
| line_start_face_ratio_x | FLOAT | 0.800–1 | — |
| line_start_face_ratio_y | FLOAT | 0.200–1 | — |
| curl_control_factor1_x | FLOAT | 0.30-1–1 | — |
| curl_control_factor1_y | FLOAT | -0.50-1–1 | — |
| curl_control_factor2_x | FLOAT | 0.70-1–1 | — |
| curl_control_factor2_y | FLOAT | 0.50-1–1 | — |
| arrow_head_size_factor | FLOAT | 0.080–0.3 | — |
| fallback_behavior | COMBO | Return Original | 3 options: Return Original, Error, Blank Image |
| multiple_face_behavior | COMBO | Largest Face | 2 options: First Detected, Largest Face |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| modified_image | IMAGE | — |