1 工效组合展示

围绕“视觉感知—智能识别—物联接入—云端部署”全链路展开,涵盖昇腾边缘计算、工业视觉、IoTDA设备接入与CodeArts应用部署。各模块分工协作、并行推进,形成完整闭环。

图1-1 实训各模块综合成果展示(OCR识别、目标检测、IoTDA在线调试等)

2 具身智能工业视觉获取与分析应用

完成昇腾开发板与海康工业相机的环境搭建,实现视觉数据采集与终端识别。主要包括工具安装、视觉环境构建与昇腾终端应用展现三个环节。

2.1 工具软件安装

安装昇腾制卡工具、MobaXterm操控终端与海康MVS客户端等工具软件。通过SSH远程登录Atlas 200I DK A2开发板,配置CANN环境变量与启动脚本,启动JupyterLab服务。

图2-1 实训所需工具软件(Ascend制卡工具、MobaXterm操控终端、海康MVS客户端)

图2-2 海康MVS客户端安装界面与安装选项

图2-3 SSH远程登录Atlas 200I DK A2开发板

图2-4 配置start_notebook.sh启动脚本(加载CANN环境变量)

图2-5 执行启动脚本运行JupyterLab服务

图2-6 JupyterLab启动成功并生成访问链接

2.2 工业视觉环境构建与应用

相机经USB3.0线缆与工控机连接后,先确认系统已正确识别USB3 Vision驱动;再在MVS客户端刷新设备列表,枚举到相机即可连接取景。同时完成光源与昇腾开发板的硬件连线,构成完整的工业视觉成像环境。

图2-7 工业相机USB驱动安装正常(设备管理器)

图2-8 MVS客户端识别工业相机(USB设备列表)

图2-9 昇腾开发板硬件连线示意图

2.3 昇腾工业视觉终端应用展现

通过浏览器访问开发板上的JupyterLab,加载内置视觉样例。选取轻量级的YOLOv5s模型运行目标检测,验证昇腾边缘终端的实时推理能力。

图2-10 JupyterLab样例主页(内置YOLOv5等视觉样例)

图2-11 01-yolov5样例目录(含om模型与测试资源)

图2-12 Atlas 200I DK A2终端YOLOv5目标检测(JupyterLab)

3 具身智能工业视觉识别快速编码实现

基于PaddleOCR开源方案,快速实现工业视觉字符识别功能。通过方案选型、环境构造、编码实现与运行测试四个步骤完成。

3.1 IMA-DS借力

借助PaddleOCR开源方案与现成交付工程,确定识别实现方案。避免从零搭建,显著缩短开发周期。

图3-1 OCR识别技术方案选型与交付文件清单(PaddleOCR开源方案借力)

3.2 运行环境构造

配置Python虚拟环境并安装PaddleOCR、OpenCV等依赖库。完成运行环境验证,确保代码与环境匹配。

图3-2 Python虚拟环境与PaddleOCR环境验证(Windows/PowerShell)

3.3 编码实现

# -*- coding: utf-8 -*-
"""
Camera OCR for Chinese text (PaddleOCR 2.x, Chinese labels on image).
Windows + venv (no conda) + local USB/IP camera.
Keys: SPACE=OCR once | c=auto | z=zoom in | x=zoom out | s=save | q=quit.
"""

import os
os.environ["OMP_NUM_THREADS"] = "4"

import time
import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont

CAMERA_SOURCE = 0
OCR_INTERVAL = 2.0
OUTPUT_DIR = "ocr_output"
WINDOW_NAME = "Camera OCR"

os.makedirs(OUTPUT_DIR, exist_ok=True)

ZOOM = 1.0


def get_chinese_font(size=20):
    """Find a Chinese font on Windows."""
    candidates = [
        "C:/Windows/Fonts/msyh.ttc",
        "C:/Windows/Fonts/msyhbd.ttc",
        "C:/Windows/Fonts/simhei.ttf",
        "C:/Windows/Fonts/simsun.ttc",
    ]
    for path in candidates:
        if os.path.exists(path):
            return ImageFont.truetype(path, size)
    return ImageFont.load_default()


CH_FONT = get_chinese_font(20)


def put_chinese_text(img, text, pos, color=(0, 255, 0), font=CH_FONT):
    """Draw Chinese text on OpenCV image using Pillow."""
    img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img_pil)
    draw.text(pos, text, font=font, fill=color)
    return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)


def open_camera(source):
    if isinstance(source, str) and source.lower().startswith(("rtsp", "http")):
        os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;udp"
    cap = cv2.VideoCapture(source)
    if not cap.isOpened():
        raise RuntimeError(f"Cannot open camera: {source}")
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
    return cap


def preprocess(frame):
    h, w = frame.shape[:2]
    scale = max(1.0, 720.0 / min(h, w))
    if scale > 1.0:
        frame = cv2.resize(frame, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC)
    kernel = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])
    frame = cv2.filter2D(frame, -1, kernel)
    return frame


def zoom_frame(frame, factor):
    if factor <= 1.0:
        return frame
    h, w = frame.shape[:2]
    nh, nw = int(h / factor), int(w / factor)
    y1 = (h - nh) // 2
    x1 = (w - nw) // 2
    return frame[y1:y1 + nh, x1:x1 + nw]


def build_ocr():
    from paddleocr import PaddleOCR
    ocr = PaddleOCR(use_angle_cls=True, lang="ch", show_log=False)
    return ocr


def draw_box(annotated, box, text, score):
    if not box:
        return
    pts = np.array([[int(p[0]), int(p[1])] for p in box], np.int32)
    cv2.polylines(annotated, [pts], isClosed=True, color=(0, 255, 0), thickness=2)
    if pts.size > 0:
        x, y = pts[0]
        label = f"{text} {score:.2f}"
        annotated[:] = put_chinese_text(annotated, label, (x, max(y - 8, 14)), color=(0, 255, 0))


def ocr_image(ocr, frame):
    texts = []
    annotated = frame.copy()
    try:
        result = ocr.ocr(frame, cls=True)
    except Exception as e:
        print("OCR error:", e)
        return annotated, texts
    if not result or not result[0]:
        return annotated, texts
    for line in result[0]:
        box, (text, score) = line[0], line[1]
        texts.append((text, score))
        draw_box(annotated, box, text, score)
    return annotated, texts


def main():
    global ZOOM
    print("Initializing OCR engine. First run downloads models, please wait...")
    ocr = build_ocr()
    print("OCR engine ready.")

    cap = open_camera(CAMERA_SOURCE)
    print("Camera opened.")
    print("SPACE=OCR once | c=auto | z=zoom in | x=zoom out | s=save | q=quit")

    auto_mode = False
    last_ocr_time = 0.0
    display = None

    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("Frame read failed.")
                break

            frame_proc = zoom_frame(frame, ZOOM)
            frame_ocr = preprocess(frame_proc)

            if auto_mode and (time.time() - last_ocr_time) >= OCR_INTERVAL:
                display, texts = ocr_image(ocr, frame_ocr)
                last_ocr_time = time.time()
                if texts:
                    print("OCR:", " | ".join(t for t, _ in texts))
            else:
                if display is None:
                    display = frame_proc
                display = display.copy()
                cv2.putText(display, f"AUTO: {'ON' if auto_mode else 'OFF'} ZOOM: {ZOOM:.1f}", (10, 20),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2, cv2.LINE_AA)
            cv2.imshow(WINDOW_NAME, display)

            key = cv2.waitKey(1) & 0xFF
            if key == ord("q"):
                break
            elif key == ord(" "):
                annotated, texts = ocr_image(ocr, frame_ocr)
                display = annotated
                if texts:
                    print("-" * 40)
                    for t, s in texts:
                        print(f"{t}  ({s:.2f})")
                    print("-" * 40)
                else:
                    print("No text found. Try: get closer, more light, press z to zoom.")
            elif key == ord("c"):
                auto_mode = not auto_mode
                display = None
                print(f"Auto mode -> {'ON' if auto_mode else 'OFF'}")
            elif key == ord("z"):
                ZOOM = min(ZOOM + 0.5, 4.0)
                display = None
                print(f"Zoom -> {ZOOM}")
            elif key == ord("x"):
                ZOOM = max(ZOOM - 0.5, 1.0)
                display = None
                print(f"Zoom -> {ZOOM}")
            elif key == ord("s"):
                path = os.path.join(OUTPUT_DIR,
                                    f"shot_{time.strftime('%Y%m%d_%H%M%S')}.jpg")
                cv2.imwrite(path, frame)
                print(f"Screenshot saved: {path}")
    finally:
        cap.release()
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

3.4 运行测试

使用海康工业相机进行实测,正确识别出目标文字。验证了快速编码实现路线的可行性。

图3-8 海康工业相机OCR运行测试(识别“纯悦 550ml”)

4 IoTDA中转空间构建

构建设备接入中转空间,完成产品模型定义与设备实例化。实现温湿度计与吸顶灯两类设备的接入与双向通信。

4.0 IoTDA构造

开通设备接入IoTDA服务并创建myIoTDA实例。作为设备与业务应用之间的中转空间,支撑海量设备接入。

图4-1 IoTDA实例(myIoTDA)创建完成并运行中

4.1 产品及其模型构建

完成云账号凭证准备与产品创建。分别定义温湿度计与吸顶灯的产品模型。

图4-2 华为云账号API凭证查看(IAM用户与项目列表)

图4-3 IoTDA实例(myIoTDA)与产品创建

4.1.1 温湿度计

定义T&H服务,包含温度、湿度两个属性。用于温湿度数据的上报。

图4-4 添加服务与新增属性(T&H:temperature/Humidity)

4.1.2 吸顶灯

定义Light服务与Color服务,包含属性与命令。支持状态上报与开关、调光等控制命令下发。

图4-5 吸顶灯产品模型定义(Light服务+Color服务)

4.2 设备实例化应用

在对应产品下注册具体设备,完成设备实例化。生成设备身份三元组,用于MQTT接入鉴权。

4.2.1 温湿度计设备注册及模拟测试

通过MQTT连接平台并上报温湿度数据。平台侧实时显示上报结果,验证数据上报链路。

图4-6 温湿度计设备MQTT连接配置(MQTT.fx)

图4-7 温湿度计属性上报数据(temperature/Humidity)

4.2.2 吸顶灯设备注册及模拟测试

完成设备连接、属性上报与命令下发调试。验证了双向通信与远程控制能力。

图4-8 吸顶灯设备MQTT连接配置(MQTT.fx)

图4-9 吸顶灯属性上报消息跟踪(properties/report)

图4-10 吸顶灯设备详情(luminance/power/color)

图4-11 吸顶灯命令下发在线调试(Light/Color)

5 CodeArts智慧路灯快速构建与部署

完成智慧路灯应用的构建、部署与运行验证。覆盖项目管理、代码托管、编译构建与部署全流程。

5.1 应用项目创建

在CodeArts项目管理中创建Scrum项目。作为后续开发与部署的统一载体。

图5-1 创建Scrum项目(mySmartLightCZD)

5.2 代码托管操作

创建代码仓库并托管智慧路灯源码。实现代码的云端版本管理。

图5-2 按模板新建代码仓库(选择IoT_Streetlight_Demo模板)

图5-3 代码仓库Master创建成功

5.3 构建任务设立

新建编译构建任务并配置Maven构建。设置软件包归档路径,为自动化构建做准备。

图5-4 新建任务(代码源选择Repo)

图5-5 新建编译构建任务(基本信息)

图5-6 选择Maven构建模板

图5-7 Maven构建步骤配置并保存执行

5.4 项目构建实现

执行构建任务并下载软件包。验证代码可正常编译并产出可部署制品。

图5-8 构建执行成功并下载软件包(huawei-0.0.1-SNAPSHOT.jar)

5.5 项目部署运行

配置Java环境并启动智慧路灯应用。实现从构建到部署运行的完整交付闭环。

图5-9 配置Java环境变量(Path添加java\bin)

图5-10 验证Java运行环境(java -version)

图5-11 运行智慧路灯应用(java -jar启动Spring Boot)

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐