Nodes/comfyui_cv/CV Filter Contours By Shape
ComfyUI Node

CV Filter Contours By Shape

Keeps the contours that look like a reference shape (cv2.matchShapes on Hu moments). The distance ignores translation, scale and rotation by design, and REFLECTION by accident: only the 7th Hu invariant's sign changes under mirroring, and matchShapes skips any term below its internal eps = 1e-5, which |h7| usually is. Measured on this build: an 'F' glyph and its mirror are indistinguishable (~0 on I1/I2/I3) - and the mirror can even rank ABOVE a correctly-handed but rotated shape - while a hook shape with a larger |h7| scores 0.50. So mirror sensitivity here is a cliff, not a property, and is never a usable handedness test. The scale/rotation/mirror policies below are what put those dimensions back; left at their defaults this node behaves exactly as it always has. Identical shapes score 0; similar ones stay below ~0.1-0.3 with CONTOURS_MATCH_I1. Make the reference with 'CV Select Contour' (e.g. the largest blob) or a second Find Contours over a template image; when the reference set has several contours its first one is used. Output is sorted most-similar first, with every per-match output aligned to it. Failure-tolerant: an empty reference or zero matches yields an empty set (count = 0), not an error.

By bmad4ever·Created 3 months ago·Updated 2 days ago· 0
CV Filter Contours By Shape
  • contours
  • reference
  • contours
  • count
  • distances
  • scale_ratios
  • rotations
  • mirrored
  • transforms
methodCONTOURS_MATCH_I1
max_distance0.30
scale_modeany scale (invariant)
scale_tolerance0.10
rotation_modeany rotation (invariant)
rotation_tolerance_deg10
mirror_modeeither handedness (invariant)
min_chirality0.010
Categoryimage/CV/contours

Inputs (10)

NameTypeDefaultDescription
contoursCV_CONTOURSCandidates to test.
referenceCV_CONTOURSThe shape to compare against (first contour of the set).
methodCOMBOCONTOURS_MATCH_I1How the Hu-moment signatures are compared (I1 is the usual choice; I2/I3 are alternative norms).
max_distanceFLOAT0.300–1000000Largest accepted dissimilarity (0 = identical). Raise it to 1e6 and inspect the distances output to calibrate.
scale_modeoptCOMBOany scale (invariant)Hu moments ignore size. 'same scale as reference' additionally requires the candidate to be about as big as the reference - the ratio of sqrt(m00), so 0.5 means half the linear size.
scale_toleranceoptFLOAT0.100–100Accepted size band as a fraction: 0.10 accepts 0.91x to 1.10x of the reference (symmetric in the ratio, so growing and shrinking are treated alike). 0 demands an exact match. Ignored unless scale is 'same scale as reference'.
rotation_modeoptCOMBOany rotation (invariant)'same orientation as reference' keeps only candidates standing the same way up. 'same orientation or 180 deg flipped' also accepts the upside-down copy - USE IT for 2-fold symmetric shapes (ellipse, rectangle), whose 0-360 orientation flips arbitrarily. Both are meaningless for a shape with no well-defined orientation: check 'pose_confidence' first (a rotating square reads 0, 140, 145, 155, 135 degrees - pure noise).
rotation_tolerance_degoptFLOAT100–180Half-width of the accepted rotation window in degrees. Compared CIRCULARLY, so 359 degrees counts as 1 degree away from 0.
mirror_modeoptCOMBOeither handedness (invariant)The matchShapes distance is a poor handedness test, so decide it here instead. Only the 7th Hu invariant's SIGN changes under reflection (OpenCV: "invariants to the image scale, rotation, and reflection except the seventh one, whose sign is changed by reflection"), and matchShapes skips any term below its internal eps = 1e-5 - which |h7| usually is. Measured: an 'F' and its mirror are indistinguishable (~0), while a hook with a bigger |h7| scores 0.50. 'same handedness only' drops reflected copies; 'mirrored only' keeps just the reflected ones. A mirror-symmetric shape (square, circle, isoceles triangle) is its own mirror, so it counts as UNDECIDED: kept by 'same handedness only', dropped by 'mirrored only'.
min_chiralityoptFLOAT0.0100–1How chiral a shape must be before mirroring can be decided at all - the magnitude of the 'chirality' value. This knob exists because the 7th Hu invariant is the one routinely discarded in practice: it is the smallest and the most fragile, and OpenCV's own docs note the invariance is proved "with the assumption of infinite image resolution", so "in case of raster images, the computed Hu invariants for the original and transformed images are a bit different". Rasterizing a symmetric shape therefore produces a small NON-zero h7 whose sign is meaningless. Measured magnitudes: an 'F' glyph 0.020-0.048, a scalene triangle 0.0069, a rasterized symmetric shape up to ~0.005 of pure noise, a square exactly 0. Below this on EITHER side the match is reported as mirrored = 0 (undecidable) rather than guessed. Set 0 to trust the sign always.

Outputs (7)

NameTypeDescription
contoursCV_CONTOURSThe matching contours, most similar first.
countINT
distancesNPARRAYfloat32 matchShapes distance per kept contour (aligned with the contour output).
scale_ratiosNPARRAY(N,) float32 size of each kept contour relative to the reference - the ratio of sqrt(m00), so 0.5 means half the linear size. 0.0 when either shape has no usable area.
rotationsNPARRAY(N,) float32 rotation in degrees, 0-360, taking the reference onto each kept contour (Y down, so it turns clockwise on screen). For a MIRRORED match it is the rotation applied AFTER flipping the reference about its vertical axis. Noise for a shape with no well-defined orientation - check 'pose_confidence' on 'CV Shape Moments'.
mirroredNPARRAY(N,) float32 handedness verdict per kept contour: +1 reflected, -1 same handedness, 0 undecidable (one of the two shapes is mirror-symmetric, or is less chiral than 'min_chirality').
transformsNPARRAY(N,2,3) float32 similarity matrix per kept contour, mapping REFERENCE coordinates onto that contour (mirror, then scale, then rotate, then centroid to centroid). Pull one row out with 'CV Slice Array' (axis 0) and feed cv2_transform with the reference points from 'CV Contour To Points' to draw the reference over its match, or cv2_warpAffine to warp a whole template image onto it.