视觉 SDK
调摄像头、拍照、从文件选图,压缩后交给视觉模型做结构化判断(质检)或物体检测(类别 + 位置框),再把结果画回图上;看公司 NVR / 网络摄像机的实时画面与高清截图(见下文「网络摄像机 / NVR」)。只用浏览器原生能力(getUserMedia、canvas、createImageBitmap、WebCodecs),不引第三方库。页面必须是 HTTPS(或 localhost)。
import { vision } from "/developer/sdk/v1/aidc.js";
清单里声明:"sdk": ["vision", "model"]、"permissions": { "camera": true }、"models": ["gpt-6-luna"]。
摄像头
const camera = await vision.openCamera({ video: document.querySelector("video"), facingMode: "environment" });
const photo = await camera.capture({ maxSize: 1280 }); // 长边 1280 的 JPEG
await camera.switchTo({ facingMode: "user" }); // 切前置
camera.stop(); // 幂等
| 方法 | 说明 |
|---|---|
openCamera(options) |
video(挂到哪个 <video>)、facingMode(environment 后置 / user 前置)、deviceId、width / height |
camera.capture(options) |
拍一张 → Photo;maxSize(长边像素,缺省 1280)、type、quality |
camera.switchTo(target) |
换摄像头 |
camera.devices() |
列出可用摄像头 |
camera.stop() |
关闭(释放设备) |
Photo = { blob, dataUrl, width, height, type, takenAt }。
没有摄像头时
const photo = await vision.pickImage(); // 手机上优先调起相机;电脑上选文件;取消返回 null
const photo2 = await vision.fromFile(file); // 已有的 File / Blob
看图判断
const result = await vision.inspect(photo, {
task: "检查成衣表面有没有污渍、破洞、跳线",
criteria: "任何肉眼可见的污渍或破损都判不合格", // 可选
model: "gpt-6-luna", // 缺省
reasoning: "low", // 缺省
});
// → { verdict: "pass" | "fail" | "uncertain", summary, findings: [...], model }
每条 finding:label(油污、划痕…)、category、severity(low / medium / high)、confidence(0–1)、box(归一化坐标 [x0, y0, x1, y1],定位不准时为 null)、note。图片模糊或看不清时模型给 uncertain,不会硬判合格。
可以一次给多张图(同一件物品的不同角度):vision.inspect([photoA, photoB], { task })。
物体检测
输入一张图,输出画面里每个物体的类别、把握和位置框。缺省模型 gpt-6-luna;用量记在当前应用 / 开发者 Key 名下(清单 models 要声明它)。
const result = await vision.detect(photo, {
labels: ["人", "叉车", "托盘"], // 可选:只找这些类别(≤ 40 个),label 原样用你写的;不给就找所有显著物体
prompt: "仓库出入口,安全帽算人的一部分", // 可选:场景与类别的补充说明
maxObjects: 30, // 可选:1–100,缺省 50,按把握从高到低
});
// → { objects: [{ label: "叉车", confidence: 0.92, box: [0.61, 0.38, 0.88, 0.79], note: "画面右侧,载着托盘" }, …], count, summary, model }
const canvas = await vision.annotate(photo, result.objects); // 画框
box 是归一化坐标 [x0, y0, x1, y1]:图片左上角 (0,0)、右下角 (1,1)——换算像素时乘图片宽高。平台会把坐标夹到 0–1、摆正左上 / 右下、丢掉面积几乎为零的框;给了 labels 时不在清单里的类别不返回。视觉大模型的框是近似定位(适合计数、找位置、配合人工复核),不是逐像素的分割。
同一个能力也是 HTTP API,任何语言都能调:POST /api/v1/models/vision/detect,body { "image": "data:image/jpeg;base64,…" | "https://…", "labels"?, "prompt"?, "maxObjects"?, "model"? },Authorization: Bearer <开发者 Key 或应用票据>。
画框标注
const canvas = await vision.annotate(photo, result.findings); // inspect 的 findings、detect 的 objects 都能传;返回画好框的 <canvas>
document.body.append(canvas);
上传给智能体
图片可以直接交给某个智能体(走 Agent API 的附件协议,24 小时内有效):
const agent = model.agent(agentKey);
const fileId = await agent.upload(photo.blob, "defect.jpg");
await agent.send("这是今天 3 号线的不合格品,请登记。", { files: [fileId] });
网络摄像机 / NVR
公司 NVR(大华、海康等)上的摄像头走 RTSP,浏览器直接连不了。平台在有人打开画面时去拉流(RTSP over TCP,Digest 认证),把码流原样(H.264 / H.265,不转码)转给浏览器,SDK 用 WebCodecs 硬解、画到 canvas。口令只在平台里(AES-256-GCM 加密存放、任何接口都不回显),应用与浏览器都拿不到。
1. 登记(本公司开发者,一次):
AIDC_CAMERA_PASSWORD='只读账号的口令' aidc vision camera add nvr \
--host 58.x.x.x --port 18554 --vendor dahua --username viewer \
--channels "1:大门,2:仓库" --title "总部 NVR"
aidc vision camera probe nvr --channels 1-16 # 连上、认证、读编码(不拉流),找出有哪些通道
口令只从环境变量 AIDC_CAMERA_PASSWORD 或 --password-stdin 读,绝不写在命令行参数里;重新登记时不给口令 = 保留原来的。也可以在应用里做一个只给开发者的「登记摄像头」表单(vision.saveCamera,见样板 camera-live)。--vendor dahua(缺省)的路径是 /cam/realmonitor?channel={channel}&subtype={stream},hikvision 是 /Streaming/Channels/{channel}0{stream},其他品牌 --vendor generic --path '/live/ch{channel}/{stream}'。主机必须是公网地址(路由器上给 NVR 做端口映射)。
2. 清单:"sdk": ["vision"]、"cameras": ["nvr"](应用只看得到这里登记的摄像头)。
3. 页面:
const cams = await vision.cameras(); // [{ name, title, channels: [{ id, title }], defaultStream, … }]
const view = vision.live(document.querySelector("canvas"), {
camera: "nvr", channel: 1, stream: "sub", // sub 子码流(缺省,远程流畅)/ main 主码流(要登记时开 allowMainLive)
onStatus: (status, { info, error }) => { /* connecting → live;reconnecting / paused / error */ },
});
view.switchTo({ channel: 2 }); // 换一路
const photo = await view.snapshot(); // 当前画面 → Photo,可直接 vision.detect(photo)
const hd = await vision.cameraSnapshot("nvr", { channel: 1 }); // 主码流高清截图(取下一个关键帧,不用开主码流实时)
view.stop();
- 只在有人看时拉流:页面隐藏 1 分钟自动断开(
paused),切回来续上;一条连接约 4 分 40 秒到点,SDK 提前开好下一条、等它出了关键帧再切,画面不断。挂着的时长计入应用的计算分钟(video)。不要用setInterval反复截图当实时——更贵也更卡。 - 同时观看上限:每个观看者单独从 NVR 拉一路流,同一台摄像头同时在拉的连接 ≤
maxViewers(缺省 4),满了报camera_busy(SDK 15 秒后重试)。 - 只给本公司的人看:应用票据的访客必须是本公司 developer / member;分享链接与公开链接的访客看不了监控画面。
- 口令错只试一次:摄像头拒绝口令后 10 分钟内不再尝试(NVR 会按失败次数锁账号),重新登记口令立即解除。
- 暂时连不上就一直重试:
camera_unreachable/camera_timeout/ 断流 / 满员时,页面开着就自动重连(间隔封顶 15 秒,onStatus的attempt是第几次),NVR 恢复后画面自己回来;口令错、没这一路、浏览器解不了才停下。平台连忙的 NVR 时会错开并发试几条连接(先不带凭证问一声,谁先回话用谁),最多只带凭证试一次。 - 浏览器:H.264 所有现代浏览器都能解;H.265 要较新的 Chrome / Edge / Safari 且电脑支持 HEVC 硬解(
vision.liveSupport()可先查)。解不了报codec_unsupported——最稳的办法是把 NVR 的子码流编码改成 H.264。
同样是 HTTP API(开发者 Key 或应用票据):GET /api/v1/developer/vision/{命名空间}/cameras、PUT …/cameras/{名字}(登记,支持 dry-run)、POST …/probe、GET …/live?channel=&stream=(流式,application/vnd.aidc.live)、GET …/keyframe?channel=&stream=(一帧原始码流,Annex B)。线格式与每个字段见 API 与 OpenAPI。
命令行
aidc vision inspect a.jpg b.jpg --task "布面有没有污渍" --json
aidc vision detect warehouse.jpg --labels 人,叉车,托盘 --json # 物体检测:类别 + 把握 + 归一化框
aidc vision camera list # 公司的网络摄像机
aidc vision camera snapshot nvr --channel 1 -o gate.jpg # 截一帧(缺省主码流高清;本机 ffmpeg 转 JPEG)
aidc vision detect gate.jpg --labels 人,车辆 --json # 智能体「看一眼现场」= 截图 + 物体检测
错误
本机摄像头:camera_denied(没给权限)、camera_not_found、camera_busy、camera_unsupported(非 HTTPS / 旧浏览器)、invalid_model_output;以及 API 的 forbidden(清单没声明模型)、quota_exhausted(应用当日额度用完)、rate_limited。
网络摄像机(API):camera_not_found(没登记这台)、camera_channel_not_found(没这一路)、camera_unreachable(连不上:地址、端口映射、出口防火墙)、camera_auth_failed(摄像头拒绝口令,冷却 10 分钟)、camera_timeout(请求石沉大海或等不到关键帧)、camera_stream_failed、camera_busy(同时观看满了)、vision_unconfigured(平台加密密钥缺失或换过,重新登记口令);浏览器侧 codec_unsupported、unsupported_environment(没有 WebCodecs)。
本页由 developer/docs/vision.md 生成 · Markdown 原文 · llms.txt