news 2026/9/16 23:50:16

单目相机标定原理与OpenCV实现:从张正友法到工程落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单目相机标定原理与OpenCV实现:从张正友法到工程落地

我最早接触相机标定,是因为一个挺打脸的项目:客户拿了一个固定式扫码相机,说要测传送带上零件的长宽,我拿着卷尺在旁边比了半天,像素距离换算出来的尺寸就是差那么几个毫米。后来才明白,问题不在测量公式,而在相机自己“看”到的世界本来就是扭曲的。你按理想针孔模型去换算,越靠图像边缘,误差越大。从那以后我就养成了一个习惯:不管用什么相机干活,先标定,再谈后面的事。

单目相机标定,说简单也简单,本质就是算出相机的内参(焦距、主点)、畸变系数和外参(相机在世界坐标中的位姿)。说复杂也复杂,因为背后牵扯到成像模型、坐标系变换、非线性优化一堆概念。这篇我尽量用“能上手干活”的方式来讲,先把原理讲到够用的程度,再给一套基于OpenCV的完整实现流程,最后把我踩过的一些坑也一并列出来。适合刚接触视觉、准备做测量/识别/定位项目、或者被标定精度折磨过的同学参考。

1. 相机成像模型与畸变:为什么要给镜头“配眼镜”

1.1 从针孔模型说起:三维坐标是怎么变成二维像素的

理解标定之前,先得建立一条完整链路:真实世界里的一个三维点,到底经历了什么,才最终落在传感器上变成一个像素。

经典的小孔成像模型是这样描述的:假设光线通过一个无限小的孔,在后方成像平面上留下倒像。数学上简化为“中心投影”,一个三维点 (P_w = (X_w, Y_w, Z_w)) 经过相机光心投影到成像平面上的位置。这个过程可以拆成四步坐标变换:

  1. 世界坐标系→相机坐标系:用旋转矩阵 (R) 和平移向量 (t) 描述相机在世界中的位姿,也就是外参。
  2. 相机坐标系→归一化平面:把三维点除以 (Z_c),得到归一化坐标 ((x, y) = (X_c/Z_c, Y_c/Z_c))。
  3. 归一化平面→图像物理坐标:乘上焦距 (f),得到 ((f\cdot x, f\cdot y))。
  4. 图像物理坐标→像素坐标:加上主点偏移 ((c_x, c_y)),再分别乘上 (x)、(y) 方向单位距离对应的像素数。

整个投影过程用一个 3x4 的投影矩阵就能写清楚:

[ s \begin{bmatrix} u \ v \ 1 \end{bmatrix} = \begin{bmatrix} f_x & 0 & c_x \ 0 & f_y & c_y \ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} r_{11} & r_{12} & r_{13} & t_1 \ r_{21} & r_{22} & r_{23} & t_2 \ r_{31} & r_{32} & r_{33} & t_3 \end{bmatrix} \begin{bmatrix} X_w \ Y_w \ Z_w \ 1 \end{bmatrix} ]

其中中间的 3x3 矩阵就是内参矩阵 (K),习惯上叫它 (K)。(f_x、f_y) 是焦距的像素表达(实际是 (f/dx、f/dy),也就是焦距除以单个像素的物理尺寸),(c_x、c_y) 是主点——理论上应该在图像正中心,实际工艺会导致偏差几个像素,这个偏差不标定是猜不准的。

注意:内参矩阵描述的是“相机自身的光学属性”,只要镜头和传感器相对位置不变,内参就不变。变的是外参,因为每次移动相机,(R) 和 (t) 都会跟着变。OpenCV的calibrateCamera能同时输出内参和每张图的外参,但工程上我们通常只留内参和畸变系数,外参用solvePnP按需实时解算。

1.2 镜头畸变:让直线变弯的罪魁祸首

针孔模型是理想状态,现实中的镜头是一组透镜,光线穿过透镜会发生折射,不可能完美地汇聚到理想位置。于是照片就产生了畸变,主要分两类。

径向畸变:图像边缘的直线向内或向外弯曲。向内弯叫枕形畸变,向外弯叫桶形畸变,广角镜头尤其明显。原因是透镜中央和边缘的放大率不一致。数学上用 (k_1、k_2、k_3) 三个系数来修正,修正公式是:

[ \begin{aligned} x_{corrected} &= x(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \ y_{corrected} &= y(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \end{aligned} ]

其中 (r) 是点到主点的距离。可以看到,距离主点越远((r) 越大),畸变修正量越大,所以图像四角的变形最明显。

切向畸变:镜头装配偏差导致透镜与传感器平面不完全平行造成的,会让直线在某个方向上产生横向偏移,用 (p_1、p_2) 两个系数修正:

[ \begin{aligned} x_{corrected} &= x + [2p_1 xy + p_2(r^2 + 2x^2)] \ y_{corrected} &= y + [p_1(r^2 + 2y^2) + 2p_2 xy] \end{aligned} ]

所以标定输出的畸变系数完整是五元组 ((k_1, k_2, p_1, p_2, k_3)),OpenCV的calibrateCamera默认返回5个值。有些精度要求不高的场景只用前两个径向畸变系数也能凑合,但正式项目我还是建议5个全求。

1.3 畸变系数到底在修正什么

很多人看完公式会问:这些系数不就是把图像重新扭曲一遍吗?对,也不全对。

畸变系数的本质是建立一条“真实光线方向→像素位置”的映射曲线。你去畸变的时候,不是简单地把像素挪一挪,而是对整幅图像做重映射(remap),每个像素都根据它离主点的距离重新采样。OpenCV里的undistortremap就是这个原理。

我曾经有个项目用的是120度的广角工业相机,不标定时画面边缘的直线明显弯曲,用undistort处理之后,整幅图看起来“正常”多了。但这个“正常”是有代价的:去畸变后的图像边缘会有黑边或裁切,有效视野变小。所以后来的项目里,我宁愿保留畸变图像做识别,只在需要测量/定位的环节才做去畸变,有时候直接用畸变系数把检测到的像素坐标反向修正,效率比全图重映射高得多。

2. 张正友标定法:一张棋盘格如何算出相机全部参数

2.1 为什么是棋盘格:角点提取的天然优势

提到标定就绕不开张正友标定法,它解决的问题是:在没有昂贵3D标定物的情况下,怎么用平面棋盘格求出相机的内外参。这篇论文1998年发表,至今仍是OpenCV、MATLAB标定工具箱的底层核心。

棋盘格之所以成为标定板的绝对主流,是因为它的角点特征极其稳定。黑白格子交替排列,角点处灰度变化剧烈,findChessboardCorners这类算法能够精准定位亚像素角点。而且棋盘格是平面结构,所有角点都在同一个平面上,这个约束给求解提供了极大便利。

实际操作中用到的棋盘格通常是 9x6 或者 7x10,这里的数字指的是内部角点数,不是格子数。比如 9x6 的棋盘格,实际上有10列7行格子,角点是格子与格子之间的交点。这一点经常有人搞混,用OpenCV时findChessboardCornerspatternSize参数填的就是内部角点数 ((9, 6)),填错就检测不出来。

2.2 单应性矩阵里藏着什么

张正友法的核心是单应性矩阵。三维空间中的平面点投影到图像平面,是一个从平面坐标系到像素坐标系的齐次变换,用 3x3 的单应矩阵 (H) 表示:

[ s \begin{bmatrix} u \ v \ 1 \end{bmatrix} = K [r_1 \quad r_2 \quad t] \begin{bmatrix} X \ Y \ 1 \end{bmatrix} = H \begin{bmatrix} X \ Y \ 1 \end{bmatrix} ]

看这个式子,(H) 包含了内参 (K)、旋转矩阵的前两列 (r_1、r_2) 和平移向量 (t)。棋盘格上每个角点的世界坐标 ((X, Y)) 是已知的(我们设定它,比如角点间距30mm),像素坐标 ((u, v)) 是检测出来的,一组点就能建立一个方程组,一对 ((X, Y)) 对应一个 ((u, v)),可以提供2个约束方程,所以至少4个对应点就能解出 (H)。而一张棋盘格上有几十个角点,(\textbf{H}) 的求解是超定问题,用最小二乘就能稳定输出。

2.3 从多张照片联立内参的数学思路

一张棋盘格照片只能提供一个单应矩阵 (H),而 (H) 里同时混着内参和外参。要单独把内参 (K) 解出来,需要利用旋转矩阵的正交约束。

旋转矩阵的每一列是单位向量,且两两正交。所以 (r_1、r_2) 满足 (r_1^T r_2 = 0) 且 (|r_1| = |r_2|)。这两个约束反映到 (H = [h_1 \quad h_2 \quad h_3]) 上,就变成了关于内参 (K) 的两个方程。每个方程本质上是对 (K^{-T}K^{-1}) 这个对称矩阵的元素做线性约束,所以:

  • 一张图给2个约束;
  • 内参矩阵有4个未知量(fx, fy, cx, cy)需要考虑畸变后再定;
  • 不考虑畸变时,理论上2张图就能解出内参;
  • 但实际中为了数值稳定和精度,至少拍10~20张不同角度的图。

这就是为什么OpenCV标定也好,MATLAB标定App也好,都要求多角度采集。不是算法需要那么多,是噪声、光照、检测误差都需要数据量来摊平。

2.4 非线性优化:让参数更准的最后一步

线性求解出来的内外参只是个初值,因为上面所有的推导都忽略了畸变,而且角点检测本身有亚像素噪声。所以张正友法的最后一步是非线性最小二乘优化,工具上对应OpenCV的calibrateCamera里内置的Levenberg-Marquardt迭代。

优化的目标函数是重投影误差的平方和:

[ \min_{K, D, R_i, t_i} \sum_{i=1}^{N} \sum_{j=1}^{M} \left| p_{ij} - \hat{p}(K, D, R_i, t_i, P_j) \right|^2 ]

翻译成人话:把第 (i) 张图里第 (j) 个角点的三维坐标 (P_j),用当前的内外参重新投影到像平面上,得到预测位置 (\hat{p}),和实际检测到的像素位置 (p_{ij}) 求距离。所有图所有角点的距离平方求和,然后不断迭代参数让这个总误差最小化。

这一步也是为什么OpenCV标定之后会返回一个RMS值(重投影误差均方根),我通常把它当作标定质量的第一道检验指标,经验值后面会细说。

3. 基于OpenCV的标定全流程:从拍照到参数落地

3.1 标定板准备:规格选择与打印要注意的事

标定板网上有现成的PDF可以直接打印。选型我总结了几条经验:

  • 精度要求0.1mm以上的项目,别用A4纸打印,用亚克力或玻璃基底的工业标定板。纸张热胀冷缩,贴在不平桌面上会局部变形,角点位置偏移直接传导到内参上。我见过最夸张的一次,打印纸受潮翘边,标定出来fx差了2%。
  • 格子尺寸用游标卡尺实测,别信打印参数。打印机的缩放误差不定,直接量实际边长填进去,比用理论值准得多。
  • 棋盘格内部角点数量选9x6比较均衡,角点太多在边缘视野里容易被裁掉,太少约束不够。

如果一定要自己打印应急,最好贴在硬质平板(铝板、亚克力板)上,拍的时候尽量用手指按压四边确保平整。

3.2 图像采集:影响精度的几个关键习惯

图像采集是整个标定流程里最容易被低估的环节。代码写得再漂亮,输入数据烂,输出参数就不可能好。

我总结的采集标准如下表:

项目建议值原因
图片数量15~20张太少约束不足,太多增加计算耗时且边际收益递减
标定板占画面比例1/4 ~ 3/4太小角点不清晰,太大超出视野
角度变化与相机光轴夹角15°~30°张正友法需要非平面角度,全正对着拍会退化成病态问题
覆盖范围画面九个区域都要拍到边缘畸变信息必须靠标定板出现在边缘来激励
光照均匀、无强烈反光反光会让角点检测失效
相机设置固定光圈、固定焦距(手动对焦)自动对焦/自动光圈会让内参变化,标定结果失去意义

另外,拍照时标定板尽量保持静止,避免运动模糊。手持也行,但快门速度要够。我用工业相机拍摄时习惯把曝光固定在一个不过曝的值,然后连拍几十张再筛选,比一张张摆姿势节约时间。

3.3 完整标定代码与参数保存

下面是基于OpenCV的完整标定代码,我用了Python,C++思路完全一样。代码接受一个文件夹作为输入,读取里面所有jpg图片,检测9x6棋盘格角点,然后标定并保存结果。

import cv2 import numpy as np import glob import json # 配置参数 CHESSBOARD_SIZE = (9, 6) # 内部角点数 SQUARE_SIZE = 30.0 # 实际格子边长,单位mm image_folder = "./calib_images/" # 图像文件夹 output_file = "./camera_params.json" # 1. 准备标定板物理坐标 objp = np.zeros((CHESSBOARD_SIZE[0] * CHESSBOARD_SIZE[1], 3), np.float32) objp[:, :2] = np.mgrid[0:CHESSBOARD_SIZE[0], 0:CHESSBOARD_SIZE[1]].T.reshape(-1, 2) objp *= SQUARE_SIZE # 2. 遍历图像,收集角点 obj_points = [] # 3D 物理坐标 img_points = [] # 2D 像素坐标 image_size = None images = glob.glob(image_folder + "*.jpg") valid_count = 0 for fname in images: img = cv2.imread(fname) if img is None: continue gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if image_size is None: image_size = gray.shape[::-1] # 查找棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, CHESSBOARD_SIZE, None) if ret: # 亚像素精化 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners_refined = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) obj_points.append(objp) img_points.append(corners_refined) valid_count += 1 # 可视化确认 vis = cv2.drawChessboardCorners(img, CHESSBOARD_SIZE, corners_refined, ret) cv2.imshow("check", vis) cv2.waitKey(100) else: print(f"角点检测失败: {fname}") cv2.destroyAllWindows() print(f"有效图像数: {valid_count} / {len(images)}") if valid_count < 5: raise RuntimeError("有效图像太少,标定结果不可靠") # 3. 执行标定 rms, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera( obj_points, img_points, image_size, None, None ) print("RMS 重投影误差:", rms) print("内参矩阵:\n", camera_matrix) print("畸变系数:\n", dist_coeffs.ravel()) # 4. 保存结果 result = { "rms": float(rms), "camera_matrix": camera_matrix.tolist(), "dist_coeffs": dist_coeffs.ravel().tolist(), "image_size": list(image_size), "square_size_mm": SQUARE_SIZE, } with open(output_file, "w", encoding="utf-8") as f: json.dump(result, f, indent=2, ensure_ascii=False) print("标定结果已保存到:", output_file)

代码逻辑不复杂,但有几个点值得强调:

  • objp的 z 坐标全为0,因为标定板是平面。这个平面就是世界坐标系的 XY 平面。
  • cornerSubPix的亚像素精化很重要,直接决定角点精度。窗口大小(11, 11)足够,太大反而容易引入邻近格子的干扰。
  • calibrateCamera一次输出内参、畸变系数、每张图的外参(旋转向量和平移向量)。外参如果要转4x4齐次矩阵,用cv2.Rodrigues把旋转向量转成旋转矩阵。

3.4 验证标定结果:去畸变与重投影误差

拿到参数不要急着用,先做两项验证。

第一项:看RMS。calibrateCamera返回的rms单位是像素。经验值如下:

RMS值评价建议
< 0.1优秀高精度测量项目可用
0.1 ~ 0.3良好大多数视觉定位/识别项目可用
0.3 ~ 0.5及格简单手势识别/粗略定位可用
> 0.5检查角点检测和图像质量,重新标定

第二项:看实际去畸变效果。用棋盘格和标定后的参数做去畸变,观察画面边缘的直线是否恢复平直。

import cv2 import numpy as np import json # 读取标定结果 with open("./camera_params.json", "r", encoding="utf-8") as f: calib = json.load(f) camera_matrix = np.array(calib["camera_matrix"]) dist_coeffs = np.array(calib["dist_coeffs"]) image_size = tuple(calib["image_size"]) # 计算去畸变映射表 new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix( camera_matrix, dist_coeffs, image_size, alpha=0, newImgSize=image_size ) mapx, mapy = cv2.initUndistortRectifyMap( camera_matrix, dist_coeffs, None, new_camera_matrix, image_size, cv2.CV_32FC1 ) # 加载一张标定测试图做验证 img = cv2.imread("./calib_images/verify.jpg") if img is not None: undistorted = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) compare = np.hstack([img, undistorted]) cv2.imshow("before | after", compare) cv2.waitKey(0) cv2.destroyAllWindows()

getOptimalNewCameraMatrix里有个alpha参数,注意它的含义:

  • alpha=0:所有像素都保留,但会有黑边,视野最小。
  • alpha=1:裁掉所有无效区域,无黑边,视野稍微变小。
  • alpha=0.5:折中。

去畸变本质是重新采样,所以只需要计算一次映射表,之后每一帧直接用remap,比每帧调用undistort更快。工控机上实测,1080p图像单次remap大概3~5ms,够实时。

4. 标定实操中的坑:光照、角点检测失败与精度自查

4.1 角点检测失败的常见原因与解决

最早用findChessboardCorners的时候,我总以为只要把棋盘格放在镜头前就一定能检测出来,结果实际拍摄中经常检测失败,尤其是边缘位置、反光区域。逐条排查下来,原因基本集中在下面几类:

  • 反光:亚克力标定板在强光下会出现高光斑块,角点被亮斑吞掉。处理办法是调整光源角度,用柔光,或者用哑光面朝相机。
  • 过曝/欠曝:智能手机拍的图自动曝光导致黑白格子反差变小。工业相机就固定曝光时间,让白色格子亮度在200~230之间,黑色在30~60之间,对比度最大,检测率最高。
  • 棋盘格太小:角点占的像素太少,亚像素精化起不到作用。我一般要求格子边长的成像宽度至少在15像素以上。
  • 棋盘格太满:占满整个画面且偏斜时,边缘格子容易被裁掉一半,内部角点计数对不上。回到3.2的“占画面1/4~3/4”建议。

一旦某张图检测失败,我会在采集阶段就当场删除,而不是后面靠代码筛选。代码里加个可视化窗口,每拍一张就画上角点给人眼确认,这种“人工质检”比任何自动筛选都高效。

4.2 拍了一堆图误差却很大的排查思路

有一次我帮同事标定一个鱼眼镜头改装的工业相机,采集了20张图,RMS飙到0.8。排查过程值得分享:

  1. 先看是不是某张图拖后腿。OpenCV的calibrateCamera不直接输出逐图误差,但可以用projectPoints自己算。把每张图的平均重投影误差打印出来,定位到误差异常大的图。
  2. 看那张图是不是标定板太偏。结果显示,所有误差大的图,标定板都出现在画面左下角边缘,而且在极端倾斜角度。边缘畸变严重时角点检测精度本来就下降,极端角度又让部分角点在亚像素层面对不齐。
  3. 剔除极端图重标。砍掉那几张误差最大的图,RMS立刻降到0.15。

这个经验后面变成了标准流程:先粗标定,再逐图误差分析,剔除异常图再精标定一次。别想着一把过,标定本身就是迭代活。

附一个逐图误差计算的代码片段:

def per_image_error(obj_points, img_points, rvecs, tvecs, camera_matrix, dist_coeffs): errors = [] for i in range(len(obj_points)): proj_points, _ = cv2.projectPoints( obj_points[i], rvecs[i], tvecs[i], camera_matrix, dist_coeffs ) err = np.mean(np.linalg.norm(img_points[i].reshape(-1, 2) - proj_points.reshape(-1, 2), axis=1)) errors.append(err) return errors

4.3 不同场景要不要重新标定

很多人以为标定一次一劳永逸,实际上有几个硬性条件:

  • 拧过镜头就要重新标定。镜头焦距环、光圈环一旦变动,内参全变。工业镜头锁紧后一般不会动,但运输震动可能导致松动。
  • 换相机重新标定。甚至同型号不同个体也有细微差异,严格来说每台相机都有自己的内参。
  • 温度变化大的环境要留意。工业现场温度从-10°C到50°C,金属镜筒热胀冷缩会让内参漂移。高精度项目要考虑在工作温度下标定,甚至定期复标。

我见过一个仓储测量项目,相机装在升降机上,每天升降震动,半年后测量误差从1mm飘到5mm,最后排查发现是镜头松了,重新标定加镜头胶固定解决。标定是手段不是目的,维护好相机机械结构同样重要。

5. 标定结果在项目中的落地与扩展方向

5.1 内参标定和九点标定、手眼标定不是一回事

这个话题我每次在交流群里都得解释一遍。相机内参标定解决的是“像素坐标和相机坐标系下真实方向之间的关系”。而工程上经常听到的九点标定,解决的是“像素坐标和执行机构坐标(比如机械臂基座坐标)之间的仿射变换”。

九点标定通常在平面上进行:让机械臂带着针尖(或者用激光点)走9个已知位置,同时在图像里记录像素坐标,然后算一个3x3的仿射/透视变换矩阵。这个过程没有“相机内参”的概念,直接把像素坐标和机器人坐标之间建立映射。如果你的项目是平面抓取,相机垂直安装,九点标定确实够用。一旦相机倾斜安装,或者目标不在同一平面,九点标定就不灵了,这时候才需要走“内参标定 + solvePnP求位姿 + 手眼标定”的完整链路。

手眼标定则是求解相机坐标系和机械臂末端坐标系之间的固定变换,分eye-in-hand(相机装在机械臂末端)和eye-to-hand(相机固定在外界)两种。它依赖内参标定结果作为输入,属于外参层面的事。单目相机标定只是第一步,后面要做空间抓取,手眼标定绕不开。

5.2 从单目到双目:外参标定与深度恢复

单目相机标定完,只能得到像素对应的射线方向,没有深度信息。双目相机则通过左右两幅图像的视差恢复深度,这时的标定就要升级了:

  1. 先分别标定左右相机的内参和畸变。
  2. 再做双目立体标定,求解左右相机坐标系之间的旋转矩阵 (R) 和平移向量 (t)(也就是外参)。
  3. stereoRectify做极线校正,让左右图像行对齐。

OpenCV里有对应接口stereoCalibratestereoRectify,原理和单目标定一脉相承,只是把约束条件扩展到了双目之间的几何关系。从单目到双目的升级,最核心的就是把“单相机内参”这个地基打牢,否则后面立体匹配全是歪的。

如果你用zed这类自带出厂标定的双目相机,官方给的参数一般够用,但出厂标定是在特定温度和机械状态下做的,高精度场合建议自己重新标一遍。

5.3 和SLAM、视觉导航结合的典型用法

这几年视觉SLAM火,ORB-SLAMVINS-Mono这类开源方案里,相机内参都是第一道输入。SLAM系统初始化时要用内参把像素坐标反投影成归一化平面坐标,再进行特征三角化和位姿估计。内参偏一点,三角化出来的深度就偏一点,累积下去轨迹就飘了。

我实测过一个项目,用同一组图像,分别用校准过的内参和直接按厂商标称内参跑VINS-Mono,轨迹误差差了将近30%。厂商标称值只能作为初值参考,工程落地必须实测标定。

在视觉导航这个方向上,标定结果通常还要和IMU的外参联合标定(也就是热词里常见的imu雷达外参标定lidar imu标定这条路)。IMU给出加速度和角速度,相机给出视觉观测,两者融合需要知道相对位姿。这一块有现成工具如Kalibrlivox_camera_lidar_calibration,但前置条件都是相机内参已经标准了。基础不牢,上层融合全白搭。

顺带提一句,汽车电子圈说的“canoe标定canape标定”是ECU参数标定,和相机标定完全是两码事,别混为一谈。做视觉的人听到“标定”二字,先分清是哪一层:相机内参?手眼外参?还是传感器联合外参?对应的方法论和工具完全不同。

我个人现在的习惯是:新相机到手,先做一次完整标定,把参数存成json,在任何项目里都以这份参数为基准;隔三个月或仪器动过之后,重新花10分钟复标一次。标定这件事,投入产出比极高,十分钟换来的是一劳永逸的坐标可信度。希望这篇能把大家领进门,少走我当初走过的弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 23:47:40

16GB板载大模型:从量化到内存优化的完整实战

1. 一块16GB开发板&#xff0c;面对17.66GB的模型&#xff0c;第一个动作是什么我刚拿到任务时&#xff0c;对方把两张图发给我&#xff1a;一张是模型文件大小&#xff0c;17.66GB&#xff1b;一张是开发板参数&#xff0c;16GB内存。我的第一反应是“这怕不是要用内存卡当硬盘…

作者头像 李华
网站建设 2026/9/16 23:47:03

AVFoundation实战:从自定义相机到直播推流的完整指南

第一次在项目里接到“做一个能拍短视频的功能”这个需求时&#xff0c;我第一反应是直接拖一个UIImagePickerController上去。说实话&#xff0c;那会儿20分钟就能拍照、录视频&#xff0c;看起来效率很高。但产品需求一旦变成“录到12秒自动停、拍摄界面要自定义UI、直播要实时…

作者头像 李华
网站建设 2026/9/16 23:46:02

麒麟V10 ARM平台部署达梦数据库DM8实战指南

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

作者头像 李华
网站建设 2026/9/16 23:45:59

NAS、SAN、ISCSI到底啥区别?从文件级到块级存储的选型指南

打开购物网站搜“NAS”&#xff0c;能看到几百块的玩客云&#xff0c;也能看到上万块的群晖企业级&#xff1b;搜“SAN”&#xff0c;出来的基本是机柜、光纤线和一个让人不敢追问的价格&#xff1b;再搜“ISCSI”&#xff0c;大多文章写得太硬核&#xff0c;读三行就劝退。很多…

作者头像 李华
网站建设 2026/9/16 23:44:57

WinCC V7.5 SP1安装与服务器授权选型实战指南

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

作者头像 李华