Quick Start
Get the Development Board
Visit the Purchase Link to get a CanMV-K230 development board.
Flash Firmware
Download firmware from GitHub or the Canaan Developer Community. After downloading the firmware for your board, follow the Firmware Flashing Guide to flash it to the board.
Download CanMV-IDE
CanMV-K230 supports development with CanMV-IDE. You can run code, view results, and preview images through the IDE. Go to Download CanMV-IDE. For detailed usage, refer to the IDE User Guide.
Run Demo Programs
The CanMV-K230 firmware includes many pre-installed demo programs that you can run without downloading from the network. Open examples from the virtual USB drive in the IDE to run them quickly. For detailed steps, refer to How to Run Demo Programs.
- After flashing firmware and connecting the K230 to CanMV, open CanMV IDE K230 and copy the following code into it:
from libs.PipeLine import PipeLine, ScopedTiming
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
import os
import ujson
from media.media import *
from time import *
import nncase_runtime as nn
import ulab.numpy as np
import time
import utime
import image
import random
import gc
import sys
import aidemo
# Custom face detection class, inherits from AIBase
class FaceDetectionApp(AIBase):
def __init__(self, kmodel_path, model_input_size, anchors, confidence_threshold=0.5, nms_threshold=0.2, rgb888p_size=[224,224], display_size=[1920,1080], debug_mode=0):
super().__init__(kmodel_path, model_input_size, rgb888p_size, debug_mode) # Call base class constructor
self.kmodel_path = kmodel_path # Model file path
self.model_input_size = model_input_size # Model input resolution
self.confidence_threshold = confidence_threshold # Confidence threshold
self.nms_threshold = nms_threshold # NMS (Non-Maximum Suppression) threshold
self.anchors = anchors # Anchor data for object detection
self.rgb888p_size = [ALIGN_UP(rgb888p_size[0], 16), rgb888p_size[1]] # Image resolution from sensor to AI, width aligned to 16
self.display_size = [ALIGN_UP(display_size[0], 16), display_size[1]] # Display resolution, width aligned to 16
self.debug_mode = debug_mode # Whether to enable debug mode
self.ai2d = Ai2d(debug_mode) # Instantiate Ai2d for model preprocessing
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT, nn.ai2d_format.NCHW_FMT, np.uint8, np.uint8) # Set Ai2d input/output format and type
# Configure preprocessing (pad and resize). Ai2d supports crop/shift/pad/resize/affine. See /sdcard/app/libs/AI2D.py
def config_preprocess(self, input_image_size=None):
with ScopedTiming("set preprocess config", self.debug_mode > 0): # Timer, enabled when debug_mode > 0
ai2d_input_size = input_image_size if input_image_size else self.rgb888p_size # Default to sensor-to-AI size; override with input_image_size
top, bottom, left, right = self.get_padding_param() # Get padding parameters
self.ai2d.pad([0, 0, 0, 0, top, bottom, left, right], 0, [104, 117, 123]) # Pad edges
self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel) # Resize image
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]]) # Build preprocessing pipeline
# Custom postprocessing; results is model output array list, uses aidemo face_det_post_process
def postprocess(self, results):
with ScopedTiming("postprocess", self.debug_mode > 0):
post_ret = aidemo.face_det_post_process(self.confidence_threshold, self.nms_threshold, self.model_input_size[1], self.anchors, self.rgb888p_size, results)
if len(post_ret) == 0:
return post_ret
else:
return post_ret[0]
# Draw detection results on screen
def draw_result(self, pl, dets):
with ScopedTiming("display_draw", self.debug_mode > 0):
if dets:
pl.osd_img.clear() # Clear OSD image
for det in dets:
# Convert detection box coordinates to display resolution
x, y, w, h = map(lambda x: int(round(x, 0)), det[:4])
x = x * self.display_size[0] // self.rgb888p_size[0]
y = y * self.display_size[1] // self.rgb888p_size[1]
w = w * self.display_size[0] // self.rgb888p_size[0]
h = h * self.display_size[1] // self.rgb888p_size[1]
pl.osd_img.draw_rectangle(x, y, w, h, color=(255, 255, 0, 255), thickness=2) # Draw rectangle
else:
pl.osd_img.clear()
# Get padding parameters
def get_padding_param(self):
dst_w = self.model_input_size[0] # Model input width
dst_h = self.model_input_size[1] # Model input height
ratio_w = dst_w / self.rgb888p_size[0] # Width scale ratio
ratio_h = dst_h / self.rgb888p_size[1] # Height scale ratio
ratio = min(ratio_w, ratio_h) # Use smaller scale ratio
new_w = int(ratio * self.rgb888p_size[0]) # New width
new_h = int(ratio * self.rgb888p_size[1]) # New height
dw = (dst_w - new_w) / 2 # Width difference
dh = (dst_h - new_h) / 2 # Height difference
top = int(round(0))
bottom = int(round(dh * 2 + 0.1))
left = int(round(0))
right = int(round(dw * 2 - 0.1))
return top, bottom, left, right
if __name__ == "__main__":
# Display mode, default "hdmi", can also use "lcd"
display_mode="hdmi"
if display_mode=="hdmi":
display_size=[1920,1080]
else:
display_size=[800,480]
# Set model path and other parameters
kmodel_path = "/sdcard/app/tests/kmodel/face_detection_320.kmodel"
# Other parameters
confidence_threshold = 0.5
nms_threshold = 0.2
anchor_len = 4200
det_dim = 4
anchors_path = "/sdcard/app/tests/utils/prior_data_320.bin"
anchors = np.fromfile(anchors_path, dtype=np.float)
anchors = anchors.reshape((anchor_len, det_dim))
rgb888p_size = [1920, 1080]
# Initialize PipeLine for image processing pipeline
pl = PipeLine(rgb888p_size=rgb888p_size, display_size=display_size, display_mode=display_mode)
pl.create() # Create PipeLine instance
# Initialize custom face detection instance
face_det = FaceDetectionApp(kmodel_path, model_input_size=[320, 320], anchors=anchors, confidence_threshold=confidence_threshold, nms_threshold=nms_threshold, rgb888p_size=rgb888p_size, display_size=display_size, debug_mode=0)
face_det.config_preprocess() # Configure preprocessing
try:
while True:
os.exitpoint() # Check for exit signal
with ScopedTiming("total",1):
img = pl.get_frame() # Get current frame
res = face_det.run(img) # Run inference on current frame
face_det.draw_result(pl, res) # Draw results
pl.show_image() # Display results
gc.collect() # Garbage collection
except Exception as e:
sys.print_exception(e) # Print exception
finally:
face_det.deinit() # Deinitialize
pl.destroy() # Destroy PipeLine instanceStep 2: Click Run.
Step 3: Point the K230 camera at a face; the K230 will detect it.