当前位置: 首页 > news >正文

无监督光流,unflow, uflow,upflow

Census 变换(Census Transform)详解

1. 基本概念

Census 变换是一种非参数化的局部二值特征描述方法,由 Zabih 和 Woodfill 在 1994 年提出。它的核心思想是通过比较像素邻域内中心像素与其他像素的亮度关系,生成一个二值编码串,从而描述局部图像的纹理结构。
特点

  • 对光照变化鲁棒:能够抵抗加性(如亮度偏移)、乘性(如对比度变化)和伽马(非线性亮度变化)的光照变化。
  • 计算高效:仅需比较操作和位运算,适合实时应用(如光流估计、立体匹配)。

2. 算法步骤

以图像中某一点 ( p )(中心像素)为例,其 Census 变换过程如下:

  1. 定义邻域
    选择一个大小为 ( n \times n ) 的邻域(例如 ( 3 \times 3 ) 或 ( 5 \times 5 )),排除中心像素后共有 ( m = n^2 - 1 ) 个邻域像素。

  2. 二值比较
    将每个邻域像素 ( q ) 的亮度 ( I(q) ) 与中心像素亮度 ( I§ ) 比较,生成二值位串:
    在这里插入图片描述
    请添加图片描述

  3. 生成 Census 描述符
    将所有邻域像素的二值结果按固定顺序(如从左到右、从上到下)拼接成一个二进制串(即 Census 签名)。
    示例(( 3 \times 3 ) 邻域):

    • 中心像素亮度 ( I§ = 100 ),邻域像素亮度为 ( [90, 110, 95, 105, 100, 102, 98, 115] )。
    • 二值比较结果:( [1, 0, 1, 0, _, 0, 1, 0] )(跳过中心像素)。
    • Census 签名:10100101(二进制)或 0xA5(十六进制)。

3. 光度差异测量

在光流或立体匹配中,Census 变换用于衡量两幅图像中对应像素块的光度差异:

  • 汉明距离(Hamming Distance)
    计算两个 Census 签名二进制串的异或(XOR)结果中 1 的个数。距离越小,相似度越高。
    优点:对光照变化不敏感,仅依赖相对亮度关系。

4. 为什么 Census 变换对光照变化鲁棒?

Census 变换的鲁棒性源于其序数特征(Ordinal Feature)

  • 加性光照变化(如全局亮度+10):所有像素亮度同时增加,但大小关系不变 → 二值编码不变。
  • 乘性光照变化(如对比度×1.2):亮度比例变化,但局部相对顺序可能保持 → 编码基本稳定。
  • 伽马校正(非线性亮度调整):只要不改变邻域内像素的亮度序数关系,编码仍有效。

对比传统方法

  • 亮度差(( I_1 - I_2 ))受光照变化直接影响。
  • Census 变换仅依赖“谁比谁亮”的相对关系,因此更稳定。

5. 改进:三元 Census 变换(Ternary Census)

在这里插入图片描述


6. 应用场景
  1. 光流估计(Optical Flow)
    • 替代传统亮度恒常假设,提升对光照变化的鲁棒性(如文中所述)。
  2. 立体匹配(Stereo Matching)
    • 用于计算左右图像中对应像素块的相似度。
  3. 特征描述(Local Feature Descriptor)
    • 类似 BRIEF 或 ORB,但更注重光照不变性。

7. 代码示例(Python 伪代码)
import numpy as npdef census_transform(image, window_size=3):h, w = image.shapecensus = np.zeros((h, w), dtype=np.uint32)offset = window_size // 2for y in range(offset, h - offset):for x in range(offset, w - offset):center = image[y, x]binary_str = 0bit_pos = 0for dy in range(-offset, offset + 1):for dx in range(-offset, offset + 1):if dy == 0 and dx == 0:continue  # 跳过中心像素neighbor = image[y + dy, x + dx]if neighbor < center:binary_str |= (1 << bit_pos)bit_pos += 1census[y, x] = binary_strreturn census

总结

  • Census 变换通过局部二值序数关系描述纹理,对光照变化具有强鲁棒性。
  • 核心操作:邻域像素亮度比较 → 二进制编码 → 汉明距离匹配。
  • 改进方向:三元编码、自适应阈值、多尺度邻域等。
  • 适用领域:光流、立体视觉、实时系统(如自动驾驶、机器人导航)。

无监督光流估计

1.UnFlow: Unsupervised Learning of Optical Flow with a Bidirectional Census Loss(2017)

1.1第一个判断遮挡

公式的含义是 x表示pixel在第一帧的位置, x+wf(x) 表示该pixel在第二帧的位置。
那么理论上,他们对应的光流应该是相反的,相加等于0的。

因此满足公式1 表示正向光流+反向光流比较小,没有被遮挡。
不满足就是遮挡。
请添加图片描述

请添加图片描述

O=1,表示被遮挡。

1.2 photometric difference

考虑遮挡区域,最终的图像一致性loss
公式2考虑了前向和后向。

请添加图片描述


关键概念解释

  1. 光度差异(Photometric Difference)

    • 衡量两幅图像中对应像素的亮度或颜色差异。
    • 传统方法(如 Yu et al. 2016)使用简单的亮度差 ( I_1(x) - I_2(x’) ),但对光照变化敏感。
    • 改进方法:使用 Census 变换(一种局部二值模式),对光照变化(如亮度偏移、对比度变化)具有鲁棒性。
  2. Charbonnier 惩罚函数

    • 公式:( \rho(x) = (x^2 + \epsilon2)\gamma ),其中 ( \gamma = 0.45 )。
    • 作用:对误差(如光流估计中的像素差异)进行鲁棒惩罚,避免异常值对优化过程的影响。
  3. 遮挡像素处理

    • 对遮挡像素施加固定惩罚 ( \lambda_p ),防止优化算法将所有像素标记为遮挡(即“平凡解”)。
    • 对非遮挡像素的光度差异进行动态惩罚。
  4. 二阶平滑约束(Second-order Smoothness)

    • 相比一阶平滑(仅约束光流梯度),二阶平滑还约束光流的曲率,使得光流场更加平滑且保持局部线性结构(如边缘对齐)。
    • 应用场景:光流估计(Optical Flow)中,避免过度碎片化,提升运动边界的准确性。

技术背景

  • Census 变换
    • 一种非参数化的局部特征描述方法,对像素邻域进行二值编码,对光照变化鲁棒。
    • 优于传统亮度差,适用于真实场景(如阴影、曝光变化)。
  • 光流(Optical Flow)
    • 估计视频或图像序列中像素的运动矢量。
    • 挑战:遮挡、光照变化、大位移等。本文通过改进的光度差异度量和平滑约束提升鲁棒性。

如果需要更详细的数学推导或代码实现细节,可以进一步探讨!

1.3 平滑loss 和光流一致性loss

请添加图片描述

在这里插入图片描述

1.4 监督loss

valid = 1的像素,光流监督
请添加图片描述

2. UFlow:What Matters in Unsupervised Optical Flow

1 photometric Consistency的几种方法

在这里插入图片描述

可以再加上一个laplace

2 遮挡估计

Related approaches estimate occlusions by
(i) checking for consistent forward and backward flow [30],
(ii) using the range map of the backwardflow [3], and
(iii) learning a model for occlusion estimation

第一个是 pixel在第一帧的位置,和该pixel在第二帧的位置。
那么理论上,他们对应的光流应该是相反的,相加等于0的。

第二个是 rangemap 在另一张图像上有多少个pixel 指向该pixel, 如果没有说明该pixel是被遮挡的。

3. Gradient Stopping at Occlusion Masks

在计算遮挡加权光度差异时,模型会倾向于掩码掉光度误差高的像素。
unflow是加了正则化避免遮挡区域过大,这里是在计算遮挡加权光度loss时将遮挡掩码视为常数(不参与梯度计算)。

occlusion_mask = occlusion_mask.detach()   # 关键步骤:截断梯度
loss = (photometric_loss * (1 - occlusion_mask)).mean()

4. smooth loss

edge-aware first order
edge-aware second order

就是根据图像梯度约束,使图像边缘的flow可以不那么平滑
一会直接看代码吧,容易懂

5. smooth loss在第几层加入

文中是基于PWC网络结构,一般在 h/2, w/2的分辨率上估计光流,然后双线性插值上采样得到最终光流, 然后apply smooth loss。
但是这样的方法有问题,这种流程会导致光流场呈现分段线性(piece-wise linear),即每4个像素中只有一个像素的二阶导数非零。

因此解决方案如下:
dge-aware smooth loss:

1)在生成光流的层级(ℓ=2)直接施加平滑性约束,而不是在上采样后的光流上计算。

2)对图像进行下采样(而非对光流上采样),使得平滑性约束作用于更接近原始光流估计的分辨率。

3)不影响最终评估,因为评估仍基于原图分辨率的光流。

6. 自监督持续自监督与图像尺寸调整

核心思想
  1. 持续自监督(Continual Self-supervision)

    • 传统方法:先训练一个固定的教师模型(Teacher Model),再用它监督学生模型(Student Model),两者独立。
    • 本文改进:使用单一模型自我监督(无需分离教师/学生模型),简化流程、降低内存占用,并允许自监督信号随训练持续优化。
    • 梯度截断:为防止自监督目标干扰“教师”光流的稳定性,阻断其梯度回传(类似“冻结”教师模型的效果,但无需实际存储两个模型)。
  2. 图像尺寸调整(Image Resizing)

    • 裁剪后的图像块(crops)会被调整回原始分辨率再输入模型,同时按比例缩放生成的光流伪标签。
    • 目的:使自监督样本更贴近真实场景中光流超出图像边界的外推问题(extrapolating flow beyond the image boundary)。

技术细节

1. 持续自监督流程
  • 步骤
    1. 对完整图像输入模型,生成“教师”光流(flow_teacher)。
    2. 裁剪图像(如去掉64像素边缘),调整裁剪块至原始分辨率,输入同一模型生成“学生”光流(flow_student)。
    3. flow_teacher在裁剪区域的估计按比例缩放,作为flow_student的监督信号。
    4. 计算遮挡加权的Charbonnier损失,仅对flow_student反向传播梯度flow_teacher的梯度被截断)。
2. 图像尺寸调整的意义
  • 若直接在小分辨率裁剪块上训练,模型可能无法学习如何在外推边界光流时保持一致性。
  • 通过恢复原始分辨率,模拟真实测试时边界像素的光流估计挑战。

伪代码实现(PyTorch风格)

import torch
import torch.nn.functional as Fdef continual_self_supervision(model, images, crop_size=64):# 假设 images: [B, C, H, W](输入图像批次)B, C, H, W = images.shape# 1. 全图生成“教师”光流(无梯度截断,正常训练)flow_teacher = model(images)  # [B, 2, H, W]# 2. 裁剪图像(四边各裁crop_size像素)cropped_images = images[:, :, crop_size:-crop_size, crop_size:-crop_size]  # [B, C, H-2*crop_size, W-2*crop_size]# 3. 调整裁剪块至原始分辨率(双线性插值)cropped_images_resized = F.interpolate(cropped_images, size=(H, W), mode='bilinear')# 4. 生成“学生”光流flow_student = model(cropped_images_resized)  # [B, 2, H, W]# 5. 裁剪并缩放“教师”光流作为监督标签flow_teacher_cropped = flow_teacher[:, :, crop_size:-crop_size, crop_size:-crop_size]  # [B, 2, H-2*crop_size, W-2*crop_size]flow_teacher_resized = F.interpolate(flow_teacher_cropped, size=(H, W), mode='bilinear')# 注意:光流值需按缩放比例调整(此处假设缩放因子为 s = H / (H-2*crop_size))scale_factor = H / (H - 2 * crop_size)flow_teacher_resized *= scale_factor# 6. 计算自监督损失(遮挡加权 + Charbonnier)mask = compute_occlusion_mask(flow_student, flow_teacher_resized)  # 假设实现遮挡掩码计算loss = charbonnier_loss(flow_student, flow_teacher_resized.detach(), mask)  # 截断教师梯度return lossdef charbonnier_loss(x, y, mask, eps=1e-3, gamma=0.45):diff = torch.sqrt((x - y)**2 + eps**2).pow(gamma)return (diff * mask).mean()

关键点总结

  1. 单模型自我监督
    • 无需维护两个模型,通过梯度截断实现教师-学生逻辑,节省内存。
  2. 分辨率恢复
    • 裁剪块调整回原尺寸,确保模型学习到真实边界外推的泛化能力。
  3. 工程优势
    • 更简单的实现(单模型)、更低的显存占用、动态更新的伪标签。

与DDFlow等方法的对比

方法教师模型学生模型梯度截断分辨率调整
DDFlow [14]固定独立
本文方法动态同一模型

7. 总的loss

翻译与解释


1. 优化目标(Optimization)

总损失函数
在这里插入图片描述

权重设置

损失类型权重 ( w ) 设置备注
光度损失Census 损失:( w_{\text{photo}} = 1 );其他损失:2SSIM/Charbonnier/L1 需更高权重
平滑性正则一阶平滑:( w_{\text{smooth}} = 2 );二阶平滑:4边缘权重 ( \lambda = 150 )
自监督损失前 50% 训练步数:( w_{\text{self}} = 0 );
接下来 10% 线性增至 0.3;之后固定
避免早期训练干扰

2. 数据预处理与增强(Data Augmentation)
  • RGB 归一化:图像像素值缩放至 ([-1, 1])。
  • 颜色增强
    • 随机交换颜色通道(如 RGB → BGR)。
    • 随机调整色调(Hue Shift)。
  • Sintel 数据集额外增强
    • 随机上下/左右翻转(提升旋转不变性)。

3. 训练策略(Training Schedule)

在这里插入图片描述


8. 结果

在这里插入图片描述

3. CVPR2021 UPFlow: Upsampling Pyramid for Unsupervised Optical Flow Learning

待续

http://www.dtcms.com/a/273398.html

相关文章:

  • imx6ull-裸机学习实验14(下)——驱动DDR3和测试
  • 数组和指针回顾,练习与解析
  • OSCP官方靶场-Solstice WP
  • 【第二节】ubuntu server配置静态IP
  • (思维)洛谷 P3081 USACO13MAR Hill Walk 题解
  • 网络安全基础概念以及虚拟环境的搭建
  • alpinelinux的网络配置
  • ZW3D 二次开发-创建六面体方框
  • 力扣面试150题--全排列
  • AOSP自启动拦截框架Intent Firewall
  • 反向传播notes
  • 敏捷测试中的质量闸门如何设置?
  • 位运算算法题
  • 第七讲:C++中的string类
  • 深度学习参数初始化方法详解及代码实现
  • 深度学习×第7卷:参数初始化与网络搭建——她第一次挑好初始的重量
  • ZW3D 二次开发-创建椭球体
  • 灰度发布策略制定方案时可以参考的几个维度
  • 递推+高精度加法 P1255 数楼梯
  • apt -y参数的含义
  • 计算机视觉 之 数字图像处理基础(一)
  • Kubernetes 1.23.6 kube-scheduler 默认打分和排序机制详解
  • 多商户商城系统源码选型指南:开源 vs 定制,哪种更适合?
  • 救回多年未用kubeadm搭建的kubernetes集群
  • 5. isaac sim4.2 教程-Core API-操作机械臂
  • 用黑盒测试与白盒测试,读懂专利审查的 “双重关卡”​​
  • K8S的CNI之calico插件升级至3.30.2
  • 深度学习中的 Seq2Seq 模型与注意力机制
  • 解释sync.WaitGroup的用途和工作原理。在什么情况下应该使用它?
  • 时间显示 蓝桥云课Java