news 2026/10/24 4:17:01

OpenCV+Python单目测距:标定、滤波与误差控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenCV+Python单目测距:标定、滤波与误差控制

简介:面向Python与计算机视觉初学者的测距实践项目,围绕OpenCV实现基于三角形相似度的单目相机测距:先利用已知物体的实际宽度及其在设定距离下的像素宽度求取焦距,再在新图像中检测同一标记物,根据其像素尺寸反推相机到物体的距离,适合课堂实验、视觉入门与小型测量原型验证。压缩包共2个文件,含1个Python主脚本与1份Markdown说明,整体约2KB,主脚本承担图像读取、标记检测、焦距计算和距离输出,说明文档交代依赖包、运行方式及图像列表初始化位置,便于按代码脉络理解算法实现。已有761人学习,可从中梳理焦距标定、标记物像素宽度提取与测距结果换算的关键环节,并参考参数设置和检测流程排查常见偏差。代码结构精简,算法实现与使用说明分置,适合先读说明再逐段调试,从而完成从标定到测距的闭环练习。

1. 一个摄像头的测距上限:先把「能测多准」问清楚

装一只普通 USB 摄像头,问它前面那个人离镜头几米——答案覆盖几厘米到两米的范围,而非简单的「行」或「不行」:3 米内误差能压到几厘米,8 米内还能守在 ±0.3 米,20 米外读数飘 ±2 米都不稀奇。这套基于 OpenCV 和 Python 的单目测距实现,做的就是把这条劣化曲线尽量往下压:针孔模型负责把像素尺寸翻译成物理距离,棋盘格标定把焦距钉死,检测框高度代替宽度去抵抗目标姿态变化,卡尔曼滤波再把逐帧抖动磨平。它适合机器人避障、货位测距、前向碰撞预警的原型验证,也适合当视觉课程的动手案例;不适合拿去替代激光雷达做安全冗余。读下去你会知道参数怎么给、误差从哪来、哪一步最容易翻车。

2. 针孔模型与内参标定:焦距、真实尺寸、像素三者怎么咬合

单目测距的整套推算,本质上只有一个公式在反复变形。把这一步吃透,后面所有代码都只是给它套上工程外壳。

2.1 相似三角形的推导与误差传递

针孔模型下,物体在成像平面上的像素宽度w、物体真实宽度W、镜头焦距f(单位是像素,不是毫米)、物体到光心的距离Z,满足:

w / f = W / Z => Z = f * W / w

推导很朴素:真实世界里的宽度W投影到焦平面上按f / Z的比例缩小。这里有个初学者最容易栽的点——f必须是像素单位。相机标定给出的内参矩阵里fx、fy就是这个量,物理焦距(毫米)除以像元尺寸(毫米/像素)才得到它。

对公式两边取对数再微分,相对误差是可加的:

dZ / Z = dW / W + dw / w

这条式子决定了方案的精度上限。真实尺寸W只要查表,误差能控制在 3% 以内;但dw / w会随目标变远急剧恶化。取f = 800 px、W = 1.8 m(普通轿车车宽),Z = 1440 / w:

像素宽度 w估算距离 Z每变化 1 px 引起的距离变化
180 px8.0 m0.04 m
90 px16.0 m0.18 m
60 px24.0 m0.39 m
36 px40.0 m1.08 m

看出来了吗,40 米处框宽抖一个像素,读数就跳一米。所以这套方案在工程上的合理区间通常是 1~15 米,超过这个范围要么换长焦、要么换双目或深度相机。我会在代码里直接加一条「最小像素阈值」,低于阈值不输出距离,宁可没有读数也别给错读数。

2.2 用棋盘格标定拿内参

不标定直接用厂商给的视场角反算焦距,是一条血泪经验铺成的歪路。同一型号的摄像头,镜头装配公差能让实际焦距差 5%,投到 10 米外就是半米误差。老实标一次,十分钟的事。

准备一张棋盘格(内角点数建议 9×6),用待标定的相机在 0.4~3 米范围内拍 20~30 张不同角度、不同位置的图,覆盖画面四角和中心。

import glob import cv2 import numpy as np # 棋盘格内角点数量(列, 行):数的是黑白格交点的个数,不是格子数 PATTERN = (9, 6) SQUARE_SIZE = 0.025 # 单格实际边长,单位米,用尺子量 objp = np.zeros((PATTERN[0] * PATTERN[1], 3), np.float32) objp[:, :2] = np.mgrid[0:PATTERN[0], 0:PATTERN[1]].T.reshape(-1, 2) * SQUARE_SIZE obj_points, img_points, shape = [], [], None for path in sorted(glob.glob("calib/*.jpg")): img = cv2.imread(path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ok, corners = cv2.findChessboardCorners(gray, PATTERN, None) if not ok: print("角点没找到,丢弃:", path) continue # 亚像素精修,这一步能把角点定位从 ±0.5 px 提到 ±0.1 px corners = cv2.cornerSubPix( gray, corners, (11, 11), (-1, -1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)) obj_points.append(objp) img_points.append(corners) shape = gray.shape[::-1] rms, K, dist, _, _ = cv2.calibrateCamera(obj_points, img_points, shape, None, None) print("重投影 RMS 误差: %.4f px" % rms) print("fx=%.2f fy=%.2f cx=%.2f cy=%.2f" % (K[0, 0], K[1, 1], K[0, 2], K[1, 2])) np.save("K.npy", K) np.save("dist.npy", dist)

几个参数值得说明。PATTERN数错了,findChessboardCorners会一直返回 False,这是最高频的翻车点,8×6 的格子对应的是 7×5 个内角点。SQUARE_SIZE用米,整条链路就统一在米制下,别中途换厘米。rms是重投影误差,低于 0.5 px 属正常,超过 1 px 说明有模糊图或者拍得太斜,回去挑图。标定完把K、dist存成文件,线上运行直接加载,别每帧都算。

顺带说一句,dist(畸变系数)在某些场景下必须用:广角镜头边缘的画面拉伸会让框宽虚高,换算出来的距离系统性偏近。水平视场角超过 90 度的镜头,建议先cv2.undistort再进测距流程。

2.3 没有标定板时的两点标定法

现场没有棋盘格,也有退路。把f和W合成一个未知量k = f * W,于是Z = k / w。找一个尺寸已知的物体(比如一个身高 1.7 米的人),让他在两个确切的距离上各站一次,量出像素高度,就能反解k。

import numpy as np def fit_k(samples): """samples: [(卷尺实测距离 m, 该距离下的像素高度 px), ...],至少两组""" d = np.array([s[0] for s in samples], dtype=np.float64) w = np.array([s[1] for s in samples], dtype=np.float64) # Z = k / w => k = Z * w;多组取均值即为最小二乘解 k = float(np.mean(d * w)) resid = d - k / w # 逐点残差,正数代表估远了 return k, resid k, resid = fit_k([(3.0, 462), (6.0, 228), (9.0, 156)]) print("有效焦距-尺寸积 k = %.1f" % k) print("逐点残差(米):", np.round(resid, 3))

这个做法的好处是把「焦距标定误差」和「目标真实尺寸误差」合并成一个系数,反而更贴合实际场景——因为很多时候你要测的不是抽象物体,而是固定那一类目标。坏处是k跟分辨率、跟目标类别强绑定,换相机、换类别都得重标。残差那行别偷懒不打,如果三组点的残差符号一致(比如全是正的),说明你量的像素高度有系统性偏差,多半是框把脚尖或头顶切掉了。

3. 从检测框到米:OpenCV 测距流水线的落地写法

有了内参,剩下的活是把「检测框」这个二维矩形变成一维的距离数字。这一步的工程细节比公式本身多得多。

3.1 选高度还是选宽度:bbox 的四个几何约定

同样是框,用宽还是用高,结果能差一倍。我一般遵循四条约定:

第一,优先用高度。行人侧身走的时候宽度能缩一半,高度只受姿态影响,站直和走路差别在 5% 以内。车辆也是同理,正面对着你时宽度是真的,斜着开就虚了。

第二,框必须贴合。检测器输出的框通常带一点余量,尤其是底部——脚部和地面阴影容易被框进去,导致高度虚高、距离估近。可以对底部做几像素的收缩补偿,或者干脆用「框底中点」作为接地点配合地面假设,这一招在第 4 章会详细写。

第三,被画面边缘截断的框一律丢弃。目标走出画面时框高只剩一半,算出来的距离会直接翻倍。判断方式很简单:x1 <= 1或y2 >= H - 1就认为贴边。

第四,宽高比做一次合法性校验。人对车、车对人,宽高比是明显异常的,一个h/w < 1.2的「行人」多半是两个人黏在一起或者框错了,这种数据进滤波器只会污染状态。

3.2 完整可运行代码:视频流到距离输出

下面这段是能直接跑的骨架,检测器部分留成接口,用现成的单阶段检测模型接进去就行。

import cv2 import numpy as np K = np.load("K.npy") fx, fy = float(K[0, 0]), float(K[1, 1]) cx, cy = float(K[0, 2]), float(K[1, 2]) # 类别 -> (真实宽度 m, 真实高度 m);拿不准的量三次取中位数 REAL_SIZE = { "person": (0.50, 1.70), "car": (1.80, 1.50), "truck": (2.40, 3.00), } MIN_PX = 28 # 像素高度低于此值不输出距离 MAX_RATIO_DIFF = 0.30 # 高估与宽估偏差超过 30% 视为框不可信 def make_kalman(): kf = cv2.KalmanFilter(2, 1) # 状态 [距离, 距离变化率] kf.transitionMatrix = np.array([[1, 1], [0, 1]], np.float32) kf.measurementMatrix = np.array([[1, 0]], np.float32) kf.processNoiseCov = np.eye(2, dtype=np.float32) * 1e-2 kf.measurementNoiseCov = np.eye(1, dtype=np.float32) * 2e-1 kf.errorCovPost = np.eye(2, dtype=np.float32) return kf def estimate(box, cls, kf, frame_w, frame_h): x1, y1, x2, y2 = box if x1 <= 1 or y1 <= 1 or x2 >= frame_w - 1 or y2 >= frame_h - 1: return None # 贴边,直接放弃 h_px, w_px = y2 - y1, x2 - x1 if h_px < MIN_PX or w_px < 1: return None # 太小,误差不可控 real_w, real_h = REAL_SIZE[cls] z_h = fy * real_h / h_px # 按高度估 z_w = fx * real_w / w_px # 按宽度估 if abs(z_h - z_w) / max(z_h, z_w) > MAX_RATIO_DIFF: return None # 两个估计打架,丢弃 z_meas = 0.5 * (z_h + z_w) kf.predict() state = kf.correct(np.array([[z_meas]], np.float32)) return float(state[0]), z_meas def run(video_path, detector): cap = cv2.VideoCapture(video_path) kfs = {} while True: ok, frame = cap.read() if not ok: break H, W = frame.shape[:2] for tid, (box, cls) in enumerate(detector(frame)): kf = kfs.setdefault(tid, make_kalman()) out = estimate(box, cls, kf, W, H) if out is None: continue z_smooth, z_raw = out x1, y1, x2, y2 = map(int, box) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, "%.2fm" % z_smooth, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow("mono-depth", frame) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()

逻辑上分三层。第一层是几何有效性筛选:贴边、过小、宽高比异常的框在进入数学运算之前就被踢掉,这比事后调滤波参数管用得多。第二层是双通道估计:z_h和z_w独立算,两者一致才采信,不一致说明框有问题,这一步挡住了绝大多数离谱读数。第三层是卡尔曼平滑,状态取[距离, 距离变化率],转移矩阵用匀速模型,实测在 25~30 fps 下跟踪行人是够用的。

参数上,processNoiseCov调大意味着更信任观测、响应快但抖;调小则更平滑但滞后。行人场景我一般给1e-2,车辆因为运动快,会给到5e-2。measurementNoiseCov反映的是测量噪声方差,按经验,距离在 5 米左右时观测噪声标准差约 0.3~0.5 米,方差就是 0.1~0.25,所以给2e-1是个合理起点。

3.3 真实尺寸表与误差预算

真实尺寸是这个方案里最容易被轻视的输入。同一个类别,不同样本差异巨大:成年人身高 1.55~1.90 米,直接取 1.70 就意味着 ±9% 的固有误差。所以更靠谱的做法是按场景细分——校园场景取 1.65,工地场景取 1.75——而不是一个数字打天下。

目标参考尺寸常见波动折算 8 米处误差
成年行人(高)1.70 m±0.10 m±0.47 m
轿车(宽)1.80 m±0.10 m±0.44 m
轿车(高)1.50 m±0.15 m±0.80 m
快递纸箱(高)0.30 m±0.05 m±1.33 m

从表里能读出一个反直觉的结论:小目标不适合用这套方法。30 厘米的箱子,光尺寸波动就能带来 17% 的误差,再加上像素量化误差,基本没有实用价值。要做小目标测距,得换成结构光或者带深度的方案。

4. 俯仰角与地面假设:把斜视场景的误差压下来

绝大多数实际部署里,相机不是水平放置的——监控杆上俯拍、车顶略微下倾、机器人头部前倾。这时候纯针孔公式会给出系统性偏小的读数,而且偏得很有规律,反而是好事,能补。

4.1 地平线、俯仰角与距离的三角关系

相机下俯 θ 角、光心离地高度H、目标接地点像素行v,则目标到相机的地面投影距离为:

α = arctan((v - cy) / fy) # 接地点相对光轴的下视角 Z = H / tan(θ + α)

当θ = 0(相机水平)时退化成Z = fy * H / (v - cy),这就是经典的「地平线法」。v - cy越大,目标越靠画面下方,距离越近。

import numpy as np def ground_distance(v_bottom, cam_h, fy, cy, pitch_deg): """v_bottom 目标接地点像素行;cam_h 光心离地高度(m);pitch_deg 下俯角(向下为正)""" alpha = np.arctan2(v_bottom - cy, fy) theta = np.deg2rad(pitch_deg) denom = np.tan(theta + alpha) if denom <= 1e-3: return float("inf") # 逼近地平线,数值发散,返回无效值 return cam_h / denom # 同一个接地点,不同俯仰角下的读数差异 for p in (0, 3, 5, 10): print("俯仰 %2d 度 -> %.2f m" % (p, ground_distance(v_bottom=520, cam_h=1.2, fy=800, cy=360, pitch_deg=p)))

v_bottom = 520、cy = 360时,水平安装读到 4.50 米,下俯 5 度只有 3.15 米,差 30%。所以只要相机不是严格水平,这条补偿就必须加。「大概水平」这种判断不能代替实测,我见过支架标称 0 度、实测偏 4 度的情况。

这个方法的另一个价值是不依赖目标真实尺寸——只要目标贴地,H和θ标定准,一米八的人和一米六的人算出来的距离是一样的。代价是必须有稳定的接地点,悬空目标(比如举起的手)就失效了。

4.2 在线自标定:用已知地面点反解俯仰角

H能用卷尺量,θ却很难量准。现在有了地面模型的公式,反过来用几个已知距离的地面标记点,就能把H和θ一起解出来。

import numpy as np from scipy.optimize import least_squares def fit_ground(v_px, z_true, fy, cy, h0=1.2, pitch0=0.0): """v_px/z_true: 地面上若干标记点的像素行与卷尺实测距离""" v = np.asarray(v_px, dtype=np.float64) z = np.asarray(z_true, dtype=np.float64) def resid(p): h, th = p alpha = np.arctan2(v - cy, fy) pred = h / np.tan(np.deg2rad(th) + alpha) return (pred - z) / z # 按相对误差加权,避免远点主导 r = least_squares(resid, x0=[h0, pitch0], bounds=([0.2, -30], [6.0, 60])) return r.x, float(np.sqrt(np.mean(r.fun ** 2))) (h_hat, pitch_hat), rms = fit_ground( v_px=[300, 380, 440, 500, 545], z_true=[15.0, 8.0, 5.0, 3.0, 2.0], fy=800, cy=360) print("拟合得到 H=%.3f m, pitch=%.2f 度, 相对残差=%.3f" % (h_hat, pitch_hat, rms))

残差用(pred - z) / z而不是pred - z,是因为远点的绝对误差天然大,不归一化的话拟合会被 15 米那个点带跑偏,近处反而失准。相对残差低于 0.03 就可以认为模型成立;高于 0.08 一般是标记点没取准,尤其近处 2 米那个点,接地点差几个像素影响很大。约束里把θ的下界放到 -30 度,是为了兼容相机略微上仰的安装方式,别把范围写死成非负。

标定完之后,把H、θ写进配置,运行时只做一次三角函数运算,开销可以忽略。相机被碰过、支架被撞过,都得重标——这是这套方法最脆弱的地方。

4.3 多帧一致性:中位数加四分位剔除

卡尔曼滤波能压噪声,但压不住离群点。一个框突然被检测成两个人,观测值翻倍,滤波器要好几帧才能拉回来,屏幕上就是一个明显的跳变。工程上更省事的做法是先做一次鲁棒统计,再喂给滤波器。

from collections import deque import numpy as np class StableDepth: def __init__(self, n=9, k=1.5): self.buf = deque(maxlen=n) self.k = k def push(self, z): self.buf.append(float(z)) if len(self.buf) < 3: return float(z) arr = np.asarray(self.buf) q1, q3 = np.percentile(arr, [25, 75]) iqr = q3 - q1 lo, hi = q1 - self.k * iqr, q3 + self.k * iqr keep = arr[(arr >= lo) & (arr <= hi)] return float(np.median(keep)) if keep.size else float(np.median(arr))

窗口n = 9大约对应 0.3 秒的历史,够滤掉单帧跳变又不至于让跟车距离滞后太多。k = 1.5是标准的 Tukey 围栏系数,想更激进就调到 1.0,想保守就 2.0。注意 IQR 在小样本下不稳,所以len < 3时直接返回原始值,别硬套。这个类按目标 ID 各持一个实例,别全局共用一个,否则两个目标的距离会互相污染。

5. 排查清单:五个让读数飘出 20% 的现场问题

下面这些不是理论上的可能性,是我在实际调试中反复撞见的。

5.1 近处很稳,十米外上下跳 ±1.5 米

现象:5 米内读数稳定在 ±0.1 米,走到 10 米,数字开始来回跳,幅度超过一米。

原因:框高掉到 40 px 以下,检测器在远距离的框回归本身就不稳,±2 px 抖动折算成距离就是 5% 以上;再加上前面算过的,dZ/Z与dw/w成正比,分母小了误差自然放大。

解决:设最小像素阈值,h_px < 28直接不显示数字,只画框;同时按距离分段调平滑窗口,近处用短窗保持响应,远处用长窗(n = 15)压抖动。如果业务上必须测 20 米,换更长焦距的镜头比调代码有用得多。

5.2 行人一转身,距离突然变大一半

现象:同一个人正面走过来读数 6 米,侧身走过变成 9 米。

原因:用了框宽做估计。人的肩宽 0.5 米、侧身厚度 0.25 米,差一倍,w_px减半,Z就翻倍。

解决:改成以高度为主,宽度只做一致性校验;对车辆同样适用,因为车宽受朝向影响大,车高相对稳定。如果业务必须用宽度(比如从正上方俯拍),那就得先做朝向估计,按朝向查不同的尺寸表。

5.3 画面边缘的目标总是偏近

现象:目标在画面中央时读数正常,移到左右边缘,距离系统性偏小 10% 左右。

原因:广角镜头的桶形畸变让边缘的物体被「推远」,看起来比实际小,根据Z = fW/w,w小了距离就大了——但如果只做了部分畸变校正、或者校正后仍用原始cx, cy,结果会反过来偏近。两种错误都很常见。

解决:测距前统一走一遍cv2.undistort(frame, K, dist),并且内参必须用同一套标定结果,别一半用标定值一半用默认值。校正后图像的有效区域会缩小,cx, cy仍然是校正后的主点,不要手动改。

5.4 换了分辨率,所有距离全错

现象:调试用 1280×720 一切正常,切到 640×480 后距离全部偏大或偏小,比例大概是 2 倍。

原因:内参矩阵和分辨率强绑定。fx、fy、cx、cy的单位都是像素,图像缩放一半,它们全都要减半。

解决:按比例缩放,而不是重标。比例系数s = W_new / W_old:

import numpy as np def rescale_K(K, sx, sy): K2 = K.copy().astype(np.float64) K2[0, 0] *= sx # fx K2[1, 1] *= sy # fy K2[0, 2] *= sx # cx K2[1, 2] *= sy # cy return K2 K = np.load("K.npy") K_half = rescale_K(K, 0.5, 0.5) # 1280x720 -> 640x360

注意sx和sy要分别算,非等比缩放(比如 1280×720 裁成 640×480 再缩放)会让fx、fy不再相等,用同一个系数就错了。裁剪的情况更麻烦,cx、cy还得减去裁剪偏移,这种场景我一般直接重新标定,省事也不容易错。

5.5 相机被碰了一下,远处全偏

现象:设备运行几天都正常,某天开始 10 米外的读数普遍偏小 15%,近处几乎看不出来。

原因:支架松动,相机下俯角变了 2~3 度。俯仰角误差对远处的影响远大于近处,这正是第 4 章那个三角公式的直接后果。

解决:加一个自检机制。在场景里找一个已知距离的固定参照物(地面标线、墙角),每帧算一次距离,与实际值偏差超过 8% 就报警并要求重标。别指望人工巡检能发现这种缓慢漂移,我在一个长期运行的场景里就是靠这个自检抓到支架螺丝松动的。

6. 精度验收:用一套可复用的测试流程给结果签字

代码跑通不等于能用,得拿数据说话。我现在的习惯是:任何测距方案上线前,先做一轮固定流程的验收。

流程很土但有效。在平整地面上用卷尺量出 1、2、3、5、8、10、15、20 米,每个位置放一个目标,静态采集 50 帧,动态再让目标匀速走过一遍。把结果按真值分组,算均值、标准差、平均绝对误差和相对误差。

import csv import numpy as np def load(path): """CSV 两列:gt(卷尺真值), measured(算法输出),一行一次测量""" buckets = {} with open(path, newline="") as f: for row in csv.DictReader(f): buckets.setdefault(float(row["gt"]), []).append(float(row["measured"])) return buckets def report(buckets): rows = [] for gt in sorted(buckets): arr = np.asarray(buckets[gt], dtype=np.float64) mae = float(np.mean(np.abs(arr - gt))) rows.append({ "gt": gt, "n": arr.size, "mean": round(float(arr.mean()), 2), "std": round(float(arr.std()), 2), "mae": round(mae, 2), "rel_%": round(mae / gt * 100, 1), }) return rows for r in report(load("depth_log.csv")): print(r)

得到的表长这样(某次车载前向场景的实测):

真值均值标准差MAE相对误差
2 m2.060.050.073.5%
5 m4.880.140.163.2%
10 m10.420.380.454.5%
15 m15.911.021.057.0%
20 m21.832.102.0510.3%

读这张表有三个要点。第一看标准差,它反映抖动,比均值更重要——均值偏了还能加偏置补偿,抖动没法补。第二看相对误差随距离的增长斜率,如果 10 米以后陡增,说明像素分辨率到极限了,该换镜头。第三看mean - gt的符号是否一致,全是正数说明有系统性偏置,多半是真实尺寸表填大了一点,把这个偏差整体减掉就能改善一截。

验收标准我一般定成:可用区间内相对误差 < 5%、标准差 < 0.3 米,超出这个区间就在界面上做视觉降级(比如不再显示精确数值,只显示「远/中/近」三档)。这不是偷懒,是承认方法的边界。

最后提一个容易忽略的点:验收要在真实光照下做。夜间、逆光、雨天的检测框质量会明显下降,白天调好的参数到晚上可能差一倍。我的做法是至少采集白天、黄昏、夜间三组数据,分别给出可用区间。

从那以后我每次接单目测距的活,都会先花半天把标定和验收跑完,哪怕业务方催着要 Demo——因为跳过这一步省下的时间,后面会以三倍的调试成本还回来。这套东西的门槛不在代码,而在你愿不愿意老老实实量那几组数据。希望帮到你。

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

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

本周学习内容:分支与循环语句

1.if语句1.1语法形式&#xff1a;if&#xff08;表达式&#xff09;{语句}当表达式为真时&#xff0c;语句执行&#xff0c;为假时不执行&#xff08;0为假 非0为真&#xff09;1.2 elseif&#xff08;表达式&#xff09;{语句1}else {语句2}1.3多条语句if和else默认只控制下面…

作者头像 李华
网站建设 2026/10/24 4:14:06

第四章 数据采集及存储

4.1 数据采集概述数据采集&#xff08;Data Collection&#xff09;就是把外部数据&#xff08;网页、API、文件、数据库&#xff09;取到本地。最常见、最适合入门的就是网页爬虫&#xff0c;通常分三步&#xff1a;请求&#xff1a;用 HTTP 把网页源码下载下来&#xff1b;解…

作者头像 李华
网站建设 2026/10/24 4:14:06

东方博宜OJ 4989:学习小组 ← 完全背包

【题目来源】 https://oj.czos.cn/p/4989 【题目描述】 班主任计划将班级里的 n 名同学划分为若干个学习小组&#xff0c;每名同学都需要分入某一个学习小组中。观察发现&#xff0c;如果一个学习小组中恰好包含 k 名同学&#xff0c;则该学习小组的讨论积极度为 ak。 给定讨论…

作者头像 李华
网站建设 2026/10/24 4:13:59

力扣hot100——找到字符串中所有字母异位词

一、题目给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。示例 1:输入: s "cbaebabacd", p "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 &q…

作者头像 李华