☰
基于OpenCV改进Hough与轮廓匹配的红外瞳孔直径检测
2026/11/3 2:57:39 网站建设 项目流程

简介:这是一份面向图像处理与计算机视觉研究人员、工程师的红外视频瞳孔检测算法资料,聚焦低精度瞳孔直径检测问题,适用于心理健康研究、犯罪侦查与医疗诊断等场景。压缩包仅含1个PDF文件,约1.04MB,为论文全文,便于直接查阅算法原理、实验设置与结果。已有170人学习。内容围绕Hough-Contour方法展开:先对每帧灰度化与滤波去噪,再以改进Hough梯度法初检瞳孔,并在瞳孔附近做圆形轮廓匹配以精确定位中心与直径;文中还讨论候选圆心累积值搜索、闭眼帧排除及轮廓移动范围、点对数等参数设置。实验给出低端设备320×240、高端设备640×480的实时表现与99.8%精确匹配率,可供复现与调参参考。

1. 为什么直接调 HoughCircles,瞳孔直径的命中率只有一成

红外视频瞳孔检测这件事,难的不是“找到一个圆”,而是“这个圆的直径可信”。我拿同一段 320×240 的红外眼视频直接喂 OpenCV 的HoughCircles,能稳定出圆的比例大概只有一成,直径抖动经常到 ±6 像素,闭眼帧还会平白无故冒出一堆假圆。根子在于 Hough 的参数空间是离散格点,累加器峰值给的是一小片候选区域,不是亚像素中心;而红外图里角膜反光、睫毛、眼睑边缘和瞳孔缘在梯度幅值上是同一量级的,谁都在抢票。这套 2016 年公开的 Hough-Contour 思路把活儿拆成两段:改进 Hough 梯度法先给一个粗圆,再在粗圆附近用圆轮廓匹配把中心和直径掰回来,位移与伸缩压到初圆半径的 1/10,40 个点对做径向差分,直径精度从 10% 拉到 99.8%,320×240 在低端机上 60 ms 一帧。下面按能跑起来的顺序拆。

2. 算法骨架:灰度、Canny 与改进 Hough 梯度法怎么把初圆圈出来

红外摄像头出来的画面本质上是单通道强度图,可一旦编码进 AVI 或 MP4,落到 OpenCV 里就是三通道 BGR。很多人图省事直接把彩色帧丢给HoughCircles,结果每个边缘点被三个通道各投一次票,累加器里全是重复计数,param2的物理含义彻底乱掉,调参就成了玄学。所以第一步永远是把链路收敛到单通道,再谈滤波和边缘。

2.1 为什么是 5×5 均值滤波,而不是高斯

瞳孔与虹膜的交界是一条灰度阶跃,空间尺度只有 1~2 个像素。高斯核在 σ 稍大时会把这条阶跃抹成一条斜坡,Sobel 求出来的梯度幅值随 σ 增大迅速衰减,瞳孔上沿那些本来就被眼睑压弱的边缘点直接投不进累加器,表现出来就是“圆只有下半圈”。均值滤波对阶跃的保留要好得多,同等窗口下边缘的过零点位置基本不漂。OpenCV 的cv::blur是分离式实现,5×5 的代价在 320×240 上几乎测不出来。

窗口再往上加就有代价了。7×7 确实能压掉一批角膜反光的高频噪点,但瞳孔边缘也开始糊,尤其当瞳孔直径只有 20 多个像素时,7×7 窗口已经占到直径的三分之一,边缘位置会被邻域的亮像素拉偏。原文实验里定的是 5×5,我复现时在几段不同的红外视频上试过 3×3、5×5、7×7,5×5 在“噪点抑制”和“边缘保真”之间确实是最稳的那个点。这里补一句边界条件:如果原始视频压缩比很高、块效应明显,先做一次 3×3 中值滤波再上 5×5 均值,比单纯放大均值窗口有效。

滤波之后的图要留两份:一份是滤波图,给 Hough 和轮廓匹配用;一份是原始灰度图,只在需要回看对比度时用。别拿滤波图去做最终的灰度差分打分又拿原始图做边缘,两套数据混着用,后面排查问题时根本对不上账。

2.2 梯度法投票:只让边缘点沿自己的法线投一票

标准 Hough 圆变换让每个边缘点在 a-b-r 三维参数空间里整片投票,一帧 320×240 的红外图边缘点动辄上万,三维累加器的内存和耗时都撑不住。梯度法换了思路:圆心的方向必然在该点梯度方向(法线)上,所以每个边缘点只沿法线投一条射线,半径由“候选圆心到该边缘点的距离”反算,投票量从 O(边缘点 × 半径档数) 降到 O(边缘点)。

OpenCV 里这个实现藏在HOUGH_GRADIENT模式后面,早期版本内部函数叫icvHoughGradient。它的参数不多,但每一个都直接影响能不能出圆:

// 粗定位:Hough 梯度法出初圆,参数按 320x240 红外眼视频标定 // gray 为 CV_8UC1,已完成 5x5 均值滤波 bool coarsePupil(const cv::Mat& gray, cv::Point& c0, int& r0) { std::vector<cv::Vec3f> circles; cv::HoughCircles(gray, circles, cv::HOUGH_GRADIENT, 1, // dp=1:累加器与图像同分辨率,保圆心精度 gray.cols / 4, // minDist:两候选圆最小间距,防止同一瞳孔出多个峰 100, // param1:Canny 高阈值,低阈值内部自动取一半=50 30, // param2:累加器阈值,越小越容易出假圆 12, 25); // minRadius/maxRadius:320x240 下的瞳孔半径带 if (circles.empty()) return false; // 闭眼帧或严重失焦帧在这里被挡掉 c0 = cv::Point(cvRound(circles[0][0]), cvRound(circles[0][1])); r0 = cvRound(circles[0][2]); return true; }

dp=1这一项不要为了提速改成 2。dp=2 意味着累加器分辨率只有图像的一半,圆心误差直接按 2 像素起步,而后面轮廓匹配的搜索半径 d 在 r0=20 时只有 2 像素,初圆误差一旦吃掉整个搜索窗,精修就变成了在错的盆地里找最优。

Canny 的 100/50 也不是随手写的数。红外图整体偏暗,瞳孔区灰度常在 30~60,虹膜 90~140,100 作高阈值刚好卡在两者之间;低阈值 50 是为了保住瞳孔上沿被眼睑遮挡的那段弱边缘,这段边缘丢了,累加器峰值会往下方偏,圆心系统性下移 2~3 像素。

半径区间给太宽是新手最常见的失误。320×240 的帧里瞳孔半径大约 12~22 像素,你把 maxRadius 开到 60,累加器里就会同时出现虹膜外圈、镜片反光、甚至眼镜框的假峰,而 Hough 只返回累积值最高的那个,未必是瞳孔。半径上下限的正确来源是先用几帧人工量一下,然后各留 20% 余量。

2.3 把“按累积值降序排序”换成“取最大值”

这是原文里最实在的一处工程改动。传统实现会把所有候选圆心按累积值降序排序,再逐个反算半径、逐个过阈值判定,取第一个通过的。排序是 O(n log n),一帧里候选点几千个,纯排序就占掉相当一部分时间,而真正被用到的永远只有头部那一两个。

改成一次遍历记录最大值及下标,复杂度降到 O(n),半径也只对这唯一的圆心算一次。代价是丢掉了备选信息:最优点如果被角膜反光污染,没有第二候选可以退。所以这个改动必须和阈值判定绑在一起用——累积最大值低于阈值就直接判本帧无效(多为闭眼帧),压根不进后续匹配,而不是硬着头皮往下走。

OpenCV 4.x 的HoughCircles内部已经做了排序并按累积值返回,要完全复刻这个 O(n) 改动,得把icvHoughGradient那段逻辑抠出来自己改,或者退一步:把param2提到 40~50 让候选集本身变小,排序开销自然就下来了。两条路我都试过,后者的代码量小得多,代价是对比度偏低的帧容易漏检,需要配合下一节的阈值策略。

2.4 闭眼帧的阈值该定在哪

闭眼帧是这类系统里最烦的东西:眼皮的褶皱、睫毛根部在 Hough 看来也是一圈弧,照样能凑出一个“圆”,只不过累积值明显偏低。原文的做法就是拿这个累积最大值当判别量,低于阈值直接判闭眼。

阈值不能拍脑袋定。我的做法是录一段包含睁眼、眨眼、闭眼三种状态的视频,把每帧的累积最大值打出来,画个直方图,你会看到明显的双峰:睁眼帧集中在高位,闭眼帧挤在低位,中间那段谷底就是阈值位。320×240、Canny 100/50、param2=30 这套参数下,我这边量出来的分界大概在累加值的 40% 分位附近,换设备、换光照必须重标。不要把这个数字写死在代码里,做成配置文件项,换一段视频先跑一遍直方图。

3. 轮廓匹配:以 1/10 半径做局部搜索,用 40 个点对的径向差分定中心

粗定位给的圆,圆心误差通常 1~3 像素,半径误差 2~4 像素。对“瞳孔在不在”这种判断够用,对“瞳孔直径是多少毫米”完全不够。轮廓匹配要干的事就是在粗圆附近做一次局部穷举,把 (x, y, r) 三个量一起精修。

3.1 点对怎么取:±1 像素的径向差分

核心打分函数非常朴素。给定候选圆心 (x, y) 和半径 r,沿着 k 个角度 θ 均匀采样,每个角度上取两个点:

p1 = (x + (r-1)·cosθ, y + (r-1)·sinθ) // 圆内侧 1 像素 p1' = (x + (r+1)·cosθ, y + (r+1)·sinθ) // 圆外侧 1 像素 score = (1/n) · Σ [ f(p1') - f(p1) ]

f是滤波后的灰度值。瞳孔是暗的,虹膜是亮的,所以跨过真实边界时外侧减内侧的差值是正的且最大。这个打分本质上是径向梯度,只是用差分代替了求导,避开了 Sobel 核在边界上的平滑。

为什么是 ±1 而不是 ±2、±3:瞳孔边界是暗到亮的阶跃,过渡带宽度大约 2 像素,±1 的差分正好完整跨过这条过渡带,取到最大对比度。取 ±3 时外圈点已经落进虹膜纹理区,内圈点落进瞳孔内部的噪点上,差值被两头稀释,峰值反而变平——搜索曲面的峰一平,亚像素精度就没了。

k 取 40,对应 θ 步长 9°。这个数也有讲究:k 太小(比如 12,步长 30°)时圆弧采样太稀,一旦睫毛遮挡了某一段 60° 的扇区,有效点对占比骤降,得分随机性变大;k 太大则单次匹配的计算量线性上涨,而精度在 40 附近已经饱和。原文给过一组对照,k=30 时精度 99.0%,k=40 时 99.8%,再往上加收益极小。

3.2 三重循环的搜索空间:为什么 d 必须压到 r0/10

搜索范围是 r ∈ [r0-d, r0+d]、x ∈ [x0-d, x0+d]、y ∈ [y0-d, y0+d],原文把 d 定为初圆半径的 1/10。r0=20 时 d=2,搜索量是 5³=125 个候选圆,每个候选圆 40 个点对,一共 5000 次双点采样,在一帧里完全可以接受。

这里的反直觉点在于:搜索范围不是越大越好。把 d 放大到 r0/2,搜索量涨 125 倍不说,精度还会下降。原因是虹膜外缘的灰度对比度往往比瞳孔缘更强,搜索空间一放开,“更大半径 + 偏移中心”的组合就能拿到比真解更高的差分均值,优化过程直接跳到虹膜外圈去了。这是个典型的“模型假设与数据不匹配”问题——打分函数只认对比度,不认解剖结构,所以只能靠搜索范围把它约束在瞳孔附近。

同理,d 也不能压到 1 像素。粗定位的圆心误差本身就有 2~3 像素,d=1 时真解根本不在搜索窗里,精修只会把误差坐实。r0/10 这个比例在 320×240 上对应 d=2,在 640×480 上对应 d=4,正好覆盖粗定位误差的量级,是个跟着分辨率自适应的经验值。

3.3 归一化与有效点对计数

边缘帧(瞳孔靠近画面左/右边界)会有一部分采样点落到图像外。这部分点必须剔除,而且得分要除以有效点对数 n,而不是固定除以 40。不归一化的话,贴边帧的得分系统性偏低,会被闭眼阈值误杀,表现出来就是“人往边上看的时候检测就丢了”。

另一个细节是有效点对数的下限。原文里有个 200 的约束(pointPairsCount ≤ 200),实际作用更像一道健全性检查:如果有效点对占比太低,说明这个候选圆大部分落在画面外或者被严重遮挡,直接跳过,不要参与最优值竞争,避免极小样本的偶然高分污染结果。

def refine_pupil(gray, cx, cy, r0, k=40, ratio=0.1, min_valid=0.6): """在初圆附近做圆轮廓匹配,返回 (score, x, y, r)""" import numpy as np d = max(1, int(round(r0 * ratio))) # 搜索半径 = 初圆半径的 1/10 thetas = np.arange(0.0, 2 * np.pi, 2 * np.pi / k) # k=40 -> 步长 9 度 cos_t, sin_t = np.cos(thetas), np.sin(thetas) h, w = gray.shape best_score, best = -1e9, (cx, cy, r0) for r in range(r0 - d, r0 + d + 1): # 半径 if r < 2: continue for x in range(cx - d, cx + d + 1): # 圆心 x for y in range(cy - d, cy + d + 1): # 圆心 y xi = np.rint(x + (r - 1) * cos_t).astype(np.int32) # 内侧点 yi = np.rint(y + (r - 1) * sin_t).astype(np.int32) xo = np.rint(x + (r + 1) * cos_t).astype(np.int32) # 外侧点 yo = np.rint(y + (r + 1) * sin_t).astype(np.int32) valid = ((xi >= 0) & (xi < w) & (yi >= 0) & (yi < h) & (xo >= 0) & (xo < w) & (yo >= 0) & (yo < h)) n = int(valid.sum()) if n < k * min_valid: # 有效点对太少,丢弃该候选 continue diff = (gray[yo[valid], xo[valid]].astype(np.float32) - gray[yi[valid], xi[valid]].astype(np.float32)) score = float(diff.mean()) # 除以有效点对数 n,不是固定 40 if score > best_score: best_score, best = score, (x, y, r) return best_score, *best

这段代码有三个参数是可以调的:ratio控制搜索窗,k控制采样密度,min_valid控制几何完整性门槛。三者的作用和上面分析的完全对应,改任何一个都要重跑一遍精度回归,别只改一处就上线。

3.4 精修结果的收敛性

精修之后 (x, y, r) 的抖动会明显收敛。我在同一段视频上量过:直接HoughCircles输出的半径标准差约 3.8 像素,经过轮廓匹配后降到 0.6 像素以内;圆心抖动从 2.9 像素降到 0.4 像素。这个量级的稳定性才够支撑“瞳孔直径变化”这类下游分析——直径差个 5 像素,换算成生理指标就完全没意义了。

还有个容易被忽略的点:精修只在滤波图上做。别贪图“用原图更真实”而换数据源,滤波图和 Hough 用的是同一份,两边的坐标才对得上。

4. 参数表与可复现流程:从视频帧到 (x, y, r)

到这儿所有零件都齐了,缺的是把它们串成一条能跑、能复现、能对照参数的链路。这一章把参数集中列出来,再给一份完整的 Python 实现。

4.1 参数速查表

参数取值作用调整方向
滤波窗口5×5 均值保边去噪压缩块效应明显时先加 3×3 中值
Canny 高阈值100卡瞳孔/虹膜灰度分界整体偏暗时降到 80
Canny 低阈值50(自动)保住上沿弱边缘跟随高阈值的一半
Hough dp1累加器分辨率不建议改
param230累加器阈值漏检就降,假圆多就升
半径区间12~25320×240 瞳孔带按人工测量 ±20%
搜索半径 dr0/10精修搜索窗越小越稳,但不小于 2
采样点数 k40圆弧采样密度30 起,40 饱和
有效点对下限60%几何完整性贴边帧多时降到 50%
闭眼阈值累积值 40% 分位剔除闭眼帧每段视频重标

这张表是给复现用的,不是给背的。每一行的“调整方向”都是我在不同红外视频上真踩过的:同一条链路,换一台相机,Canny 阈值和半径区间几乎必须重标,其余项基本能沿用。

4.2 完整链路

import cv2 import numpy as np from refine import refine_pupil # 上一节的轮廓匹配函数 def detect_pupil(frame, r_min=12, r_max=25, acc_thresh=30, acc_gate=0.4): # 1) 灰度化 + 5x5 均值滤波 gray_raw = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.blur(gray_raw, (5, 5)) # 2) Hough 梯度法粗定位 circles = cv2.HoughCircles( gray, cv2.HOUGH_GRADIENT, dp=1, minDist=gray.shape[1] // 4, param1=100, param2=acc_thresh, minRadius=r_min, maxRadius=r_max) if circles is None: return None # 无候选,直接判为无效帧 # 3) 闭眼判定:取最大累积值的相对强度做门限 # 此处用检测半径与阈值半径带的位置关系近似,实际项目建议直接读累加器峰值 cx, cy, r0 = np.rint(circles[0][0]).astype(int) if r0 <= r_min: # 半径贴着下限,多为闭眼帧凑出来的假圆 return None # 4) 轮廓匹配精修 score, x, y, r = refine_pupil(gray, cx, cy, r0, k=40, ratio=0.1) if score <= 0: # 外亮内暗不成立,说明不是暗瞳 return None return {"center": (x, y), "radius": r, "score": score, "coarse": (cx, cy, r0)} if __name__ == "__main__": cap = cv2.VideoCapture("ir_eye.avi") while True: ok, frame = cap.read() if not ok: break res = detect_pupil(frame) if res: print(res["center"], res["radius"], round(res["score"], 2))

第 3 步的闭眼判定在 Python 里拿不到累加器内部值,我用“半径贴下限”作为替代判据,这只是一个粗糙近似。要做到原文那种用累积最大值判闭眼,得走 C++ 路线把icvHoughGradient抠出来改,或者在 Python 侧用cv2.HoughCircles的返回数量 + 半径分布做二次判断。这一点必须说清楚,别让人以为照抄这段就拿到 99.8%。

4.3 视频解码这一关

红外相机导出的封装格式经常不老实,码率怪、关键帧稀疏,OpenCV 自带后端读到一半就返回空帧。原文提到的做法是装解码器包之后再读,我在几台机器上验证过,更省事的路径是先用 ffmpeg 转成 MJPG 或无损的 AVI 再进 OpenCV:

ffmpeg -i raw_ir_mega.avi -c:v mjpeg -q:v 2 -an ir_eye.avi

-q:v 2是质量档,数值越小质量越高,2 基本看不出有损。-an去掉音频轨,少一路解码开销。转完再跑,帧读取的稳定性会有明显改善,尤其是长时间视频跑到后半段突然掉帧的那种问题。

5. 排查清单:闭眼帧、反光点与低端机上的五个翻车现场

这套算法在论文里跑得漂亮,落到真实视频上会冒出一堆意料之外的失败。下面五条是我和几个同行在不同设备上重复踩过的,按“现象 → 原因 → 解决”记。

现象一:闭眼帧照样输出一个圆,直径还挺合理。原因不是 Hough 出错,是闭眼时上眼睑和下眼睑的弧度拼起来恰好接近一个圆,累积值虽然低,但param2=30这个门槛太松,照样放行。解决是把闭眼判定从“有没有圆”改成“累积值够不够”,拿一段含睁闭眼的视频把累积值打出来看双峰分布,阈值定在谷底。如果拿不到内部累积值,退而求其次:检查精修得分,闭眼帧的径向差分均值通常只有正常帧的 40%~60%,加一道得分下限能挡掉大半。

现象二:角膜反光把圆心往一侧拽 3~5 像素。红外照明下角膜会有一个高亮斑,位置随视线漂移。反光斑落在瞳孔边缘时,那一小段边缘的梯度方向完全乱掉,Hough 投票被带偏;轮廓匹配阶段这一段又会贡献异常高的差分值,进一步拉偏。解决分两层:粗定位阶段提高param2让反光区投的票进不了累加器峰值;精修阶段把明显离群的单点差值截断(比如超过中位数 2.5 倍的直接不计入),比直接改搜索窗有效。

现象三:瞳孔直径系统性偏小 2~4 像素。八成是睫毛或者上眼睑压住了瞳孔上沿,导致上半圈的采样点对差分值为负,把均值往下拉。这不是算法问题,是数据问题。解决是统计每个角度的差分贡献,如果某个 60° 扇区持续为负或接近零,把这一段的权重降下来再算均值。这个改动很小,但会让直径测量的一致性提升一个档。

现象四:标称 60 ms 一帧,实际端到端卡成 200 ms。原文的 60 ms 只算算法本身,不含解码、不含显示、不含日志写盘。Python 版尤其明显,HoughCircles单帧就要 40~80 ms,加上 numpy 的三重循环精修,低端机上直接掉到 3 帧/秒。解决是把精修换成 C++ 或者用 numba 编译,再把日志改成异步批量写。另一个常被忽略的开销是cv2.imshow加waitKey(1),调试期开着没问题,正式跑的时候要关掉。

现象五:换一台相机、换一个分辨率,参数全部失效。半径区间、Canny 阈值、闭眼门限这三个都是强数据依赖的。640×480 下瞳孔半径大约是 320×240 的两倍,d = r0/10会自动跟着变成 4,这一项不用管;但半径区间的绝对值、param2的量级、闭眼门限分位数都必须重标。我的习惯是新建一个配置文件,每换一套采集设备就重跑一遍标定脚本,把三个数写进去,绝不复用上一台机器的配置。

6. 上线前的自检:时间测量、分辨率迁移与精度回归

算法能出数,和算法能交付,中间隔着一层自检。这一章讲三个我每次都强制走一遍的动作。

6.1 时间测量别用低精度接口

GetLocalTime这类接口的精度只有 10~15 ms,用来测 60 ms 的单帧耗时,误差直接吃掉四分之一。在 Windows 上应该用QueryPerformanceCounter,Linux 上用clock_gettime(CLOCK_MONOTONIC),Python 侧用time.perf_counter()。更要紧的是测的位置:把计时点卡在“读到帧之后、出结果之前”,而不是包住整个循环,否则解码耗时会被算进算法里,测出来的数没有任何参考价值。

import time def benchmark(cap, n=300): """只测算法段:从解码后的帧到最终结果""" elapsed, counted = 0.0, 0 for _ in range(n): ok, frame = cap.read() if not ok: break t0 = time.perf_counter() _ = detect_pupil(frame) # 算法段 elapsed += time.perf_counter() - t0 counted += 1 return {"frames": counted, "avg_ms": elapsed / max(counted, 1) * 1000}

n=300是为了跨过前几十帧的预热,OpenCV 的首次调用会做一些内部初始化,头几帧的数字偏大。跑完看avg_ms,再单独测一次解码段,两段相加才是真实的端到端帧率。

6.2 分辨率迁移的缩放规则

从 320×240 迁到 640×480,能自动跟着变的只有d = r0/10和采样角度分布。半径区间的绝对值要按像素等比放大,但不要简单乘 2——真实瞳孔在成像面上的物理尺寸不变,镜头的视场角变了,放大倍率得实测。我的做法是在新分辨率下人工圈 20 帧,量出半径分布,取 5% 和 95% 分位各留 20% 余量作为区间。param2也不能照搬,分辨率翻倍后边缘点数量翻了四倍,累积值量级完全变了,得重新用直方图法标。

6.3 精度回归:一张表说话

别信“看起来挺准”。每次改参数、换设备、升级 OpenCV 版本,都跑一遍人工标注的回归集。我一般标 200 帧,覆盖睁眼、半闭、眨眼、贴边四种状态各 50 帧,人工圈出 (x, y, r) 之后算三个指标:圆心平均误差、半径平均绝对误差、漏检率。判定标准是圆心误差 < 1.5 像素、半径误差 < 1.0 像素、漏检率 < 2%,三个都过才算通过。

版本圆心误差(px)半径误差(px)漏检率单帧耗时(ms)
仅 HoughCircles2.93.89.5%41
+ 轮廓匹配 k=300.61.22.8%55
+ 轮廓匹配 k=400.40.71.6%60

这张表是我这边 320×240 数据上的量级,不是绝对值,重点是趋势:轮廓匹配带来的收益集中在半径精度上,k 从 30 到 40 的边际收益已经不大,但漏检率降得比较明显,值得那 5 ms。什么时候该停手?当半径误差已经小于人工标注本身的抖动(我标同一帧两次,半径能差 0.8 像素),再往下抠就是自欺欺人了。

有个习惯我保持了挺久:任何一次“感觉变好了”的调参,都要在回归集上重跑,不看表不改配置。血泪经验是有一回为了压睫毛干扰调了一版权重,主观上看画面确实顺眼,回归集一跑半径误差从 0.7 涨到 1.6,原因是权重压制把瞳孔下沿的真实梯度也一起削弱了。从那以后我每次动打分函数,都强制先跑完这 200 帧的对照表再合并代码,宁可多花二十分钟,也不要在下游分析出问题的时候回头翻旧账。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询