具身智能工业视觉分析与物联监护应用演练
具身智能工业视觉分析与物联监护应用演练
1 工效组合展示

本次实训主要完成工业视觉识别+物联网设备接入+云端项目部署整套流程。
2 具身智能工业视觉获取与分析应用
2.1 工具软件安装
2.1.1 实验目的
在开发机与昇腾设备上安装并验证工业视觉开发所需的工具链;
确保 npu-smi、CANN、MindStudio 可正常工作。

2.2 工业视觉环境构建与应用
2.2.1 实验目的
完成工业视频流获取;
准备并转换(ATC)一个适用于昇腾的视觉推理模型;
跑通最小推理样例,验证环境可用。
2.2.2 实验内容展示

2.3 昇腾工业视觉终端应用展现
2.3.1 实验目的
将视觉推理能力部署到昇腾边缘终端,实现"实时采集—推理—展现"闭环;
完成一次可录屏/截图演示的终端应用展示。
2.3.2 实验内容展示






3 具身智能工业视觉识别快速编码实现
3.1 IMA-DS借力
3.1.1 实验目的
学会使用 IMA-DS(智能编码助手 / 数据服务)根据需求描述生成工业视觉识别代码骨架;在此基础上进行人工校正与补全。
3.1.2 实验内容展示

3.2 运行环境构造
3.2.1 实验步骤


3.3 编码实现
3.3.1 代码片段示例
#!/usr/bin/env python3# -*- coding: utf-8 -*-"""海康工业相机(USB)+ PaddleOCR 文字识别(含中文)运行环境:Windows 10/11 x64,Python 3.8~3.12,CPU 推理"""
import osimport sysimport timeimport argparseimport ctypes
import numpy as npimport cv2
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
try:
sys.stdout.reconfigure(encoding="utf-8")
except Exception:
passif sys.stderr and hasattr(sys.stderr, "reconfigure"):
try:
sys.stderr.reconfigure(encoding="utf-8")
except Exception:
pass
HIK_AVAILABLE = False
HIK_IMPORT_ERROR = None
_MVS_IMPORT_DIRS = [
os.path.join(os.path.dirname(os.path.abspath(__file__)), "MvImport"),
r"C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport",
r"C:\Program Files\MVS\Development\Samples\Python\MvImport",
r"D:\MVS\Development\Samples\Python\MvImport",
]
_MVS_DLL_DIRS = [
r"C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64",
r"C:\Program Files\Common Files\MVS\Runtime\Win64_x64",
]
if sys.platform == "win32":
for _d in _MVS_DLL_DIRS:
if os.path.isdir(_d):
try:
os.add_dll_directory(_d)
except Exception:
pass
for _d in _MVS_IMPORT_DIRS:
if os.path.isdir(_d) and _d not in sys.path:
sys.path.insert(0, _d)
try:
from MvCameraControl_class import * # noqa
HIK_AVAILABLE = Trueexcept Exception as _e:
HIK_IMPORT_ERROR = str(_e)
class HikCamera: """枚举 -> 建句柄 -> 打开 -> 取流 -> 取图 -> 转 BGR"""
def __init__(self, device_index=0, device_type="usb"):
if not HIK_AVAILABLE:
raise RuntimeError(
"海康 MVS SDK 未加载成功。\n"
f"错误信息:{HIK_IMPORT_ERROR}\n"
"请确认已安装海康 MVS,并把 MvImport 文件夹放到本脚本同级目录。"
)
self.device_index = device_index
self.cam = None
self.is_open = False
self.is_grabbing = False
_type_map = {
"usb": MV_USB_DEVICE,
"gige": MV_GIGE_DEVICE,
"all": MV_GIGE_DEVICE | MV_USB_DEVICE,
}
self._type_flag = _type_map.get(device_type, MV_USB_DEVICE)
def enumerate_devices(self):
device_list = MV_CC_DEVICE_INFO_LIST()
ctypes.memset(ctypes.byref(device_list), 0, ctypes.sizeof(device_list))
ret = MvCamera.MV_CC_EnumDevices(self._type_flag, device_list)
if ret != 0:
raise RuntimeError(f"枚举设备失败,错误码 0x{ret & 0xFFFFFFFF:08X}")
return device_list
def open(self):
device_list = self.enumerate_devices()
n = device_list.nDeviceNum
if n == 0:
raise RuntimeError("未检测到海康工业相机。请检查 USB 连接、驱动,并关闭 MVS Studio。")
if self.device_index >= n:
raise RuntimeError(f"相机索引 {self.device_index} 超出范围(共检测到 {n} 台)。")
st_device_info = ctypes.cast(
device_list.pDeviceInfo[self.device_index],
ctypes.POINTER(MV_CC_DEVICE_INFO),
).contents
self.cam = MvCamera()
ret = self.cam.MV_CC_CreateHandle(st_device_info)
if ret != 0:
raise RuntimeError(f"创建相机句柄失败,错误码 0x{ret & 0xFFFFFFFF:08X}")
ret = self.cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
self.cam.MV_CC_DestroyHandle()
self.cam = None
raise RuntimeError(
f"打开相机失败,错误码 0x{ret & 0xFFFFFFFF:08X}。"
"常见原因:相机被其他程序(如 MVS Studio)占用。"
)
self.is_open = True
try:
self.cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
except Exception:
pass
return self
def start(self):
if not self.is_open:
raise RuntimeError("相机尚未打开。")
ret = self.cam.MV_CC_StartGrabbing()
if ret != 0:
raise RuntimeError(f"开始取流失败,错误码 0x{ret & 0xFFFFFFFF:08X}")
self.is_grabbing = True
def get_frame(self, timeout_ms=1000): """返回 BGR 图像;超时返回 None。"""
if not self.is_grabbing:
return None
st_frame = MV_FRAME_OUT()
ctypes.memset(ctypes.byref(st_frame), 0, ctypes.sizeof(st_frame))
ret = self.cam.MV_CC_GetImageBuffer(st_frame, timeout_ms)
if ret != 0:
return None
try:
st_info = st_frame.stFrameInfo
n_len = st_info.nFrameLen
if n_len <= 0 or not st_frame.pBufAddr:
return None
buf = (ctypes.c_ubyte * n_len)()
ctypes.memmove(buf, st_frame.pBufAddr, n_len)
return self._to_bgr(
buf,
n_len,
st_info.nWidth,
st_info.nHeight,
st_info.enPixelType,
)
finally:
self.cam.MV_CC_FreeImageBuffer(st_frame)
def _to_bgr(self, buf, n_len, width, height, pixel_type):
if pixel_type == PixelType_Gvsp_Mono8:
gray = np.frombuffer(buf, dtype=np.uint8, count=width * height).reshape(height, width)
return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
if pixel_type == PixelType_Gvsp_BGR8_Packed:
arr = np.frombuffer(buf, dtype=np.uint8, count=width * height * 3)
return arr.reshape(height, width, 3).copy()
if pixel_type == PixelType_Gvsp_RGB8_Packed:
arr = np.frombuffer(buf, dtype=np.uint8, count=width * height * 3).reshape(height, width, 3)
return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)
return self._convert_to_bgr(buf, n_len, width, height, pixel_type)
def _convert_to_bgr(self, src_buf, src_len, width, height, src_pixel_type):
dst_len = width * height * 3
dst_buf = (ctypes.c_ubyte * dst_len)()
st_param = MV_CC_PIXEL_CONVERT_PARAM()
ctypes.memset(ctypes.byref(st_param), 0, ctypes.sizeof(st_param))
st_param.nWidth = width
st_param.nHeight = height
st_param.pSrcData = ctypes.cast(src_buf, ctypes.POINTER(ctypes.c_ubyte))
st_param.nSrcDataLen = src_len
st_param.enSrcPixelType = src_pixel_type
st_param.enDstPixelType = PixelType_Gvsp_RGB8_Packed
st_param.pDstBuffer = ctypes.cast(dst_buf, ctypes.POINTER(ctypes.c_ubyte))
st_param.nDstBufferSize = dst_len
ret = self.cam.MV_CC_ConvertPixelType(st_param)
if ret != 0:
raise RuntimeError(f"像素格式转换失败,错误码 0x{ret & 0xFFFFFFFF:08X}")
arr = np.frombuffer(dst_buf, dtype=np.uint8, count=dst_len).reshape(height, width, 3)
return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)
def close(self):
if self.cam is None:
return
for fn, guard in (
(self.cam.MV_CC_StopGrabbing, self.is_grabbing),
(self.cam.MV_CC_CloseDevice, self.is_open),
(self.cam.MV_CC_DestroyHandle, True),
):
if guard:
try:
fn()
except Exception:
pass
self.is_grabbing = False
self.is_open = False
self.cam = None
class OCREngine: """PaddleOCR 中文识别,强制 CPU 推理。"""
def __init__(self, lang="ch"):
self.ocr = None
self._init(lang)
def _init(self, lang):
try:
import paddle
try:
paddle.set_device("cpu")
except Exception:
pass
except Exception:
pass
from paddleocr import PaddleOCR
last_err = None
try:
self.ocr = PaddleOCR(lang=lang, device="cpu", enable_mkldnn=False)
return
except Exception as e:
last_err = e
attempts = [
dict(lang=lang, use_angle_cls=True, use_gpu=False, show_log=False),
dict(lang=lang, use_angle_cls=True, use_gpu=False),
dict(lang=lang, use_angle_cls=True),
dict(lang=lang),
]
for kw in attempts:
try:
self.ocr = PaddleOCR(**kw)
return
except Exception as e:
last_err = e
raise RuntimeError(f"PaddleOCR 初始化失败:{last_err}")
def predict(self, img_bgr):
if hasattr(self.ocr, "predict"):
return self.ocr.predict(img_bgr)
return self.ocr.ocr(img_bgr, cls=True)
def parse_ocr_results(raw):
items = []
if not raw:
return items
if isinstance(raw[0], dict):
for r in raw:
texts = r.get("rec_texts") or []
scores = r.get("rec_scores") or []
polys = r.get("rec_polys") or []
for i, text in enumerate(texts):
text = str(text).strip()
if not text:
continue
score = float(scores[i]) if i < len(scores) else 0.0
poly = polys[i] if i < len(polys) else None
items.append((poly, text, score))
return items
for line in raw:
if not line:
continue
for box, info in line:
text = str(info[0]).strip()
score = float(info[1])
if not text:
continue
items.append((box, text, score))
return items
def find_chinese_font():
candidates = [
r"C:\Windows\Fonts\msyh.ttc",
r"C:\Windows\Fonts\msyhbd.ttc",
r"C:\Windows\Fonts\simhei.ttf",
r"C:\Windows\Fonts\simsun.ttc",
]
for p in candidates:
if os.path.exists(p):
return p
return None
def draw_results(img_bgr, items, font_path=None):
from PIL import Image, ImageDraw, ImageFont
rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
pil = Image.fromarray(rgb)
draw = ImageDraw.Draw(pil)
fp = font_path or find_chinese_font()
if fp and os.path.exists(fp):
font = ImageFont.truetype(fp, 26)
else:
font = ImageFont.load_default()
for poly, text, score in items:
if poly is None:
continue
pts = [(int(float(p[0])), int(float(p[1]))) for p in poly]
if len(pts) >= 3:
draw.polygon(pts, outline=(0, 255, 0))
x0, y0 = pts[0]
label = f"{text} {score:.2f}"
draw.rectangle([x0, y0 - 28, x0 + len(label) * 26, y0], fill=(0, 0, 0))
draw.text((x0 + 2, y0 - 26), label, font=font, fill=(0, 255, 0))
return cv2.cvtColor(np.array(pil), cv2.COLOR_RGB2BGR)
def save_result(annotated, items, directory, idx):
os.makedirs(directory, exist_ok=True)
ts = time.strftime("%Y%m%d_%H%M%S")
img_path = os.path.join(directory, f"ocr_{ts}_{idx}.jpg")
txt_path = os.path.join(directory, f"ocr_{ts}_{idx}.txt")
cv2.imwrite(img_path, annotated)
lines = [f"{score:.4f}\t{text}" for _, text, score in items]
with open(txt_path, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
return img_path, txt_path
def main():
parser = argparse.ArgumentParser(
description="海康工业相机(USB)+ PaddleOCR 中文文字识别(CPU)"
)
parser.add_argument("--index", type=int, default=0, help="相机索引(默认 0)")
parser.add_argument("--type", default="usb", choices=["usb", "gige", "all"],
help="相机接口类型(默认 usb)")
parser.add_argument("--save-dir", default="", help="按 s 键保存结果的目录")
parser.add_argument("--font", default="", help="中文字体路径")
parser.add_argument("--no-show", action="store_true", help="不显示窗口")
args = parser.parse_args()
if not HIK_AVAILABLE:
print("=" * 70)
print("[错误] 海康 MVS SDK 加载失败:")
print(f" {HIK_IMPORT_ERROR}")
print("=" * 70)
print("请先安装海康 MVS,并把 MvImport 文件夹放到本脚本同级目录。")
sys.exit(1)
print("[1/3] 初始化 OCR(首次运行会自动下载模型,请联网)...")
ocr_engine = OCREngine(lang="ch")
print("[1/3] OCR 就绪(CPU 模式)。")
print("[2/3] 打开海康相机 ...")
cam = HikCamera(device_index=args.index, device_type=args.type)
cam.open()
cam.start()
print("[2/3] 相机已启动,开始实时识别。")
print("[3/3] 运行中:按 q / ESC 退出,按 s 保存当前帧。")
frame_idx = 0
save_dir = args.save_dir or "."
try:
while True:
frame = cam.get_frame(timeout_ms=1000)
if frame is None:
print("取帧超时(无新图像)...")
continue
raw = ocr_engine.predict(frame)
items = parse_ocr_results(raw)
if items:
print("-" * 60)
for _, text, score in items:
print(f" [{score:.3f}] {text}")
annotated = draw_results(frame, items, args.font) if items else frame
key = -1
if not args.no_show:
cv2.imshow("HikCamera OCR", annotated)
key = cv2.waitKey(1) & 0xFF
if key in (ord("q"), 27):
break
if key == ord("s"):
img_path, txt_path = save_result(annotated, items, save_dir, frame_idx)
print(f" 已保存图片: {img_path}")
print(f" 已保存文本: {txt_path}")
frame_idx += 1
except KeyboardInterrupt:
print("\n用户中断。")
finally:
cam.close()
cv2.destroyAllWindows()
print("已释放相机,退出。")
基于模板编写工业视觉识别代码,实现图像采集、预处理、目标识别、结果输出功能。根据实训场景微调代码参数,保证识别效果适配工业场景。
3.4 运行测试

4 IoTDA中转空间构建
4.0 IoTDA构造
4.0.1 实验目的
本实验指导学员如何使用 http请求,完成华为云 IoT平台的应用侧 API调用。通过本实验,您将能够:
完成认证鉴权、查询设备列表、创建设备的 API调用
完成设备影子、查询产品的 API调用,实现鸿蒙应用于 IoT平台的数据同步
完成下发命令的 API调用,实现鸿蒙应用通过 IoT平台向设备下发命令
4.0.2 实验内容展示


4.1 产品及其模型构建
4.1.1 温湿度计

温湿度计产品信息如下:
产品信息:
产品名称:温湿度计
协议类型:MQTT
数据格式:JSON
所属行业:智能家居
所属子行业:智能家居
服务列表:
服务 ID:T&H
属性名称:temperature
数据类型:decimal
访问权限:可读可写
取值范围:-100~100
属性名称:humidity
数据类型:decimal
访问权限:可读可写
取值范围:0~100
点击“产品 》创建产品”。
产品信息:
–产品名称:智能吸顶灯
–数据格式:JSON
–所属行业:智能家居
–所属子行业:智能家居
服务ID:Light+
属性名称:光照强度+
数据类型:decimal+
访问权限:可读可写+
取值范围:0~5000
属性名称:功率
数据类型:decimal-
访问权限:可读可写+
取值范围:0~10000
命令名称:Light+
下发参数名称:turn
数据类型:string+
长度:10
下发参数名称:power+
数据类型:decimal+
取值范围:0~10000
服务ID:Color+
属性名称:当前颜色
数据类型:strings-
长度:10
命令名称:设置颜色
下发参数名称:color+
数据类型:string-
长度:10
4.1.2 吸顶灯


产品信息:
–产品名称:智能吸顶灯
–数据格式:JSON
–所属行业:智能家居
–所属子行业:智能家居
服务ID:Light+
属性名称:光照强度+
数据类型:decimal+
访问权限:可读可写+
取值范围:0~5000
属性名称:功率
数据类型:decimal-
访问权限:可读可写+
取值范围:0~10000
命令名称:Light+
下发参数名称:turn
数据类型:string+
长度:10
下发参数名称:power+
数据类型:decimal+
取值范围:0~10000
服务ID:Color+
属性名称:当前颜色
数据类型:strings-
长度:10
命令名称:设置颜色
下发参数名称:color+
数据类型:string-
长度:10
4.2 设备实例化应用
4.2.1 温湿度计设备注册及模拟测试
在对应产品下注册设备实例,获取设备密钥并完成设备绑定。启动模拟设备,测试数据上云,查看平台能否正常接收温湿度数据、查询设备状态。

4.2.2 吸顶灯设备注册及模拟测试
注册吸顶灯设备并完成上云配置。通过云端平台下发控制指令,测试远程开灯、关灯、调光功能,验证设备可正常响应云端命令。

5 CodeArts智慧路灯快速构建与部署
5.1 应用项目创建
配置系统变量。需配置3个变量:JAVA_HOME、Path、CLASSPATH(不区分大小写)。若变量名已经存在,则单击“编辑”;若变量名不存在,则单击“新建”。一般Path变量存在,JAVA_HOME变量和CLASSPATH变量需要新增。




进入CodeArts云端开发平台,新建智慧路灯项目,规划项目目录与功能模块,初始化项目运行环境。



5.2 代码托管操作

5.3 构建任务设立





5.4 项目构建实现


5.5 项目部署运行
将构建好的智慧路灯项目部署到云端服务器,启动项目并测试功能,验证项目可以正常联网、接收设备数据、实现路灯智能管控,完成整体实训部署。


DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)