From opencv-python-consistency
Write, review, refactor, or debug Python computer-vision code with OpenCV / cv2 (imread, cvtColor, resize, findContours, VideoCapture, thresholding, drawing) using one canonical idiom set. Use this skill whenever code loads, transforms, displays, or saves images and video with cv2, or when the user hits blue-tinted images in matplotlib, "NoneType has no attribute shape", swapped width/height, contour unpacking errors, cv2.imshow crashing on a server, or weirdly dark/wrapped pixel math. Trigger it even when the user just says "detect the edges in this photo" or "read frames from this video" in Python — without saying the word "OpenCV."
How this skill is triggered — by the user, by Claude, or both
Slash command
/opencv-python-consistency:opencv-python-consistencyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
cv2's API is stable; the inconsistency is *conventions*: BGR channel order against the
cv2's API is stable; the inconsistency is conventions: BGR channel order against the
RGB rest-of-the-world, (x, y) points against numpy's [row, col] indexing,
(width, height) sizes against .shape's (height, width), functions that return
None instead of raising, and uint8 arithmetic that wraps under numpy but saturates
under cv2. Generated code mixes these per line. This skill pins the canonical
conventions for OpenCV 4.x.
| Always | Never | Why |
|---|---|---|
img = cv2.imread(p); if img is None: raise FileNotFoundError(p) | using img unchecked | imread returns None on missing/corrupt files — the error surfaces later as a cryptic NoneType attribute crash. |
cv2.cvtColor(img, cv2.COLOR_BGR2RGB) before matplotlib/PIL/ML models | passing BGR onward | cv2 is BGR; everything else is RGB. Skipping the conversion = blue-orange swapped images and silently degraded model accuracy. |
h, w = img.shape[:2] and pass cv2 sizes as (w, h) | conflating the two orders | .shape is (height, width[, channels]); resize/warp* take (width, height); points are (x, y); indexing is img[y, x]. |
cv2.add/cv2.subtract/cv2.addWeighted for uint8 pixel math | img1 + img2 on uint8 | numpy wraps (250+10=4); cv2 saturates (=255). Wrapping shows as speckle noise, not an error. |
convert deliberately: img.astype(np.float32) / 255.0 in, np.clip(x * 255, 0, 255).astype(np.uint8) out | mixing float and uint8 mid-pipeline | Display/save expect uint8 0–255; float 0–1 shown as uint8 is black. |
contours, _ = cv2.findContours(bin_img, mode, method) (4.x signature) | copy-pasted 3.x triple unpacking | 3.x returned (image, contours, hierarchy); 4.x returns two values — unpacking mismatches crash or, worse, bind the wrong thing. |
grayscale explicitly: cv2.imread(p, cv2.IMREAD_GRAYSCALE) or cvtColor | assuming single-channel | Channel-count assumptions break threshold/contour code with shape errors far downstream. |
| matplotlib (after BGR2RGB) or file output in headless/server/notebook contexts | cv2.imshow everywhere | imshow needs a GUI build/display; on servers and opencv-python-headless it crashes or hangs (and always needs waitKey). |
cap = cv2.VideoCapture(p); check cap.isOpened(); loop ret, frame = cap.read() checking ret; cap.release() | reading frames unchecked | Capture failures are flags, not exceptions; unchecked ret hands you None frames. |
binary masks via _, mask = cv2.threshold(gray, t, 255, cv2.THRESH_BINARY) (or cv2.inRange) | thresholding color images implicitly | Threshold semantics differ per channel; be explicit about the single-channel input. |
House style:
import cv2
import numpy as np
img = cv2.imread("parts.png")
if img is None:
raise FileNotFoundError("parts.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) < 100:
continue
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # BGR green
cv2.imwrite("annotated.png", img)
roi = img[y:y+h, x:x+w] aliases the original — drawing on
roi draws on img. .copy() when independence is intended.rectangle, putText, …) and also returns the image —
chains that assume a copy corrupt the source.imwrite
infers format from the extension — a typo'd extension changes the codec silently.cv2.imwrite expects BGR: saving an RGB-converted array swaps colors back in
the file. Convert only at the true boundary.imread default drops alpha (loads 3-channel); use
cv2.IMREAD_UNCHANGED when transparency matters.waitKey is the GUI event pump: imshow without waitKey shows nothing/freezes;
cv2.destroyAllWindows() at the end.imread fails (→ None) on some platforms; decode via
cv2.imdecode(np.fromfile(p, np.uint8), flags) when paths aren't plain.cv2.resize interpolation: downscale with INTER_AREA, upscale with
INTER_LINEAR/INTER_CUBIC — the default (linear) moiré-aliases big downscales.Target OpenCV 4.x (pip install opencv-python; opencv-python-headless on servers —
no GUI functions; opencv-contrib-python for contrib modules like SIFT-adjacent extras;
install exactly one of these variants). The 3.x→4.x change models still trip on:
findContours two-value return. Legacy constants (cv2.CV_*, cv.*) are 2.x-era.
img.shape/img.dtype before any processing.cap.read, missing BGR↔RGB conversions at
matplotlib/model boundaries, + on uint8 images, 3.x findContours unpacking,
imshow in headless code, (h, w) passed where (w, h) belongs.For the conversion-code catalog, dtype/range table, contour/morphology recipes, and video
I/O patterns, read references/opencv-python-patterns.md.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub guidogl/opencv-python-consistency --plugin opencv-python-consistency