
1. 为什么要在树莓派4B上折腾Halcon把工业级的机器视觉算法库搬到一块信用卡大小的开发板上这件事听起来有点不务正业但实际做下来你会发现它有非常明确的落地场景。我最初动这个念头是因为一个做小型自动化检测设备的朋友找到我他们的产线检测工位想做成便携式的一体机用PC方案成本压不下来功耗和体积也超标问我能不能用树莓派4B跑Halcon做基础的定位和测量。当时我第一反应是够呛因为Halcon官方对ARM平台的支持一直比较克制但真正动手之后发现只要把工具链和依赖理顺跑通核心算子是完全可行的。树莓派4B这块板子的硬件底子其实不差四核Cortex-A72、主频1.5GHz、最高8GB LPDDR4内存GPU是VideoCore VI。对比十年前工控机上跑的视觉方案它的算力已经超过很多老设备了。关键在于Halcon的ARM版本能不能拿到、运行时依赖能不能补齐、以及编译链接环节会不会卡住。这三个问题解决了剩下的就是性能调优的事。这篇文章适合三类人看一是手里有树莓派4B、想把它用进机器视觉项目的开发者二是做嵌入式视觉设备、需要评估ARM平台算法可行性的工程师三是正在学Halcon、想搞清楚跨平台部署到底涉及哪些环节的学生。我会把从系统准备、Halcon ARM包获取、CMake工程配置到实际跑通一个测量Demo的完整链路讲清楚中间踩过的坑也会一并交代。需要提前说明的是Halcon在ARM上的部署和x86平台有本质区别很多在PC上理所当然的操作在这里行不通心态上要做好重新学一遍的准备。2. 树莓派4B的系统选择与基础环境搭建2.1 系统镜像到底选哪个版本树莓派4B能跑的系统不少官方Raspberry Pi OS、Ubuntu Server、Ubuntu Desktop、甚至一些轻量发行版都行。但涉及Halcon部署我的建议很明确优先选64位的Ubuntu Server 20.04 LTS或22.04 LTS。原因有三点。第一Halcon的ARM版本主要面向aarch64架构发布32位armhf的包越来越难找即使找到也是老版本。第二Ubuntu的软件源里CMake、GCC、OpenCV这些依赖的版本比Raspberry Pi OS新省去大量手动编译的麻烦。第三Server版没有桌面环境内存占用低把宝贵的RAM留给算法本身。如果你确实需要图形界面调试可以装Desktop版但要做好内存吃紧的心理准备8GB版本会从容很多。烧录镜像用官方的Raspberry Pi Imager就行选Other general-purpose OS里的Ubuntu Server 64位。烧录前记得在Imager的高级设置里预先配置好WiFi、主机名和SSH省得插上显示器再折腾。第一次启动会比较慢树莓派4B的SD卡读写是瓶颈建议用A2级别的卡不然系统更新能等到你怀疑人生。2.2 系统装完必须做的几件事系统起来之后先别急着装Halcon有几件基础工作必须做扎实否则后面会反复返工。第一件是换软件源。默认的Ubuntu源在国内访问速度堪忧换成国内镜像源之后apt安装速度能快十倍。编辑/etc/apt/sources.list把里面的archive.ubuntu.com和security.ubuntu.com替换成镜像地址即可。换完之后执行sudo apt update sudo apt upgrade -y第二件是扩容文件系统。如果你用的是比实际SD卡容量小的镜像烧录系统分区可能没占满整张卡。用df -h看一下根分区大小如果明显小于卡的容量用raspi-config或者growpart扩容。Halcon的库文件和开发包加起来好几个GB空间不够会直接卡死。第三件是关闭不必要的服务。树莓派4B的散热是个老问题满载跑视觉算法时CPU温度很容易冲到80度以上触发降频。除了加散热片和风扇软件层面可以关掉一些用不到的服务比如蓝牙、avahi-daemon。另外在/boot/firmware/config.txt里可以适当调整但注意不要盲目超频稳定性比那点性能提升重要得多。第四件是确认架构。执行uname -m输出必须是aarch64。如果是armv7l说明你装的是32位系统后面Halcon的包会对不上趁早重装。2.3 编译工具链的安装Halcon在ARM上开发绕不开CMake和GCC。Ubuntu Server自带的GCC版本通常够用但CMake建议装新一点的版本因为Halcon的CMake配置文件里用到了一些较新的语法特性。sudo apt install -y build-essential cmake git pkg-config装完之后用cmake --version确认一下建议在3.16以上。如果apt源里的版本太老可以去CMake官网下载aarch64的预编译包解压后把bin目录加到PATH里。这里有个细节不要用pip装cmake那个版本和系统库的配合经常出问题老老实实用apt或者官方二进制包。另外建议装一个ninja作为构建后端比make快不少尤其在树莓派这种多核但单核性能一般的平台上并行构建的收益很明显sudo apt install -y ninja-build3. Halcon在ARM平台的获取与依赖处理3.1 Halcon ARM版本的获取渠道这是整个流程里最容易被卡住的一步。Halcon是商业软件官方下载页面提供的安装包主要面向x86_64的Windows和Linux。ARM版本的情况比较特殊MVTec官方确实提供aarch64的Linux版本但通常需要通过正式授权渠道获取不是随便就能下载到的。如果你所在的公司或学校有Halcon的正版授权可以直接联系MVTec或者国内代理商说明需要Linux aarch64版本。一般会给你一个下载链接和对应的license文件。这里要提醒一句license是和硬件绑定的ARM平台的license通常基于网卡MAC地址或者加密狗拿到之后要按官方文档正确配置否则运行时会报license错误。如果你只是想学习研究可以先用Halcon的试用版或者评估版但要注意试用版在ARM上的功能限制。另外网上流传的一些破解版我强烈不建议使用一是法律风险二是这类包经常被篡改在嵌入式设备上跑出问题很难排查。3.2 安装包的结构和关键目录拿到Halcon的Linux aarch64安装包之后先别急着运行安装脚本。解压看一下目录结构通常包含这几个部分bin/aarch64-linux可执行文件和运行时库lib/aarch64-linux核心动态库比如libhalcon.so、libhalconcpp.soincludeC和C的头文件examples示例代码license授权相关文件安装的时候建议装到一个固定路径比如/opt/halcon方便后面CMake引用。安装脚本一般会问你是否配置环境变量选是的话会在/etc/profile.d/下生成一个脚本设置HALCONROOT、HALCONARCH、LD_LIBRARY_PATH这些变量。装完之后记得source一下或者重新登录让环境变量生效。验证安装是否成功可以跑一下hdevelop的命令行版本或者直接写个小程序调用get_system算子。如果报找不到库八成是LD_LIBRARY_PATH没配对。3.3 运行时依赖的补齐Halcon在Linux上依赖不少系统库ARM平台尤其要注意。常见的缺失库包括依赖库用途安装命令libusb-1.0加密狗通信sudo apt install libusb-1.0-0-devlibx11 / libxext图形显示相关sudo apt install libx11-dev libxext-devlibgl1 / libglu1OpenGL渲染sudo apt install libgl1-mesa-dev libglu1-mesa-devlibtiff / libjpeg图像格式支持sudo apt install libtiff-dev libjpeg-devlibavcodec等视频编解码sudo apt install libavcodec-dev libavformat-dev即使你不需要图形界面libx11这类库也可能被间接依赖因为Halcon的某些库在编译时链接了它们。用ldd命令检查libhalcon.so的依赖情况ldd /opt/halcon/lib/aarch64-linux/libhalcon.so | grep not found有not found的逐个装上就行。这一步很关键很多人编译通过了但一运行就崩问题往往就出在运行时库缺失。4. CMake工程配置的完整拆解4.1 为什么不用qmake而选CMakeHalcon的示例代码里qmake和CMake的工程都有但在ARM平台上我强烈建议用CMake。原因很实际Halcon官方提供的Halcon.cmake配置文件对CMake的支持最完善能自动处理头文件路径、库路径、架构判断这些琐事。qmake虽然也能用但需要手动写一堆LIBS和INCLUDEPATH跨平台时容易出错。更重要的是CMake的find_package机制配合Halcon提供的配置文件可以做到写一次x86和ARM都能编译。你只需要在CMakeLists里指定HALCON_ARCH剩下的交给Halcon的cmake脚本处理。4.2 一个能跑通的最小CMakeLists下面这个CMakeLists是我在实际项目中反复打磨过的去掉业务代码后保留最核心的配置你可以直接拿去改cmake_minimum_required(VERSION 3.16) project(HalconARMTest CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定Halcon安装根目录也可以通过环境变量传入 if(NOT DEFINED HALCONROOT) set(HALCONROOT /opt/halcon) endif() # 指定架构树莓派4B是aarch64 set(HALCON_ARCH aarch64-linux) # 引入Halcon的CMake配置 list(APPEND CMAKE_MODULE_PATH ${HALCONROOT}/cmake) find_package(Halcon REQUIRED) # 可执行文件 add_executable(halcon_test main.cpp) # 链接Halcon库 target_link_libraries(halcon_test PRIVATE ${HALCON_LIBRARIES}) target_include_directories(halcon_test PRIVATE ${HALCON_INCLUDE_DIRS})这里有几个关键点要解释。CMAKE_MODULE_PATH必须指向Halcon安装目录下的cmake文件夹find_package(Halcon)才能找到FindHalcon.cmake。HALCON_ARCH这个变量决定了链接哪个架构的库写错了会链接到x86的库编译时就会报架构不匹配。4.3 编译时最常见的三个报错报错一找不到HalconConfig.cmake。这通常是CMAKE_MODULE_PATH没设对或者HALCONROOT路径写错了。用ls确认一下/opt/halcon/cmake目录下确实有FindHalcon.cmake文件。报错二undefined reference toHalconCpp::HObject::...。这是链接顺序问题。Halcon的库有依赖关系halconcpp依赖halcon链接时顺序不能反。用target_link_libraries时把${HALCON_LIBRARIES}放在最后CMake会自动处理顺序。如果还不行手动指定halconcpp在前、halcon在后。报错三cannot find -lhalcon。说明库路径没加进去。检查HALCON_LIBRARIES变量是否为空可以在CMakeLists里加一句message(STATUS Halcon libs: ${HALCON_LIBRARIES})打印出来看。4.4 交叉编译还是本地编译这里要澄清一个常见误区。很多人一提到ARM开发就想到交叉编译但在树莓派4B这个场景下本地编译往往是更省事的选择。原因很简单树莓派4B的性能足够跑编译而且本地编译避免了交叉工具链配置、sysroot同步这些麻烦事。Halcon的库本身就是aarch64的本地编译直接链接就行。交叉编译适合的是批量生产场景比如你要给几百台设备烧录固件那在x86主机上配好aarch64工具链批量编译确实高效。但如果是开发调试阶段本地编译的迭代速度反而更快改完代码直接make不用scp传文件。如果你确实需要交叉编译工具链文件大概长这样set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g) set(CMAKE_FIND_ROOT_PATH /path/to/sysroot) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)但要注意sysroot里必须有Halcon的aarch64库和头文件否则链接会失败。5. 跑通第一个Halcon测量Demo5.1 从读取图像到边缘测量光编译通过不算数得跑个实际算法验证。下面这段代码做的是最经典的测量任务读一张图用卡尺工具测两个边缘之间的距离。这个流程在工业检测里非常常见比如测零件宽度、孔径、间隙。#include HalconCpp.h #include iostream using namespace HalconCpp; int main() { try { // 读取图像 HObject image; ReadImage(image, part.png); // 转灰度 HObject gray; Rgb1ToGray(image, gray); // 创建测量模型 HTuple width, height; GetImageSize(gray, width, height); // 定义测量矩形位置和角度根据实际图像调整 HTuple row height / 2; HTuple col width / 2; HTuple phi 0; HTuple length1 100; HTuple length2 20; HObject measureHandle; CreateMeasureHandle(row, col, phi, length1, length2, nearest_neighbor, measureHandle); // 执行测量 HTuple measureResult, score; MeasurePos(gray, measureHandle, 1, 30, all, all, measureResult, score); // 计算距离 HTuple distance; DistancePp(measureResult[0], measureResult[1], measureResult[2], measureResult[3], distance); std::cout Measured distance: distance[0].D() pixels std::endl; CloseMeasureHandle(measureHandle); } catch (HException ex) { std::cerr Halcon error: ex.ErrorMessage() std::endl; return -1; } return 0; }编译运行mkdir build cd build cmake .. -G Ninja ninja ./halcon_test如果一切正常会输出测量到的像素距离。这里要强调一点像素距离不等于物理距离要得到实际尺寸必须做标定。标定的本质是求出每个像素对应多少毫米方法是用已知尺寸的标定板拍一张图用Halcon的标定算子算出相机内参和畸变系数。5.2 性能实测与优化方向在树莓派4B上跑上面这个测量流程单张1080p图像的处理时间大概在几十毫秒到一百多毫秒之间具体取决于测量区域大小和参数设置。这个速度对于低速检测场景比如每秒几帧是够用的但如果你要做实时视频流处理就得优化。优化方向有几个。第一是缩小ROI只对感兴趣区域做处理不要全图跑。第二是降低图像分辨率如果精度允许把图像缩放到一半大小处理速度能提升三四倍。第三是用Halcon的并行算子树莓派4B有四个核parallel相关的算子能利用多核。第四是避免频繁创建销毁句柄测量句柄这类对象尽量复用。还有一个容易被忽略的点内存带宽。树莓派4B的内存带宽有限大图像频繁拷贝会成为瓶颈。能用引用就用引用避免不必要的图像复制。5.3 深度图转点云的尝试如果你的应用涉及3DHalcon的深度图转点云功能在ARM上也能跑。核心算子是把深度图的灰度值按标定参数映射到三维坐标。这个计算量比2D测量大不少树莓派4B处理一张640x480的深度图大概需要几百毫秒。如果要做实时3D建议降低分辨率或者只处理关键区域。深度图转点云的关键是标定参数要准包括相机的内参和深度图的缩放系数。参数错了点云就是歪的。建议先在PC上用Halcon验证参数再移植到树莓派上。6. 部署过程中踩过的坑与排查思路6.1 license报错的几种形态license问题是ARM部署里最高频的坑。表现形态有好几种程序启动直接退出、报license not found、报license expired、或者跑着跑着突然报license错误。第一种情况通常是license文件路径没配对。Halcon通过HALCON_LICENSE_FILE环境变量或者默认路径找license确认一下变量是否设置正确。第二种情况是license和硬件不匹配ARM平台的license往往绑定MAC地址换了网卡或者用了USB网卡都会导致失效。第三种情况比较隐蔽是license的并发数用完了如果你同时跑了多个Halcon进程可能超出授权数量。排查的时候先用Halcon自带的license管理工具看一下当前license状态确认有效期和绑定信息。如果是在Docker里跑要注意容器的MAC地址和宿主机不一样license可能对不上。6.2 段错误和库版本冲突程序编译通过但一运行就段错误这是第二高频的问题。原因通常是运行时链接到了错误的库版本。比如系统里装了多个版本的libstdc或者Halcon的库和系统库有符号冲突。排查手段是用ldd看实际链接了哪些库用gdb跑一下看崩溃时的调用栈。常见的一个坑是Halcon的库是用较老版本的GCC编译的而你的程序用新版本GCC编译C ABI不兼容。解决办法是统一GCC版本或者用-D_GLIBCXX_USE_CXX11_ABI0编译。另一个坑是OpenCV。如果你的项目同时用了OpenCV和Halcon两者可能链接了不同版本的底层库比如libjpeg、libpng导致符号冲突。建议把OpenCV的依赖也理清楚必要时静态链接。6.3 散热降频导致性能忽高忽低这个问题很隐蔽因为程序逻辑没问题但性能就是不稳定。树莓派4B在持续满载时SoC温度会迅速上升超过85度就触发降频主频从1.5GHz掉到1GHz甚至更低。表现出来就是前几帧很快后面越来越慢。解决办法硬件上加散热片和风扇软件上可以用vcgencmd measure_temp监控温度。如果温度确实压不住考虑降低算法复杂度或者加处理间隔。另外把树莓派放在通风良好的位置别塞在密闭盒子里。6.4 图像采集环节的坑如果你接的是USB工业相机在树莓派4B上要特别注意USB带宽。树莓派4B有两个USB 3.0和两个USB 2.0口相机一定要插在USB 3.0口上否则带宽不够会导致丢帧。另外USB相机的驱动在ARM上可能和x86不一样有些相机厂商只提供x86的SDKARM上要么用通用UVC驱动要么找厂商要ARM版本。用GigE相机的话树莓派4B的千兆网口是够用的但要注意网络配置确保相机和树莓派在同一网段MTU设置合理。7. 一些实用的经验和小技巧关于Halcon在树莓派上的实际使用我积累了几条经验都是文档里不会写的。第一开发阶段在PC上做部署阶段再上树莓派。Halcon的HDevelop在PC上调试算法效率高得多可视化、参数调整都方便。算法定型之后再移植到树莓派用C接口封装。这样能省下大量在树莓派上反复编译调试的时间。第二善用Halcon的导出功能。HDevelop可以把程序导出成C代码虽然导出的代码风格一般但至少保证了算子调用顺序和参数正确。在此基础上做封装和优化比从零写快得多。第三注意图像数据的类型转换。Halcon内部用HObject管理图像和OpenCV的Mat之间转换时要注意数据布局。Halcon默认是行优先和OpenCV一致但通道顺序可能不同RGB和BGR要转换清楚。第四日志和异常处理要做扎实。嵌入式设备上出问题不像PC上那么好调试建议在关键步骤加日志记录时间戳和中间结果。Halcon的异常信息比较详细用try-catch包住把ErrorMessage打出来能省很多排查时间。第五版本匹配很重要。Halcon的版本、CMake的版本、GCC的版本之间有一定的兼容性要求。不要盲目追新用官方文档里推荐的组合最稳妥。我遇到过用最新GCC编译Halcon老版本库导致链接失败的情况退回GCC 9就正常了。最后说一个关于性能的预期管理。树莓派4B跑Halcon做简单的定位、测量、缺陷检测是没问题的但别指望它能跑深度学习推理或者复杂的3D重建。它的定位是低成本、低功耗的边缘视觉节点适合算法相对固定、实时性要求不极端的场景。如果你的应用需要更强的算力可以考虑树莓派加一个神经网络加速棒或者直接上更高性能的ARM工控板。选型的时候把算法复杂度和性能需求算清楚比事后优化省事得多。