工业相机SDK二次开发实战:从采集到多相机同步

简介:这份资源面向从事物流分拣、工业视觉方向的.NET开发者,聚焦海康相机SDK的二次开发实践,核心是利用MvCodeReaderSDKNet读取快递包裹上的一维码并获取其XY坐标,用于自动化分拣定位。资源包共41个文件,约486KB,以cs源码、csproj工程文件、sln解决方案、config配置、dll动态库及exe可执行程序为主,另含少量缓存与日志文件,构成一个可直接编译运行的Visual Studio项目。项目围绕相机连接、实时流启动、条码识别与坐标提取展开,包含窗体界面、资源文件与程序入口等模块,便于读者对照理解SDK接口调用与工程组织方式。目前已有5600人学习下载,适合希望快速上手海康相机条码识别、搭建分拣验证程序的开发者参考借鉴。

1. 从一台工业相机说起:为什么需要二次开发

产线上摆着一台工业相机,供应商给了一个 SDK 压缩包,里面躺着几个头文件、几个动态库、一份 PDF 手册,然后呢?然后就没有然后了。很多刚接触机器视觉的开发者第一次拿到这类 SDK 时,最直接的反应是“这玩意儿怎么跑起来”。相机能出图,但你要把它接进自己的检测流程、要控制曝光和增益、要抓取每一帧做算法处理、要把结果回传给上位机,这些都不是双击一个 exe 能解决的。所谓二次开发,就是拿着厂商给的底层接口,把相机的能力嵌进你自己的业务系统里。

这个项目围绕的就是这件事:用工业相机 SDK 做一套可编译、可运行、可继续扩展的采集程序。它适合两类人——一类是刚入行机器视觉、需要把相机跑通的新手;另一类是有一定 C++ 基础、想搞清楚 SDK 调用链路和图像采集线程模型的熟手。下面我从工程结构、核心接口、编译运行到二次改造,把整个链路拆一遍。

2. 工程结构与技术选型:这套代码到底由什么组成

2.1 目录划分与模块职责

拿到一个 SDK 项目,我一般先看目录,因为目录结构基本能反映作者的模块化思路。这个项目的典型结构大致如下:

CameraSdkDemo/ ├── include/ # SDK 头文件目录 │ ├── CameraApi.h # 相机控制核心接口 │ ├── CameraDefine.h # 结构体与枚举定义 │ └── CameraStatus.h # 错误码定义 ├── lib/ # 静态库/动态库目录 │ ├── x64/ # 64位库 │ └── x86/ # 32位库 ├── src/ │ ├── main.cpp # 程序入口,初始化与主循环 │ ├── CameraManager.cpp # 相机枚举、打开、关闭封装 │ ├── FrameGrabber.cpp # 采集线程与回调处理 │ └── ImageSaver.cpp # 图像格式转换与保存 ├── thirdparty/ # 第三方依赖(如 OpenCV) ├── CMakeLists.txt # 构建脚本 └── config/ └── camera_config.ini # 曝光、增益、触发模式等参数

include和lib是 SDK 自带的,不要改。src是你自己的业务代码,也是二次开发真正要动的地方。config放运行参数,方便不改代码就调曝光时间。这种分法在工业相机项目里很常见,好处是 SDK 升级时只需要替换 include 和 lib,业务代码不受影响。

2.2 技术栈与依赖选择

核心语言是 C++,因为绝大多数工业相机 SDK 只提供 C/C++ 接口。构建工具用 CMake,跨 Windows 和 Linux 都能用。图像处理部分通常会引入 OpenCV,用来做格式转换(比如把相机输出的 Bayer 格式转成 BGR)和后续算法。如果你不想引入 OpenCV,也可以自己写转换函数,但工作量不小。

线程模型上,采集和业务处理必须分开。相机回调函数里不能做耗时操作,否则会丢帧。常见做法是回调里只做一件事:把图像数据拷贝到队列,然后通知处理线程去取。这个设计在后面讲 FrameGrabber 时会展开。

注意:SDK 的库文件分 32 位和 64 位,编译时一定要和你的目标平台一致,否则会出现链接错误或运行时崩溃。

3. 核心接口拆解:从枚举相机到抓取一帧图像

3.1 相机初始化与枚举

任何相机操作的第一步都是初始化 SDK 环境,然后枚举设备。不同厂商的函数名不一样,但流程大同小异。下面是一段典型的初始化代码:

#include "CameraApi.h" #include "CameraDefine.h" int main() { // 1. 初始化 SDK 环境,必须在所有其他调用之前执行 int status = CameraSdkInit(1); if (status != CAMERA_STATUS_SUCCESS) { printf("SDK init failed, code: %d\n", status); return -1; } // 2. 枚举已连接的相机设备 tSdkCameraDevInfo cameraList[8]; int cameraCount = 8; status = CameraEnumerateDevice(cameraList, &cameraCount); if (status != CAMERA_STATUS_SUCCESS || cameraCount == 0) { printf("No camera found\n"); return -1; } // 3. 打开第一台相机 CameraHandle hCamera; status = CameraInit(&cameraList[0], -1, -1, &hCamera); if (status != CAMERA_STATUS_SUCCESS) { printf("Camera init failed, code: %d\n", status); return -1; } // 4. 设置采集模式为连续采集 CameraSetTriggerMode(hCamera, 0); // 0 表示连续采集,1 表示软触发 CameraPlay(hCamera); // ... 后续采集与处理 // 5. 释放资源 CameraUnInit(hCamera); CameraUnInitLib(); return 0; }

这段代码的逻辑很直白:初始化环境、找相机、打开相机、设置采集模式、开始采集。参数说明上,CameraSdkInit(1)里的 1 通常表示初始化方式,具体含义看手册;CameraInit的第二个和第三个参数是分辨率和位深,传 -1 表示使用相机默认值;CameraSetTriggerMode的 0 和 1 分别对应连续采集和软触发,产线上如果要用外部信号触发,就改成 1 再配合CameraSoftTrigger调用。

3.2 图像采集回调与线程安全

采集图像有两种方式:主动调用CameraGetImageBuffer轮询,或者注册回调函数被动接收。回调方式实时性更好,但必须注意线程安全。下面是一个回调函数的典型写法:

// 全局图像队列,回调线程写入,处理线程读取 std::queue<cv::Mat> g_imageQueue; std::mutex g_queueMutex; // 回调函数:相机每采集一帧就调用一次 void OnFrameCallback(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead *pFrameHead, void *pContext) { // 1. 根据帧头信息判断图像格式 // pFrameHead->uiMediaType 表示输出格式,如 RAW8、RGB24 等 if (pFrameHead->uiMediaType == CAMERA_MEDIA_TYPE_MONO8) { // 2. 将原始数据包装成 OpenCV Mat(不拷贝数据) cv::Mat rawImage(pFrameHead->iHeight, pFrameHead->iWidth, CV_8UC1, pFrameBuffer); // 3. 拷贝一份放入队列,因为回调返回后缓冲区会被 SDK 回收 cv::Mat clonedImage = rawImage.clone(); // 4. 加锁写入队列,通知处理线程 std::lock_guard<std::mutex> lock(g_queueMutex); g_imageQueue.push(clonedImage); } // 5. 必须调用,通知 SDK 该帧已处理完毕,可以复用缓冲区 CameraReleaseImageBuffer(hCamera, pFrameBuffer); }

这里有几个关键点。第一,回调里不能做耗时操作,所以只做拷贝和入队。第二,CameraReleaseImageBuffer必须调用,否则 SDK 的缓冲区会耗尽,导致采集停止。第三,拷贝是必要的,因为回调返回后pFrameBuffer指向的内存可能被下一帧覆盖。第四,队列需要加锁,因为回调线程和处理线程是并发的。

处理线程的代码就简单了,循环从队列取图,做算法处理:

void ProcessThread() { while (g_running) { cv::Mat image; { std::lock_guard<std::mutex> lock(g_queueMutex); if (g_imageQueue.empty()) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); continue; } image = g_imageQueue.front(); g_imageQueue.pop(); } // 在这里做你的检测算法 // ... } }

这种“回调入队、线程处理”的模式在工业相机项目里几乎是标配,能有效避免丢帧和卡顿。

3.3 曝光、增益与触发模式配置

相机参数配置通常通过CameraSetAeState、CameraSetExposureTime、CameraSetGain等函数完成。下面是一段配置示例:

// 关闭自动曝光,使用手动曝光 CameraSetAeState(hCamera, FALSE); // 设置曝光时间为 10000 微秒(即 10ms) CameraSetExposureTime(hCamera, 10000.0); // 设置模拟增益为 2.0 倍 CameraSetGain(hCamera, 2.0); // 设置触发模式为软触发 CameraSetTriggerMode(hCamera, 1); // 发送一次软触发信号,采集一帧 CameraSoftTrigger(hCamera);

参数怎么调,取决于你的场景。产线速度快,曝光时间就要短,但短曝光可能导致图像偏暗,这时候需要补光或者提高增益。增益太高会引入噪声,所以一般优先调曝光,增益作为辅助。触发模式的选择也很关键:连续采集适合调试和低速场景,软触发适合和外部信号同步,硬触发则通过相机 IO 口接收光电传感器信号,实时性最好。

提示:修改曝光和增益后,建议等一两帧再取图,因为参数生效需要时间。我一般会在设置参数后 sleep 50ms 再开始采集。

4. 编译、运行与调试:把代码跑起来

4.1 CMake 构建配置

CMakeLists.txt 是跨平台构建的关键。下面是一个适配 Windows 和 Linux 的配置示例:

cmake_minimum_required(VERSION 3.10) project(CameraSdkDemo) set(CMAKE_CXX_STANDARD 14) # 根据平台选择库目录 if(WIN32) set(SDK_LIB_DIR ${CMAKE_SOURCE_DIR}/lib/x64) set(SDK_LIBS ${SDK_LIB_DIR}/CameraSDK.lib) else() set(SDK_LIB_DIR ${CMAKE_SOURCE_DIR}/lib/linux) set(SDK_LIBS ${SDK_LIB_DIR}/libCameraSDK.so) endif() # 头文件路径 include_directories(${CMAKE_SOURCE_DIR}/include) # 查找 OpenCV find_package(OpenCV REQUIRED) # 源文件 file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/src/*.cpp) # 生成可执行文件 add_executable(CameraSdkDemo ${SOURCES}) target_link_libraries(CameraSdkDemo ${SDK_LIBS} ${OpenCV_LIBS}) # Windows 下需要拷贝动态库到输出目录 if(WIN32) add_custom_command(TARGET CameraSdkDemo POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${SDK_LIB_DIR} $<TARGET_FILE_DIR:CameraSdkDemo>) endif()

这段配置做了几件事:设置 C++ 标准、根据平台选库、找 OpenCV、收集源文件、链接库、Windows 下自动拷贝 DLL。Linux 下还需要设置LD_LIBRARY_PATH或者把 so 文件放到系统库路径。

4.2 编译与运行步骤

Windows 下用 Visual Studio 打开 CMake 项目,或者命令行:

mkdir build && cd build cmake .. -G "Visual Studio 16 2019" -A x64 cmake --build . --config Release

Linux 下:

mkdir build && cd build cmake .. make -j4 ./CameraSdkDemo

运行前确认相机已连接、驱动已安装。如果报“找不到相机”,先检查 USB 或网口连接,再看设备管理器里有没有识别到。Linux 下可能需要配置 udev 规则,否则普通用户没有权限访问 USB 设备。

4.3 常见运行问题与排查

现象一:程序启动后报 SDK 初始化失败。原因通常是库文件没放对位置,或者位数不匹配。解决方法是确认 exe 同目录下有对应的 DLL,或者 Linux 下ldd检查 so 依赖是否齐全。

现象二:能打开相机但采集不到图像。先检查触发模式,如果是软触发但没调CameraSoftTrigger,就不会出图。如果是硬触发,检查外部信号是否正常。另外确认镜头盖有没有摘。

现象三:采集几帧后卡死。大概率是回调里没调CameraReleaseImageBuffer,缓冲区耗尽。检查回调函数最后一行。

现象四:图像颜色不对。相机输出可能是 Bayer 格式,需要做去马赛克。用 OpenCV 的cv::cvtColor配合COLOR_BayerBG2BGR转换即可。

现象五:多相机同时采集时帧率下降。USB 带宽不够,换 USB 3.0 口或者降低分辨率。网口相机则检查网络配置,建议用独立网卡。

5. 二次开发改造:从能跑到好用

5.1 封装成独立采集类

原始 SDK 是面向过程的 C 接口,直接散落在业务代码里不好维护。我一般会封装一个CameraDevice类,把初始化、采集、参数设置、释放都包进去:

class CameraDevice { public: bool Open(int index = 0); void Close(); bool StartGrabbing(); void StopGrabbing(); bool GetFrame(cv::Mat &frame, int timeoutMs = 1000); bool SetExposure(double us); bool SetGain(double gain); private: CameraHandle m_handle; std::thread m_grabThread; std::queue<cv::Mat> m_queue; std::mutex m_mutex; std::condition_variable m_cond; bool m_running = false; };

这样上层业务只需要GetFrame拿图,不用关心 SDK 细节。换相机品牌时,只需要重新实现这个类,业务代码不动。

5.2 增加配置热加载与日志

产线调试时经常需要改曝光参数,如果每次都要重启程序就很麻烦。可以在CameraDevice里加一个配置文件监听线程,检测到camera_config.ini变化就重新读取并应用。日志方面,建议把每帧的时间戳、帧号、曝光值记录下来,出问题时能追溯。

5.3 多相机同步采集

如果项目需要多个相机同时工作,比如双目或者多工位检测,就需要考虑同步。硬件同步靠触发线,软件同步靠时间戳对齐。常见做法是主相机触发后,通过 IO 输出信号触发从相机,保证曝光时刻一致。代码上,每个相机一个采集线程,各自维护队列,上层根据时间戳做配对。

5.4 性能优化要点

第一,避免在回调里做内存分配,可以预分配一个缓冲池。第二,图像拷贝用memcpy而不是逐像素赋值。第三,如果不需要全分辨率,可以在相机端设置 ROI,减少数据量。第四,处理线程用条件变量而不是轮询,降低 CPU 占用。

注意:SDK 的函数大多不是线程安全的,多个线程同时调用同一个相机的接口可能出问题。我一般把相机操作都放在一个线程里,其他线程通过消息队列通信。

6. 踩坑记录:那些年我调相机时翻过的车

6.1 回调里调 SDK 函数导致死锁

现象:程序运行几分钟后卡死,调试发现卡在回调函数里。原因:在回调里调用了CameraSetExposureTime之类的 SDK 函数,而 SDK 内部有锁,回调和主线程互相等待。解决:回调里只做数据拷贝和入队,所有 SDK 调用放到主线程或独立控制线程。

6.2 忘记释放图像缓冲区

现象:采集几十帧后不再更新,相机指示灯正常但没数据。原因:回调里没有调用CameraReleaseImageBuffer,SDK 缓冲区耗尽。解决:确保回调最后一行释放缓冲区,即使发生异常也要释放,可以用 RAII 封装。

6.3 曝光时间设置不生效

现象:调用CameraSetExposureTime后图像亮度没变化。原因:自动曝光没关闭,SDK 覆盖了手动值。解决:先调CameraSetAeState(hCamera, FALSE)再设置曝光时间。

6.4 多线程访问队列崩溃

现象:程序随机崩溃,堆栈指向队列操作。原因:回调线程和处理线程同时读写队列,没有加锁。解决:用std::mutex保护队列,或者换成无锁队列。条件变量等待时要用while而不是if,防止虚假唤醒。

6.5 Linux 下权限不足打不开相机

现象:Linux 下运行报错“permission denied”。原因:USB 设备默认只有 root 可访问。解决:添加 udev 规则,把设备权限开放给普通用户,或者用sudo运行(不推荐)。

7. 二次开发进阶:从单相机到多相机同步的改造思路

单相机跑通之后,下一步往往是多相机。我拿一个双目采集的场景来说改造方法。假设你有两台相机,需要同时曝光、分别取图、按时间戳配对。硬件上,把主相机的闪光输出接到从相机的触发输入,主相机设为软触发,从相机设为硬触发。软件上,主相机回调里记录时间戳,从相机回调里也记录,然后在一个配对线程里根据时间戳差值小于阈值(比如 1ms)的帧组成一对。

代码上,CameraDevice类需要增加一个GetTimestamp方法,返回帧头里的时间戳。配对逻辑可以这样写:

struct FramePair { cv::Mat left; cv::Mat right; double timestamp; }; void PairThread(std::queue<cv::Mat> &leftQueue, std::queue<cv::Mat> &rightQueue, std::queue<FramePair> &pairQueue) { while (g_running) { // 从两个队列各取一帧,比较时间戳 // 如果差值小于 1ms,组成一对 // 否则丢弃较旧的一帧,继续等待 } }

验证方法很简单:拿一个秒表放在相机前,同时采集,看两张图上的时间是否一致。如果差得多,检查触发线连接和触发模式配置。

另一个改造方向是接入深度学习推理。采集到的图像直接送给推理引擎,结果通过串口或网络发给 PLC。这时候要注意推理耗时,如果单帧推理超过采集间隔,就需要丢帧或者降低采集帧率。我一般会在处理线程里加一个帧率统计,实时打印实际处理帧率,方便判断瓶颈在哪。

从那以后我每次调新相机,都强制走一遍“枚举→打开→设参数→采一帧→存图→释放”的最小闭环,确认底层通了再往上堆业务。这个习惯帮我省了很多排查时间。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

C语言实现双线性插值:从原理到定点优化与查表提速

C语言实现双线性插值:从原理到定点优化与查表提速

简介&#xff1a;这是一份面向图像处理、计算机图形学与数值计算初学者的双线性插值学习资料&#xff0c;以C语言实现为主线&#xff0c;帮助读者理解二维平面数据插值的数学原理并完成代码落地。压缩包共31个文件&#xff0c;约1.86MB&#xff0c;包含4个h头文件、3个cpp源文件…

2026/10/20 4:03:24 阅读更多 →
从UDP RTP流到H264文件:NAL单元重组与Annex-B封装实战

从UDP RTP流到H264文件:NAL单元重组与Annex-B封装实战

简介&#xff1a;这是一份面向网络视频传输开发者的实战代码资源&#xff0c;聚焦将RTP包中的H264数据解封装并保存为本地文件&#xff0c;同时通过UDP接收摄像头实时流。适合具备一定C与网络编程基础、从事监控、在线会议或远程教育方向的工程师参考。压缩包共14个文件&#x…

2026/10/20 4:03:24 阅读更多 →
iOS 17免越狱虚拟定位:基于CoreMotion与CLHeading的可信运动模拟

iOS 17免越狱虚拟定位:基于CoreMotion与CLHeading的可信运动模拟

简介&#xff1a;本资源是一款面向iOS 17设备用户的免越狱虚拟定位跑步模拟工具&#xff0c;专为需在不实际运动情况下完成健康类App打卡&#xff08;如Nike Run Club、Keep等&#xff09;的开发者、测试人员及进阶用户设计&#xff0c;解决因天气、时间或身体限制无法真实跑步…

2026/10/20 4:03:24 阅读更多 →

最新新闻

AIGC检测原理与论文写作重构:告别降AI工具,建立真实作者性

AIGC检测原理与论文写作重构:告别降AI工具,建立真实作者性

最近总有人拿着检测报告截图来问我&#xff1a;论文AIGC疑似比例飙到六成以上&#xff0c;学校通知延期&#xff0c;怎么办&#xff1f;说实话&#xff0c;看到这种局面我心里也替人着急&#xff0c;但更着急的是&#xff0c;很多人的第一反应是冲去找“去AI痕迹神器”&#xf…

2026/10/20 10:04:46 阅读更多 →
接口与UI自动化测试框架模板:测开提效实战指南

接口与UI自动化测试框架模板:测开提效实战指南

做测开这几年&#xff0c;我最大的感受就是&#xff1a;真正耗时间的不是业务测试逻辑本身&#xff0c;而是每接一个新项目&#xff0c;都要从零搭一遍自动化框架。目录结构重新建、公共方法重新写、日志和报告重新配&#xff0c;甚至连“怎么读取配置”这种几十行代码都要再敲…

2026/10/20 10:04:46 阅读更多 →
Vue前端用pdf-lib实现PDF盖章签名下载:坐标系避坑与完整指南

Vue前端用pdf-lib实现PDF盖章签名下载:坐标系避坑与完整指南

简介&#xff1a;这是一份基于Vue.js实现PDF上传、盖章与签名功能的完整项目源码包&#xff0c;面向需要为合同、审批等文档流程引入在线签章能力的开发者&#xff0c;适合具备一定Vue基础、希望快速落地的前端学习者。压缩包共19个文件&#xff0c;含5个Vue组件、5个JavaScrip…

2026/10/20 10:04:46 阅读更多 →
STM32F4固件库架构解析:从工程搭建到串口调试与HAL迁移避坑指南

STM32F4固件库架构解析:从工程搭建到串口调试与HAL迁移避坑指南

简介&#xff1a;STM32F4固件库是意法半导体为STM32F4系列微控制器提供的软件开发框架&#xff0c;面向嵌入式工程师与学生开发者&#xff0c;可简化基于ARM Cortex-M4内核的应用开发。压缩包共2425个文件&#xff0c;大小47.1MB&#xff0c;以html说明文档、c/h源代码、png图片…

2026/10/20 10:04:46 阅读更多 →
AI驱动自动化测试工具实测:如何用自然语言替代XPath,解决UI选择器维护难题

AI驱动自动化测试工具实测:如何用自然语言替代XPath,解决UI选择器维护难题

中午在技术群里刷到一条消息&#xff1a;某科技巨头开源了一个主打AI驱动的自动化测试工具。消息一出&#xff0c;群里的反应几乎和我预想的一样&#xff0c;先是“卧槽&#xff0c;又一个颠覆级项目”&#xff0c;再是“以后写UI自动化是不是不用维护选择器了”&#xff0c;最…

2026/10/20 10:04:46 阅读更多 →
MATLAB PCA人脸识别:特征脸原理、降维实现与GUI避坑实战

MATLAB PCA人脸识别:特征脸原理、降维实现与GUI避坑实战

简介&#xff1a;一个基于MATLAB的PCA人脸识别项目&#xff0c;附带图形用户界面&#xff0c;专门面向学习模式识别、计算机视觉或数据降维的高校学生与开发者&#xff0c;可帮助理解如何从高维人脸图像中提取有效信息&#xff0c;并形成低维特征表示的完整流程。压缩包共113个…

2026/10/20 10:03:45 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →