Nodes/ComfyUI-FaceCalloutNode/Face Callout Effect ✨
ComfyUI Node

Face Callout Effect ✨

The zoom-in circle that explains every meme — FaceCalloutEffect

By theshubzworld·Created about a year ago·Updated 9 months ago· 0
Face Callout Effect ✨
  • image
  • modified_image
face_padding_percent0.20
callout_scale_factor0.8
callout_pos_x_percent0.80
callout_pos_y_percent0.15
callout_border_thickness3
callout_border_color#FFFFFF
line_color#333333
line_thickness3
line_start_face_ratio_x0.80
line_start_face_ratio_y0.20
curl_control_factor1_x0.30
curl_control_factor1_y-0.50
curl_control_factor2_x0.70
curl_control_factor2_y0.50
arrow_head_size_factor0.08
fallback_behaviorReturn Original
multiple_face_behaviorLargest Face

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_color and line_color - hex strings like #FFFFFF. Not color pickers, just plain strings.
  • The four curl_control_factor values - 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, or Blank 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) or First 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.

Categoryimage/Annotation

Inputs (18)

NameTypeDefaultDescription
imageIMAGE
face_padding_percentFLOAT0.200–1
callout_scale_factorFLOAT0.80.1–3
callout_pos_x_percentFLOAT0.800–1
callout_pos_y_percentFLOAT0.150–1
callout_border_thicknessINT30–20
callout_border_colorSTRING#FFFFFF
line_colorSTRING#333333
line_thicknessINT31–20
line_start_face_ratio_xFLOAT0.800–1
line_start_face_ratio_yFLOAT0.200–1
curl_control_factor1_xFLOAT0.30-1–1
curl_control_factor1_yFLOAT-0.50-1–1
curl_control_factor2_xFLOAT0.70-1–1
curl_control_factor2_yFLOAT0.50-1–1
arrow_head_size_factorFLOAT0.080–0.3
fallback_behaviorCOMBOReturn Original3 options: Return Original, Error, Blank Image
multiple_face_behaviorCOMBOLargest Face2 options: First Detected, Largest Face

Outputs (1)

NameTypeDescription
modified_imageIMAGE