曝光、快门(全局、卷帘)、CMOS 与 CCD、相机软件调试

概述

拍照的总体流程,在数码相机或影像传感器(如CMOS、CCD)中,拍摄图像的过程可以分为以下几个核心阶段:

  • 光线进入镜头 → 打在感光元件上(图像传感器)
  • 感光元件将光信号转换为电信号(电压信号)
  • 电信号经过采样、放大、模数转换(ADC)成为数字信号
  • 数字信号经图像处理(白平衡、降噪、锐化)→ 输出图像文件

曝光

  • 曝光(Exposure)指的是传感器接收到的总光量,它决定了图像的明暗程度。曝光由以下三个要素共同决定:
  • 快门时间(Shutter Speed):光照射在传感器上的时间长度。
  • 光圈大小(Aperture):光线进入镜头的通光孔径。
  • 感光度(ISO):传感器对光信号的放大倍数。

快门

  • 快门的作用:控制光照时间窗口
  • 快门是控制光照射时间的"门"。它决定了传感器在多长时间内"接受"光信号
  • 机械快门:通过物理遮光板打开/关闭。
  • 电子快门:通过控制传感器读出电路的开关时间实现。
  • 在快门打开的时间内,光子打到传感器的每个像素上,产生电子积累。快门关闭后,传感器开始读取这些电子信号。
  • 快门时间:从传感器开始接收光信号到停止接收光信号之间的时间。在这段时间内,每个像素的光电二极管都在"积分"入射光能量,即不断累积电子。当快门关闭后,积分结束,电荷量固定下来,随后才进入读出阶段。

电信号采集

电压信号采集过程:从光子到电压

  • 当光照射到图像传感器(以CMOS为例)时:
  • 光电转换:光子打在像素点的光电二极管上,释放电子,形成电荷累积。
  • 电荷-电压转换:在快门关闭后,像素的电荷通过电容转化为电压信号。
  • 读出放大与采样保持(Sample & Hold):每个像素的电压信号被读取、放大,并暂存。
  • 模数转换(ADC):模拟电压信号转换为数字信号,供图像处理使用。
bash 复制代码
时间轴:   |--- 快门开启 --->--- 快门关闭 ---> 读出/采样 ---> ADC转换 ---> 数字信号输出 |
信号变化: | 光子积累(电荷增加) | 电荷保持 | 电压采样 | 电压转数字 | 图像信号生成 |

全局快门(Global Shutter)和卷帘快门(Rolling Shutter):

CMOS 传感器**"理论上"每个像素都能独立采样**,但"**实际上"电路和物理架构根本无法让所有像素同时采样**:

  • 回顾拍照流程:光进入感光元器件、快门打开、开始曝光、曝光结束、快门关闭、电压采样。
  • 因为无法所有像素同时采样,所以发明了一些方法:
  • 卷帘快门:逐行曝光 + 逐行采样。(果冻效应,但是电荷转移少,噪点少)
  • 全局快门:整体曝光 + 电容保持电荷 + 逐行挨个采样。(电容保持电荷存在噪点,但是没有果冻效应)

其余的折中方案:

方案 思想 优缺点
卷帘快门 行扫描,逐行曝光+读出 简单、便宜、有果冻效应
全局快门 所有像素同时曝光+采样 无畸变、结构复杂、成本高
准全局快门(Near-Global) 多行同步曝光、快速读出 畸变极小,成本可控
存储层分离架构(stacked sensor) 在像素层下增加独立读出层 紧凑、性能提升,但制造贵(Sony 近年采用)

卷帘快门带来的果冻效应:因为卷帘快门是一行一行曝光、一行一行采样,所以会产生"果冻效应",也就是运动模糊。


那一款相机既支持全局快门也支持卷帘快门,你之前说的缺点"光敏面积变小"、"电路复杂度上升",是不是就不存在了,因为他已经做好了全局快门?此时卷帘快门的唯一优势就是功耗低?

  • 确实一款相机如果同时支持全局快门与卷帘快门,那么它的底层硬件都已经固定,全局快门带来了的"光敏面积变小"、"电路复杂度上升"的问题,卷帘快门模式下也仍然存在。
  • 但是卷帘快门也有它的优势:噪声更低一点。
  • 在卷帘快门(Rolling Shutter)模式下,每个像素确实不需要额外的存储电容(Sample & Hold Capacitor),而是在曝光结束后,直接把像素节点的电荷转换为电压并立刻读取。卷帘快门像素的"电荷→电压→数字化"过程是同步发生的
  • 全局快门模式下,电荷需要从光电二极管转移两次(PD → Csh → 放大节点),每次转移都会带来信号失真与噪声

CCD 与 CMOS 的区别

CCD与CMOS图像传感器光电转换的原理相同,他们最主要的差别在于信号的读出过程不同;

  • 光电转化:光子打到感光单元(像素) → 电子被激发 → 形成电荷信号。
  • 由于CCD仅有一个(或少数几个)输出节点统一读出,其信号输出的一致性非常好; 而CMOS芯片中,每个像素都有各自的信号放大器,各自进行电荷-电压的转换,其信号输出的一致性较差。

软件调试与验证

V4L2-ctrl 介绍

V4L 是 Video for Linux 的缩写,2 代表是第二个版本,v4l2-ctl 支持绝大多数 USB 摄像头的关键原因在于它依赖的 V4L2 通用标准层 与 UVC 驱动

通用的 UVC 标准驱动,绝大多数 USB 摄像头都遵循 USB Video Class (UVC) 标准,因此,v4l2-ctl 能通过标准的 V4L2 控制接口访问这些控件。

  • Linux 内核中自带的 uvcvideo 驱动支持 UVC 1.0/1.1/1.5 协议。
  • uvcvideo 驱动在注册 /dev/videoX 设备时,自动将摄像头的功能映射为 V4L2 控件(controls),例如
    • V4L2_CID_BRIGHTNESS
    • V4L2_CID_CONTRAST
    • V4L2_CID_EXPOSURE_AUTO
    • V4L2_CID_FOCUS_ABSOLUTE

厂商扩展控制的兼容机制

  • 即使部分摄像头有厂商私有控制项(如 Logitech 的人脸跟踪、红外切换),它们通常仍通过 V4L2_CID_PRIVATE_BASE 向上注册。
  • v4l2-ctl --list-ctrls 会列出所有这些自定义控制。
  • 只要驱动正确注册,v4l2-ctl 就能访问。

UVC 驱动与 V4L2 子系统高度统一

  • 内核中 uvcvideo 驱动直接实现了 V4L2 子系统的所有关键接口(包括视频采集、流控制、控制项查询)。
  • 因此,v4l2-ctl 几乎不需要针对不同品牌做额外适配。

V4L2-ctrl 指令

安装相关工具:

bash 复制代码
sudo apt update
sudo apt install v4l-utils
v4l2-ctl --version

查看当前的 USB 相机列表

bash 复制代码
# w300: 摄像头的逻辑名称(由设备固件或驱动提供)
# (usb-0000:00:14.0-6):摄像头连接的 USB 总线信息(物理连接位置)
# /dev/video0:摄像头的主视频流接口(通常是图像采集节点)
# /dev/video1:附属视频接口(可能是元数据流、红外流或麦克风接口)
# /dev/media0:Media Controller 节点,用于高级设备拓扑管理(连接传感器、ISP、编码器等子设备)
w300: w300 (usb-0000:00:14.0-6):
	/dev/video0
	/dev/video1
	/dev/media0

查看某个具体视频流的配置:

bash 复制代码
v4l2-ctl --device=/dev/video1 --all

# 查看用户可以修改的配置信息:
v4l2-ctl --device=/dev/video0 --list-ctrls
bash 复制代码
# v4l2-ctl --device=/dev/video1 --all, 关于视频流的输出信息
Format Video Capture:
	Width/Height      : 1920/1080
	Pixel Format      : 'MJPG' (Motion-JPEG)
	Field             : None
	Bytes per Line    : 0
	Size Image        : 4147789
	Colorspace        : sRGB
	Transfer Function : Default (maps to sRGB)
	YCbCr/HSV Encoding: Default (maps to ITU-R 601)
	Quantization      : Default (maps to Full Range)

Format Video Capture 中的 Width/Height : 1920/1080,它表示当前输出视频流的分辨率,但不一定等于感光元件(sensor)的物理像素数量。

# 现代摄像头在传感器与输出之间还有许多中间环节
传感器原始像素 → ISP(图像信号处理)→ 编码/压缩 → USB 传输 → 输出帧

# 常见的几种情况:
1. 输出分辨率 = 传感器原生分辨率
	最理想情况。
	比如传感器物理像素是 1920×1080,驱动输出 1920×1080;
	图像清晰,细节完整。
2. 输出分辨率 < 传感器分辨率(下采样)
	常见于高分辨率传感器降级输出。
	比如传感器 2592×1944(5MP),输出 1280×720;
	驱动或 ISP 做了下采样(average/binning);
	图像细节减少,但噪声更低。
3. 输出分辨率 > 传感器分辨率(插值放大)
	廉价 USB 摄像头常见。
	实际传感器也许只有 640×480(VGA),但驱动报告 1920×1080;驱动内部做了数字插值(软件放大),
	结果"像素多了,但细节没变",画面看起来虚假清晰。

在 Linux 下通过 v4l2-ctl 或其他用户态命令行工具,你看不到摄像头传感器(MOS/CMOS Sensor)真正的物理像素数量,只能看到驱动报告出来的视频输出格式(分辨率、帧率、像素格式)

  • v4l2-ctl、ffmpeg、media-ctl 等命令访问的是 /dev/videoX 设备。这条链路最终的输出是"视频流".
  • 驱动层通常不公开底层传感器信息:
  • 对于 USB 摄像头(UVC 协议):内核只看到一个标准化的接口(UVC descriptors),不知道里面是什么传感器芯片(例如 OV5640、GC2145、IMX219 等)。它只知道设备"支持哪些分辨率"和"支持哪些像素格式"。
  • 对于 MIPI/CSI 摄像头(嵌入式平台):驱动可能确实知道底层 sensor 信息,但只有在 media-ctl、libcamera 层才可能看到。
  • 获取真实像素数的正确途径:先确认摄像头的 USB Vendor ID / Product ID ---> 然后上网搜索对应的芯片,一般能查到使用的 CMOS 芯片型号(如 OV2640、GC0308 等),---> 再查该 sensor 的 datasheet,就能看到其原生像素。

查看当前视频流支持的所有分辨率、帧率、图像格式:

bash 复制代码
v4l2-ctl --list-formats-ext

设置当前视频流的分辨率、帧率、图像格式:

  • 修改分辨率只影响当前会话;设备重新插拔后通常会恢复默认。
  • 若有多个摄像头,务必带上 --device=/dev/videoX。
  • 如果用 ffplay、ffmpeg 等工具采流,它们可能在打开时会覆盖 v4l2-ctl 设置(因为它们会重新请求特定分辨率/格式)。
bash 复制代码
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=<宽度>,height=<高度>,pixelformat=<格式>

# 把摄像头设置为 1280×720,MJPEG 格式
v4l2-ctl --device=/dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=MJPG

v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=MJPG --set-parm=30

设置当前视频流的曝光信息。

先查看当前的曝光信息:

  • auto_exposure: min=0 max=3 default=3 value=3 (Aperture Priority Mode),设置为1 的时候,才是手动模式,这时候才可以设置曝光时间。
  • exposure_time_absolute: min=1 max=5000 step=1 default=157 value=157 flags=inactive
bash 复制代码
v4l2-ctl --list-ctrls

User Controls

                     brightness 0x00980900 (int)    : min=-64 max=64 step=1 default=0 value=0
                       contrast 0x00980901 (int)    : min=0 max=64 step=1 default=32 value=32
                     saturation 0x00980902 (int)    : min=0 max=128 step=1 default=64 value=64
                            hue 0x00980903 (int)    : min=-40 max=40 step=1 default=0 value=0
        white_balance_automatic 0x0098090c (bool)   : default=1 value=1
                          gamma 0x00980910 (int)    : min=72 max=500 step=1 default=100 value=100
                           gain 0x00980913 (int)    : min=0 max=100 step=1 default=0 value=0
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=1 value=1 (50 Hz)
      white_balance_temperature 0x0098091a (int)    : min=2800 max=6500 step=1 default=4600 value=4600 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=6 step=1 default=4 value=4
         backlight_compensation 0x0098091c (int)    : min=0 max=160 step=1 default=80 value=80

Camera Controls
                  auto_exposure 0x009a0901 (menu)   : min=0 max=3 default=3 value=3 (Aperture Priority Mode)
         exposure_time_absolute 0x009a0902 (int)    : min=1 max=5000 step=1 default=157 value=157 flags=inactive
     exposure_dynamic_framerate 0x009a0903 (bool)   : default=0 value=1

设置不同的曝光率:受限需要关闭自动曝光,设置为手动曝光模式

bash 复制代码
# 设置为手动曝光模式:
v4l2-ctl -c auto_exposure=1

# 设置曝光时间:
v4l2-ctl -c exposure_time_absolute=80

验证效果:使用 ffplay 来抓取视频流,此时曝光时间越短,画面应该越暗,曝光时间越长,画面应该越亮。

bash 复制代码
ffplay /dev/video0

Opencv

opencv 安装

https://www.cnblogs.com/booturbo/p/17399215.html

opencv 架构

OpenCV(Open Source Computer Vision Library)是一个跨平台的计算机视觉库,

用 C/C++ 实现,底层封装了各种 图像采集、处理、显示与硬件接口。它可以运行在 Windows、Linux、macOS、Android、iOS、嵌入式板卡 等多平台。

OpenCV 的总体架构,可以概括为一个 "多层抽象模型":

bash 复制代码
┌────────────────────────────┐
│ 应用层(Python / C++ / Java APIs)│
├────────────────────────────┤
│ 模块层(imgproc, videoio, dnn, calib3d, etc.)│
├────────────────────────────┤
│ 平台适配层(HAL: Hardware Abstraction Layer)│
├────────────────────────────┤
│ 底层系统接口(OS / 驱动 / SDK) │
└────────────────────────────┘
层级 功能
应用层 用户调用的接口,比如 cv::imread(), cv::VideoCapture(), cv::imshow()
模块层 图像处理算法模块(滤波、边缘检测、人脸识别、深度学习等)
HAL 层(Hardware Abstraction Layer) 抽象硬件加速接口,屏蔽不同平台的差异(CPU / CUDA / OpenCL)
底层接口 不同操作系统提供的驱动接口(V4L2、DirectShow、AVFoundation 等)

OpenCV 访问摄像头/视频设备时的底层驱动差异:

OpenCV 的 cv::VideoCapture 模块负责与操作系统的视频接口交互,在不同系统下,它自动选择对应的驱动或后端:

平台 使用的底层驱动或 API 说明
Linux 🎥 V4L2 (Video4Linux2) 直接调用 /dev/videoX 设备(USB 摄像头、CSI 摄像头等)
Windows 🎬 DirectShowMedia Foundation 用 Windows 自带的视频捕获框架访问 USB 摄像头
macOS 🍎 AVFoundation Apple 的原生多媒体框架
Android 📱 NDK Camera API / OpenMAX / MediaNDK 调用安卓底层相机接口
iOS 📷 AVFoundation (iOS SDK) 同样通过苹果的多媒体接口
GStreamer(可选) 🧩 可跨平台的多媒体框架 OpenCV 可编译时启用 GStreamer 支持,用于视频流/网络推流
FFmpeg(可选) 🧠 通用视频解码库 主要用于读取文件(MP4、AVI 等),也能采流

所以,当你在不同系统上调用:cv::VideoCapture cap(0);

OpenCV 会自动:

  • 在 Linux 下走 /dev/video0 → V4L2;
  • 在 Windows 下走 DirectShow;
  • 在 macOS 下走 AVFoundation;
  • 用户完全无需关心底层实现。
相关推荐
双翌视觉6 小时前
机器视觉的液晶电视OCA全贴合应用
人工智能·数码相机·机器学习·1024程序员节
LucianaiB6 小时前
【案例实战】基于分布式能力的跨设备任务协同应用开发
harmonyos·鸿蒙·1024程序员节·案例实战
Lenz's law7 小时前
智元灵犀X1-本体通讯架构分析2:CAN/FD总线性能优化分析
架构·机器人·can·1024程序员节
Dev7z7 小时前
宠物皮肤病图像分类数据集
1024程序员节
木井巳10 小时前
[Java数据结构和算法] HashMap 和 HashSet
java·数据结构·1024程序员节
杨DaB11 小时前
【SpringCloud】Eureka
spring cloud·eureka·1024程序员节
桃里桑12 小时前
【算法】互补滤波在位移双反馈控制汇总的应用
1024程序员节
liu****12 小时前
1.模拟算法
开发语言·c++·算法·1024程序员节
dragoooon3412 小时前
[优选算法专题五.位运算——常见位运算总结及NO.33~34判定字符是否唯一、丢失的数字]
1024程序员节