如何使用Python访问笔记本电脑的内置红外网络摄像头?

问题描述 投票:0回答:3

我正在尝试在 python 项目中访问笔记本电脑的内置红外网络摄像头(用于 windows hello)。我可以使用 OpenCV 中的 VideoCapture 类轻松访问普通 RGB 摄像头,但是找不到访问红外摄像头的方法。我尝试将不同的索引传递给 VideoCapture 类,但是只有“0”有效,这是正常的网络摄像头。

有多种方法可以使用 Windows API 来执行此操作,但是我找不到在 Python 中访问它的方法。

有些人已经能够使用 fswebcam 访问 Ubuntu 上的 windows hello 相机。

有没有办法使用python访问红外摄像头?也许有某种使用 pywin32 与 Windows API 交互的方式?任何开始使用此功能的帮助将不胜感激。或者,有没有类似于 Windows 版 fswebcam 的东西可以让我做同样的事情?

python api opencv computer-vision
3个回答
3
投票

您提供的那个示例似乎没有使用 win32 api,而是使用 dotnet 框架,特别是 Windows.Media.Capture.Frames.MediaFrameSourceGroup 类。

看起来您将能够使用 http://pythonnet.github.io/ 访问 dotnet 框架。之后,应该将 C# 代码移植到 Python。


1
投票

您需要访问 WinRT API,而不是 Win32 API。

使用此库:https://github.com/Microsoft/xlang/tree/master/src/package/pywinrt/projection,您应该能够从您发布的代码中调用 WinRT 中的必要部分。


0
投票

我有点晚了,但也许我可以帮助别人。您可以通过 WinRT 访问红外摄像头。如果您想使用 Python 来完成此操作,则应使用维护的 winrt 替代方案 winsdk

我遵循了本教程:使用 MediaFrameReader 处理媒体帧

我跳过并简化了代码的某些部分,但它确实完成了工作。捕获的帧显示在 OpenCV 窗口中。您可以按“q”退出。

您必须注意脚本中的两个常量。

camera_image_width
camera_image_height
定义捕获帧的分辨率。对于我的硬件,它们是 640 和 360。我不知道这是否是预览相机的标准分辨率,对于其他硬件,它们可能有所不同。您可以通过在第 88 行之后调用
software_bitmap.pixel_height
software_bitmap.pixel_height
来确定它们。

必须安装以下Python包:

  • 异步
  • numpy
  • opencv-python
  • winsdk

这是整个脚本:

import asyncio
import time
import numpy as np

import cv2

from winsdk.windows.media.capture import MediaStreamType
from winsdk.windows.media.capture import MediaCapture
from winsdk.windows.media.capture import MediaCaptureInitializationSettings
from winsdk.windows.media.capture import MediaCaptureSharingMode
from winsdk.windows.media.capture import MediaCaptureMemoryPreference
from winsdk.windows.media.capture import StreamingCaptureMode

from winsdk.windows.media.capture.frames import MediaFrameSourceGroup
from winsdk.windows.media.capture.frames import MediaFrameSourceInfo
from winsdk.windows.media.capture.frames import MediaFrameSourceKind
from winsdk.windows.media.capture.frames import MediaFrameReader

from winsdk.windows.graphics.imaging import SoftwareBitmap
from winsdk.windows.graphics.imaging import BitmapPixelFormat

from winsdk.windows.storage.streams import Buffer

camera_image_width = 640
camera_image_height = 360

async def main():
    #####  Find the first infra source group  #####

    media_frame_source_groups = await MediaFrameSourceGroup.find_all_async()

    infra_source_group: MediaFrameSourceGroup
    infra_source_info: MediaFrameSourceInfo

    # Iterating through source groups
    for source_group in media_frame_source_groups:
        for source_info in source_group.source_infos:
            if source_info.media_stream_type == MediaStreamType.VIDEO_PREVIEW and source_info.source_kind == MediaFrameSourceKind.INFRARED:
                infra_source_group = source_group
                infra_source_info = source_info

    # Check if there's available infra source
    if infra_source_group is None or infra_source_info is None:
        print("No infra source was found!")
        return

    #####  Getting frames from infra camera  #####

    with MediaCapture() as media_capture:
        # Settings for MediaCapture object
        media_capture_settings = MediaCaptureInitializationSettings()
        media_capture_settings.source_group = infra_source_group
        media_capture_settings.sharing_mode = MediaCaptureSharingMode.EXCLUSIVE_CONTROL
        media_capture_settings.memory_preference = MediaCaptureMemoryPreference.CPU
        media_capture_settings.streaming_capture_mode = StreamingCaptureMode.VIDEO
        await media_capture.initialize_async(media_capture_settings)

        # Init frame reader
        media_frame_reader: MediaFrameReader = await media_capture.create_frame_reader_async(media_capture.frame_sources[infra_source_info.id])
        await media_frame_reader.start_async()

        # Each frame must be dumped into a buffer
        frame_buffer = Buffer(camera_image_width * camera_image_height * 4)

        # Wait for frames
        while True:
            # Capturing with 20fps
            time.sleep(0.05)

            # Get the latest available frame
            media_frame_reference = media_frame_reader.try_acquire_latest_frame()

            # If the frame is null, skip this cycle
            if media_frame_reference is None:
                continue

            # Try to read frame
            with media_frame_reference:
                # Boilerplate bullshit to extract bitmap data
                video_media_frame = media_frame_reference.video_media_frame

                if video_media_frame is None:
                    return
                
                software_bitmap = video_media_frame.software_bitmap

                if software_bitmap is None:
                    return
                
                #####  The bitmap is just fine  #####

                with software_bitmap:
                    # Convert image format
                    grayscale_bitmap = SoftwareBitmap.convert(software_bitmap, BitmapPixelFormat.RGBA8)

                    # Dump image data to byte buffer
                    grayscale_bitmap.copy_to_buffer(frame_buffer)
                    
                    # Create actual OpenCV image from byte buffer
                    image_array = np.frombuffer(frame_buffer, dtype=np.uint8).reshape(camera_image_height, camera_image_width, 4)

                    # If the image is all black, skip showing
                    if cv2.countNonZero(cv2.cvtColor(image_array, cv2.COLOR_RGBA2GRAY)) == 0:
                        continue
                    
                    cv2.imshow('Infrared camera', image_array)
                    
                    if cv2.waitKey(1) == ord('q'):
                        break

        cv2.destroyAllWindows()

asyncio.run(main())

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.