如何基于凝视注视数据CSV生成匹配原样式的灰度显著性地图
凝视注视数据转灰度显著性地图的代码优化建议
核心方向确认
你的实现方向是对的——基于凝视点的位置和持续时长生成热力图/显著性地图是眼动数据可视化的标准思路,问题出在细节处理上。
针对性代码修改建议
1. 修正坐标映射逻辑
- 先确认凝视坐标的原点定义:网站采集的坐标通常以屏幕左上角为(0,0),如果你的画布尺寸和采集时的屏幕尺寸不一致,必须做归一化映射,否则会出现边界偏移:
# 假设采集时的屏幕宽高为screen_w、screen_h,生成的显著性图尺寸为map_w、map_h norm_x = (gaze_x / screen_w) * map_w norm_y = (gaze_y / screen_h) * map_h - 别忘了处理滚动状态的偏移:数据中的滚动字段(示例里的第4个值)会让凝视坐标变成相对页面的位置,需要用滚动值修正y坐标:
# scroll_offset为数据中的滚动状态值,修正后的y坐标 corrected_y = gaze_y - scroll_offset
2. 强化中心区域权重
- 中心区域不突出,大多是因为没有根据持续时长加权,或高斯核参数不合理:
- 给每个凝视点分配与时长成正比的权重,时长越长,高斯核的幅值越高:
# 先把时长归一化到0-1范围,再乘以基础强度 max_duration = max(all_durations) # all_durations是所有凝视点的时长列表 intensity = 1.0 * (duration / max_duration) - 调整高斯核的sigma值:值越小,中心峰值越锐利,更能突出长时长的凝视点:
sigma = 25 # 可根据效果微调,建议在20-40之间测试 kernel = cv2.getGaussianKernel(51, sigma) kernel = kernel @ kernel.T # 转为二维高斯核 weighted_kernel = kernel * intensity - 叠加核时注意边界处理,避免越界:
x, y = int(norm_x), int(norm_y) h, w = weighted_kernel.shape # 计算有效叠加区域,防止超出画布范围 top = max(0, y - h//2) bottom = min(map_h, y + h//2 + 1) left = max(0, x - w//2) right = min(map_w, x + w//2 + 1) # 截取对应区域的核并叠加 saliency_map[top:bottom, left:right] += weighted_kernel[ top-(y-h//2):bottom-(y-h//2), left-(x-w//2):right-(x-w//2) ]
- 给每个凝视点分配与时长成正比的权重,时长越长,高斯核的幅值越高:
3. 灰度图的对比度增强
- 生成后的显著性图必须做全局归一化,把像素值缩放到0-255的灰度范围,避免动态范围不足导致细节丢失:
# 归一化到0-1后转成0-255的uint8格式 saliency_map = (saliency_map - saliency_map.min()) / (saliency_map.max() - saliency_map.min()) * 255 saliency_map = saliency_map.astype(np.uint8) - 可选:用直方图均衡增强对比度,让高权重区域更突出:
saliency_map = cv2.equalizeHist(saliency_map)
4. 边界点的补全处理
- 贴近画布边界的凝视点,高斯核会被截断,导致边缘区域权重偏低,可以先给画布加padding,处理完成后再裁剪回原尺寸:
padding = 50 # 创建带padding的临时画布 temp_map = np.zeros((map_h + 2*padding, map_w + 2*padding), dtype=np.float32) # 所有凝视点坐标加上padding后再做叠加处理 # ...(叠加高斯核的逻辑) # 裁剪回原尺寸 saliency_map = temp_map[padding:-padding, padding:-padding]
验证步骤
- 单独提取几个典型凝视点(比如中心长时长、左侧边界点),手动计算映射后的坐标,检查是否符合预期
- 逐步注释掉高斯叠加、归一化等步骤,定位是哪一步导致的结果差异
内容的提问来源于stack exchange,提问作者hasin
相关产品推荐
相关产品推荐

