Welcome to K230 Vision Module repository
4. Morphological Operations
Morphological Operations
Morphological OperationsPrefaceExample ResultsPrinciplesWhat Are Morphological OperationsStructuring ElementsCode OverviewImport ModulesInitialize Camera and Display ModuleSet Morphological ModeGrayscale and Binarization PreprocessingExecute Morphological OperationsWrap Grayscale Image and DisplayResource ReleaseParameter Adjustment Notes
Preface
This tutorial applies to firmware version: CanMV_K230_YAHBOOM_micropython_v1.8-13. Download from the official Canaan website at https://download.kendryte.com/developer/releases/canmv_k230_micropython/daily_build/

Example Results
Run the example code for this section: 02.camera_morphology.py.
This section first converts the camera color image to grayscale, then generates a binary image through OTSU automatic thresholding, and finally demonstrates erosion, dilation, opening, closing, morphological gradient, top hat, and black hat operations.
Results are shown below






Principles
What Are Morphological Operations
Morphological operations use a small matrix sliding over the image, called a structuring element or convolution kernel. It mainly processes white foreground in binary images. The shape and size of the kernel determine the neighborhood range.
- Erosion: White areas shrink, can remove small white spots.
- Dilation: White areas expand, can connect nearby areas.
- Opening: Erosion followed by dilation, commonly used to remove small white noise.
- Closing: Dilation followed by erosion, commonly used to fill small black holes and connect breaks.
- Morphological Gradient: Dilation result minus erosion result, highlights contours.
- Top Hat: Original image minus opening result, highlights small bright areas.
- Black Hat: Closing result minus original image, highlights small dark areas.
Structuring Elements
OpenCV supports rectangular, cross, and elliptical structuring elements. This example pre-allocates 5×5 rectangular and elliptical kernels:
KS = 5kr = cv2.getStructuringElement(cv2.MORPH_RECT, (KS, KS))ke = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (KS, KS))Creating kernels outside the loop avoids repeated array allocation per frame.
Code Overview
Import Modules
xxxxxxxxxximport time, os, sys, gcfrom media.sensor import *from media.display import *from media.media import *import cv2import ulab.numpy as npInitialize Camera and Display Module
xxxxxxxxxxW, H = 640, 480sensor = Sensor(width=1280, height=960, fps=90)sensor.reset()sensor.set_framesize(width=W, height=H)sensor.set_pixformat(Sensor.RGB888)Display.init(Display.ST7701, width=640, height=480, to_ide=True)sensor.run()time.sleep(0.5)Set Morphological Mode
xxxxxxxxxxmode = 2| mode | Processing Function | Description |
|---|---|---|
| 0 | erode | Erosion |
| 1 | dilate | Dilation |
| 2 | MORPH_OPEN | Opening, source code default |
| 3 | MORPH_CLOSE | Closing |
| 4 | MORPH_GRADIENT | Morphological gradient |
| 5 | MORPH_TOPHAT | Top hat |
| 6 | MORPH_BLACKHAT | Black hat |
Grayscale and Binarization Preprocessing
xxxxxxxxxximg = sensor.snapshot()img_np = img.to_numpy_ref()gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)OTSU automatically selects the threshold based on the current frame's grayscale histogram. ret saves the calculated threshold, and binary is a binary image containing only 0 and 255.
Execute Morphological Operations
xxxxxxxxxxif mode == 0: out = cv2.erode(binary, kr)elif mode == 1: out = cv2.dilate(binary, kr)elif mode == 2: out = cv2.morphologyEx(binary, cv2.MORPH_OPEN, ke)elif mode == 3: out = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, ke)elif mode == 4: out = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, ke)elif mode == 5: out = cv2.morphologyEx(binary, cv2.MORPH_TOPHAT, ke)else: out = cv2.morphologyEx(binary, cv2.MORPH_BLACKHAT, ke)Erosion and dilation use rectangular kernels, while other operations use elliptical kernels. This way you can observe basic operations and compare the effects of different shaped structuring elements on edges.
Wrap Grayscale Image and Display
xxxxxxxxxximg_out = image.Image( W, H, image.GRAYSCALE, alloc=image.ALLOC_REF, data=out)Display.show_image(img_out)ALLOC_REF directly references the out array without copying the full image. The array must remain valid until display is complete.
Resource Release
xxxxxxxxxxfinally: sensor.stop() Display.deinit() os.exitpoint(os.EXITPOINT_ENABLE_SLEEP) time.sleep_ms(100)Parameter Adjustment Notes
- Kernel size KS: Must be a positive number, typically odd numbers like 3, 5, 7. Larger kernel means stronger effect but higher computation.
- Foreground polarity: Erosion and dilation are defined for white foreground. If the target is black in the binary image, the visual effect will be opposite to expectations. You can use
THRESH_BINARY_INVinstead. - OTSU stability: Illumination changes cause the automatic threshold to vary per frame. For stable contrast, you can fix the illumination or use a fixed threshold.
- Number of iterations: The current call executes only once. For stronger effect, you can pass
iterations, but start from 1 and increase gradually. - Performance: Continuous morphological operations at 640×480 generate temporary arrays. If frame rate is insufficient, you can first drop to 320×240 to compare effects.