In OpenCV, what is the difference between MORPH_OPEN and MORPH_CLOSE?
answer
- one is erode-then-dilate
- the other reverses that order
- specks out versus holes in
- second pass restores the size
- polarity decides which is which
basics
~20 sMORPH_OPEN erodes then dilates: it removes small white specks and thin bridges. MORPH_CLOSE dilates then erodes: it fills small holes and joins nearby blobs. Both roughly preserve blob size, unlike a bare erode or dilate.
solid answer
~40 sBoth are compound operations passed to `cv2.morphologyEx` with a structuring element from `cv2.getStructuringElement`. **Opening** is erosion followed by dilation with the same kernel: the erosion deletes anything thinner than the kernel - isolated specks, thin bridges between touching parts - and the dilation restores the surviving blobs to roughly their original size. **Closing** is the reverse, dilation then erosion: the dilation seals pinholes and small gaps inside or between blobs, and the erosion shrinks the result back. The key point is that the second pass undoes the size change of the first, so unlike a bare `cv2.erode` or `cv2.dilate` neither op systematically shrinks or grows your objects. On a binary mask these definitions assume white foreground; if the objects are black, open and close swap roles.
code
python · 13 linesimport cv2
import numpy as np
binary = np.zeros((100, 100), np.uint8)
cv2.rectangle(binary, (20, 20), (80, 80), 255, -1)
binary[50, 50] = 0 # pinhole inside the blob
binary[5, 5] = 255 # isolated speck outside it
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
print(opened[5, 5], closed[50, 50]) # 0 (speck gone), 255 (hole filled)go deeper
Memorise the two orders and their effects: open removes small white specks, close fills small holes. Being able to name cv2.morphologyEx and getStructuringElement is enough at this level.
Explain why the compound ops preserve object size where a bare erode or dilate does not, and that erosion is a minimum filter so everything depends on whether foreground is white.
Show the sequencing judgment - open before close so noise is never bridged into a real part - and tie kernel size to physical feature scale rather than tuning it by eye until the demo image looks right.
Own the question of when morphology is patching a defect that belongs upstream: unstable lighting, a bad threshold choice, or wrong optics. Kernel sizes baked per-site are a maintenance liability worth naming.
## The two primitives underneath Morphology slides a **structuring element** (a small binary kernel) over the image. `cv2.erode` sets a pixel to the minimum under the kernel: for a white-on-black mask, a foreground pixel survives only if the whole kernel fits inside the object, so objects shrink and anything thinner than the kernel disappears. `cv2.dilate` takes the maximum: a pixel becomes foreground if the kernel touches any foreground, so objects grow and small gaps fill. Both are destructive to size. Erode enough to kill a speck and your real parts have lost a ring of pixels; dilate enough to close a gap and every part is fatter. That size drift is what the compound ops exist to fix. ## Opening = erode, then dilate `cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)` is exactly `cv2.dilate(cv2.erode(src, kernel), kernel)`. The erosion is the decision step: anything the kernel cannot fit inside is annihilated and, crucially, **cannot come back** - dilation only regrows what still exists. So opening deletes isolated white specks, hairline scratches, and thin bridges where two parts touch, while blobs large enough to contain the kernel are restored to approximately their original extent. Their corners get slightly rounded by the kernel shape, which is the price. Use opening for: sensor noise on a thresholded mask, separating parts joined by a one-or-two-pixel bridge before counting them, and removing the speckle that adaptive thresholding leaves in flat regions. ## Closing = dilate, then erode `cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)` is `cv2.erode(cv2.dilate(src, kernel), kernel)`. Here the dilation is the decision step: gaps narrower than the kernel are bridged permanently, because the following erosion peels the outside back but cannot reopen an interior that is now solid. Closing fills pinholes inside blobs, seals the broken strokes of a character or a barcode bar, and merges fragments of one object that thresholding split apart. Use closing for: pinholes from specular highlights, a dashed or broken outline you want continuous, and joining a shape whose interior thresholded unevenly. ## Order matters and is not commutative Opening then closing is not the same as closing then opening. The usual industrial sequence is **open first, then close**: kill the noise before you start bridging things, otherwise closing will happily fuse a noise speck to a real part and opening can no longer separate them. Both ops are idempotent for a fixed kernel - running MORPH_OPEN twice changes nothing beyond the first pass - which is why the `iterations` argument of `morphologyEx` matters differently than for plain erode: for OPEN and CLOSE it repeats the whole compound operation, and with a fixed kernel that is close to a no-op after the first round. If you need a stronger effect, grow the kernel rather than raising `iterations`. ## Choosing the kernel `cv2.getStructuringElement(shape, ksize)` builds it, with `cv2.MORPH_RECT`, `cv2.MORPH_ELLIPSE` or `cv2.MORPH_CROSS`. Size is the real tuning knob and it should be tied to physical scale: the kernel must be larger than the noise you want gone and smaller than the smallest feature you must keep. If those two constraints conflict, morphology is the wrong tool and you need a better threshold or better lighting. Shape matters for anisotropic work: a `(1, 15)` rectangle erodes only horizontally, which is the standard trick for isolating table rules or long horizontal strokes in document images and dropping the text. `MORPH_ELLIPSE` is the safe default for blobs because it rounds corners more naturally than `MORPH_RECT`. ## Beyond open and close `morphologyEx` takes further ops with the same kernel: `cv2.MORPH_GRADIENT` (dilate minus erode) gives a one-kernel-wide outline; `cv2.MORPH_TOPHAT` (src minus opening) isolates bright details smaller than the kernel, which is a strong background-flattening trick on unevenly lit scans; `cv2.MORPH_BLACKHAT` (closing minus src) does the same for dark details; `cv2.MORPH_HITMISS` matches an exact local pattern. ## The polarity trap Every description above assumes foreground is white (255) and background is black (0). Erode is a minimum filter, full stop - it does not know what you consider an object. Threshold a dark-on-light scan with `cv2.THRESH_BINARY` instead of `THRESH_BINARY_INV`, and your opening call will be closing your characters instead of despeckling them. When a clean-up step appears to do the exact opposite of what you asked, check the polarity of the mask first.
- Why not just use cv2.erode to remove noise instead of MORPH_OPEN?Because erode alone shrinks every surviving object by the kernel radius, so areas, widths and centroids all drift and thin real features may vanish. Opening's dilation pass regrows what survived to roughly its original size, so noise is removed without biasing the measurements you take afterwards.
- If MORPH_OPEN with a 3x3 kernel is not removing enough noise, should you raise iterations?Usually not. Opening is essentially idempotent for a fixed kernel, so repeating it adds little. Grow the structuring element instead - a 5x5 or 7x7 element - which raises the size threshold of what gets deleted. Just check the larger kernel still fits inside your smallest real feature.
- You need to strip long horizontal table rules from a scanned form but keep the text. Which morphology setup?Build an anisotropic element, for example cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1)), and open the inverted mask with it. Only structures at least 40 pixels wide and continuous survive the erosion, so you isolate the rules; subtract them from the mask to leave the text.
saying these in an interview costs you the question
- Says opening is dilate then erode
- Thinks close removes noise and open fills holes
- Claims erode alone is equivalent to opening
- Raises iterations instead of enlarging the kernel
- Ignores that the mask polarity swaps the two effects