You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用OpenCV的情况下用Python捕获摄像头画面

替代OpenCV捕获摄像头单帧的轻量方案

以下方案均无需依赖OpenCV,编译后文件体积可控,分平台实现:

Windows平台(基于pywin32 + Pillow)

依赖仅为pywin32和Pillow,两者体积远小于OpenCV。示例代码:

import win32video
from PIL import Image
import numpy as np

# 枚举摄像头设备
def get_camera_device():
    devices = win32video.videoInput()
    device_count = devices.listDevices()
    if device_count == 0:
        raise Exception("未检测到摄像头")
    # 返回第一个摄像头设备索引
    return 0

# 捕获单帧
def capture_frame(device_idx):
    devices = win32video.videoInput()
    devices.setupDevice(device_idx)
    # 获取帧数据
    width, height = devices.getWidth(device_idx), devices.getHeight(device_idx)
    frame_data = np.zeros((height, width, 3), dtype=np.uint8)
    devices.getImage(device_idx, frame_data.ctypes.data, width, height, 3)
    devices.stopDevice(device_idx)
    # 转换为PIL Image并保存
    img = Image.fromarray(frame_data)
    img.save("captured_frame.jpg")

if __name__ == "__main__":
    cam_idx = get_camera_device()
    capture_frame(cam_idx)

安装依赖:pip install pywin32 pillow

Linux平台(基于V4L2原生API)

直接调用Linux内核的V4L2接口,仅需标准库和numpy(可选,也可手动处理字节流)。示例代码:

import os
import fcntl
import mmap
import numpy as np
from PIL import Image

# V4L2常量定义
VIDIOC_S_FMT = 0xc00c5605
VIDIOC_REQBUFS = 0xc0085608
VIDIOC_QUERYBUF = 0x80085609
VIDIOC_QBUF = 0xc008560a
VIDIOC_DQBUF = 0x8008560b
VIDIOC_STREAMON = 0x40045607

def capture_frame():
    # 打开摄像头设备(通常为/dev/video0)
    fd = os.open("/dev/video0", os.O_RDWR)
    
    # 设置格式为RGB24
    fmt = {
        "type": 1,  # V4L2_BUF_TYPE_VIDEO_CAPTURE
        "width": 640,
        "height": 480,
        "pixelformat": 0x32344752,  # RGB24
        "field": 0,
        "bytesperline": 640*3,
        "sizeimage": 640*480*3,
        "colorspace": 0,
    }
    fcntl.ioctl(fd, VIDIOC_S_FMT, fmt)
    
    # 请求缓冲区
    reqbufs = {"count": 1, "type": 1, "memory": 1}  # V4L2_MEMORY_MMAP
    fcntl.ioctl(fd, VIDIOC_REQBUFS, reqbufs)
    
    # 查询缓冲区
    buf = {"index": 0, "type": 1, "memory": 1, "length": 0, "offset": 0}
    fcntl.ioctl(fd, VIDIOC_QUERYBUF, buf)
    
    # 映射缓冲区
    mm = mmap.mmap(fd, buf["length"], mmap.MAP_SHARED, mmap.PROT_READ, offset=buf["offset"])
    
    # 入队缓冲区并启动流
    fcntl.ioctl(fd, VIDIOC_QBUF, buf)
    fcntl.ioctl(fd, VIDIOC_STREAMON, 1)
    
    # 出队获取帧
    fcntl.ioctl(fd, VIDIOC_DQBUF, buf)
    frame_data = np.frombuffer(mm, dtype=np.uint8).reshape(480, 640, 3)
    
    # 停止流并清理
    fcntl.ioctl(fd, VIDIOC_STREAMON, 0)
    mm.close()
    os.close(fd)
    
    # 保存帧
    img = Image.fromarray(frame_data)
    img.save("captured_frame.jpg")

if __name__ == "__main__":
    capture_frame()

依赖安装:pip install numpy pillow(若手动处理字节流可无需numpy)

macOS平台(基于PyObjC调用AVFoundation)

利用苹果原生AVFoundation框架,依赖仅为pyobjc-core和pyobjc-framework-AVFoundation,体积轻量。示例代码:

import objc
import time
from AVFoundation import (
    AVCaptureSession, AVCaptureDevice, AVCaptureDeviceInput,
    AVCapturePhotoOutput, AVCapturePhotoSettings
)
from PIL import Image
from Foundation import NSData

def capture_frame():
    # 创建捕获会话
    session = AVCaptureSession.alloc().init()
    session.setSessionPreset_(AVCaptureSession.PresetPhoto)
    
    # 获取默认摄像头
    device = AVCaptureDevice.defaultDeviceWithMediaType_("vide")
    input_device = AVCaptureDeviceInput.deviceInputWithDevice_error_(device, None)[0]
    session.addInput_(input_device)
    
    # 设置照片输出
    photo_output = AVCapturePhotoOutput.alloc().init()
    session.addOutput_(photo_output)
    
    # 定义回调处理捕获的照片
    capture_done = False
    class PhotoCaptureDelegate(objc.NSObject):
        def captureOutput_didFinishProcessingPhoto_error_(self, output, photo, error):
            nonlocal capture_done
            if error:
                print(f"捕获失败: {error}")
                capture_done = True
                return
            # 获取图片数据并保存
            image_data = photo.fileDataRepresentation()
            image_data.writeToFile_atomically_("captured_frame.jpg", True)
            session.stopRunning()
            capture_done = True
    
    delegate = PhotoCaptureDelegate.alloc().init()
    settings = AVCapturePhotoSettings.photoSettings()
    
    # 启动会话并捕获照片
    session.startRunning()
    photo_output.capturePhotoWithSettings_delegate_(settings, delegate)
    
    # 等待捕获完成
    while not capture_done:
        time.sleep(0.1)

if __name__ == "__main__":
    capture_frame()

安装依赖:pip install pyobjc-core pyobjc-framework-AVFoundation pillow

编译体积优化建议

使用PyInstaller编译时,可通过以下方式进一步缩小体积:

  • 使用--exclude-module排除未使用的模块,比如--exclude-module numpy(若代码中未用到)
  • 启用UPX压缩:pyinstaller --onefile --upx-dir /path/to/upx your_script.py
  • 使用--clean参数清理临时文件,避免冗余依赖打包

内容的提问来源于stack exchange,提问作者Dr. Dark Flames

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:25:14