Welcome to K230 Vision Module repository
6. Corner and Centroid Detection
Corner and Centroid Detection
Corner and Centroid DetectionPrefaceExample ResultsPrinciple ExplanationWhat are Image Moments and CentroidsWhy Polygon Approximation Can Find CornersCode OverviewInitialize Camera and Display ModuleSet Contour Area ThresholdGrayscale, Binarization, and Contour ExtractionCalculate and Draw CentroidsExtract and Draw CornersDisplay, Statistics, and Resource ReleaseParameter Adjustment Notes
Preface
This tutorial is applicable to firmware version: CanMV_K230_YAHBOOM_micropython_v1.8-13. Download from Jianan official website https://download.kendryte.com/developer/releases/canmv_k230_micropython/daily_build/

Example Results
Run the example code for this section 04.camera_corners.py.
This section performs grayscale conversion and OTSU binarization on the real-time camera feed, extracts external contours, calculates contour centroids using image moments, and obtains contour corners using polygon approximation. The centroid is marked with a blue cross, and corners are marked with green solid circles.

Principle Explanation
What are Image Moments and Centroids
Image moments are a set of features obtained by weighted summation of contour coordinates and their distributions. The zeroth-order moment m00 corresponds to the contour area, and the first-order moments m10 and m01 can be used to calculate the centroid:
cx = m10 / m00cy = m01 / m00When m00 is 0, division is not possible, so the code must first check if m00 > 0.
Why Polygon Approximation Can Find Corners
approxPolyDP() uses the Douglas-Peucker algorithm to simplify contours, retaining only the points that have significant impact on the overall shape. A smaller error threshold preserves more points; a larger threshold simplifies the contour more. In this example, the error is set to 2% of the contour perimeter.
Note that this example obtains "contour approximation vertices", not texture corners in the sense of goodFeaturesToTrack() or Harris algorithm.
Code Overview
Initialize 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 Contour Area Threshold
xxxxxxxxxxMIN_A = 200Contours with area less than 200 pixels are ignored directly to reduce corners from binary noise.
Grayscale, Binarization, and Contour Extraction
xxxxxxxxxxgray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)contours, _ = cv2.findContours( binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)OTSU auto-threshold is suitable for scenes where foreground and background have significantly different grayscale distributions. RETR_EXTERNAL only takes external contours, and internal holes will not be processed as independent contours.
Calculate and Draw Centroids
xxxxxxxxxxmoments = cv2.moments(contour)if moments["m00"] > 0: cx = int(moments["m10"] / moments["m00"]) cy = int(moments["m01"] / moments["m00"]) cv2.drawMarker( img_np, (cx, cy), (255, 0, 0), cv2.MARKER_CROSS, 10, 2 )Centroid coordinates are converted to integers for drawing. The color tuple is passed according to the current image channel order.
Extract and Draw Corners
xperimeter = cv2.arcLength(contour, True)approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)
for point in approx: x = int(point[0][0]) y = int(point[0][1]) cv2.circle(img_np, (x, y), 5, (0, 255, 0), -1)
cv2.drawContours(img_np, [contour], -1, (255, 255, 0), 1)arcLength(contour, True) treats the contour as a closed curve. The source code processes up to 50 valid contours at most to prevent excessive drawing from complex backgrounds.
Display, Statistics, and Resource Release
xxxxxxxxxxDisplay.show_image(img)
if time.ticks_diff(time.ticks_ms(), ft) >= 1000: print("corners:", corner_count, "| fps:", fc)
finally: sensor.stop() Display.deinit() os.exitpoint(os.EXITPOINT_ENABLE_SLEEP) time.sleep_ms(100)Parameter Adjustment Notes
MIN_A: Decrease when small target corners are filtered out, increase when there are too many small contours in the background.
OTSU Foreground Polarity: If the target is divided into black, background external contours may be detected. Use THRESH_BINARY_INV or a fixed threshold.
Approximation Error 0.02: Increase when there are too many corners, decrease when corners are being merged.
Contour Upper Limit: The source code limit is 50. Actual projects should use ROI and area range to reduce candidate contours in advance.
Texture Corners: When detecting chessboard patterns, textures, or corners inside objects, use goodFeaturesToTrack() instead of treating contour vertices as corners for all types.