Nodes/ComfyUI CV/cv2.motempl.updateMotionHistory
ComfyUI Node

cv2.motempl.updateMotionHistory

An image that remembers when things moved

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.motempl.updateMotionHistory
  • silhouette
  • mhi
  • nparray
◄timestamp0.0000►
◄duration0.0000►

OpenCV's motion templates come from the Bobick–Davis motion-history work and have shipped as a sample for two decades. The idea is delightfully cheap: instead of tracking objects, keep a float image where each pixel stores the timestamp of the last time it moved. That's the MHI - the motion history image - and this node is the only thing that writes to it.

It's the first of three steps. cv2.motempl.updateMotionHistory stamps the current motion into the history; cv2.motempl.calcMotionGradient turns the resulting stamp field into a per-pixel direction plus a validity mask; cv2.motempl.calcGlobalOrientation collapses that into one angle. The pack wraps those three; segmentMotion, the fourth member of the family, isn't exposed - its variable-length segment array doesn't fit the generated wrapper's shape.

What it does, precisely

The author's own tooltips are unusually good here, and worth trusting over a guess. silhouette is a "binary mask of what is moving RIGHT NOW" - a frame difference, or the foreground from a background subtractor. mhi is the "running float32 motion-history image carried from the previous frame"; silhouette pixels get stamped with timestamp, and anything older than duration is cleared, so the MHI encodes when each pixel last moved. timestamp is "any consistent unit, e.g. seconds or frame index" and must increase every frame. duration is how long motion stays in the history, in the same unit.

Start with a zeros image at float32 - the pack's constant-array bridge node (CV_ScalarArray, an empty value and a float32 dtype) is the way to author one in a graph. The single output socket is nparray - the new MHI, an NPARRAY - and the intent is that you feed it back in next frame.

Reading the result: non-zero means "moved within the last duration", and the value itself is when. Normalize to 0–255 with cv2_normalize (NORM_MINMAX) and you get the classic comet-trail visual, where recent motion is bright and old motion has faded out.

Where the silhouette comes from is your choice. The pack's background-subtraction workflow and subgraphs do the frames-differ and the subtractor versions; the KB's masking doc has the broader menu of ways to get a foreground mask. For a first run, cv2_absdiff between two frames plus a threshold is plenty.

The honest problem: this node is stateful in a graph that doesn't iterate

ComfyUI has no native loop construct, and an MHI is meaningless without one. Three things follow, and they're the reason people bounce off motion templates here:

  • You need a loop node. A for-each/while node from another pack, iterating frames and threading the MHI output back into the mhi input, is the real solution. Without one, you're stepping the queue by hand.
  • Batching does not accumulate. An IMAGE link is read as frame 0 of a batch by this wrapper family, and buffers are per-run, so handing it a batch gives you one frame's history, not a growing one.
  • Manual stepping needs somewhere to keep the value. A value-storing node (a Set/Get pair) lets you carry the MHI from one queue press to the next, which is enough for a two-or-three-frame demo and miserable for a sequence.

If a single-frame demo is all you want, timestamp = 1 with duration = 5 in frame units is a legitimate tiny history, and the gradient/orientation pair downstream works on it like any other MHI.

Install

ComfyUI Manager → search ComfyUI CV → install → restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12, ComfyUI on the V3 node API. cv2.motempl is a contrib submodule: no contrib wheel, no node. The usual way to break it is installing a non-contrib opencv-python(-headless) over the contrib wheel - same shared site-packages/cv2, contrib submodules gone. tools/repair_opencv_contrib.py --check / --apply in the pack handles the diagnosis and repair.

Categoryimage/CV/low-level/motempl

Inputs (4)

NameTypeDefaultDescription
silhouetteNPARRAY,IMAGE,MASK - - - Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
mhiNPARRAY,IMAGE,MASK - - - Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
timestampFLOAT0.0000-1e+38–1e+38 - - -
durationFLOAT0.0000-1e+38–1e+38 - - -

Outputs (1)

NameTypeDescription
nparrayNPARRAY—