xianyubbt 发表于 2023-8-20 14:24:47

大佬directshow 摄像头采集如何对每新到的一帧缩放大小?

格式是MJPG 1920*1080 摄像头捕获格式
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample){
            if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) return S_OK;

            HRESULT hr = pSample->GetPointer(&ptrBuffer);//新帧地址
            怎么处理ptrBuffer缩放采集帧大小,需要从1920*1080压缩到320*240                 
            if(hr == S_OK){
                  latestBufferLength = pSample->GetActualDataLength();                         
                      if(latestBufferLength == numBytes){
                                EnterCriticalSection(&critSection);
                               
                                memcpy(pixels, ptrBuffer, latestBufferLength);
                               
                                        newFrame        = true;
                                        freezeCheck = 1;
                                LeaveCriticalSection(&critSection);
                                SetEvent(hEvent);
                       
                        }else{
                                printf("ERROR: SampleCB() - buffer sizes do not match\n");
                        }
                }

陶远航 发表于 2023-8-20 14:25:55

要对每一帧进行缩放操作,您可以使用OpenCV库来实现。以下是对SampleCB函数进行修改的示例代码:

#include "opencv2/opencv.hpp"
#include <iostream>

// ...

STDMETHODIMP SampleCB(double Time, IMediaSample *pSample) {
    if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
      return S_OK;

    HRESULT hr = pSample->GetPointer(&ptrBuffer);
    if (hr == S_OK) {
      latestBufferLength = pSample->GetActualDataLength();
      if (latestBufferLength == numBytes) {
            EnterCriticalSection(&critSection);

            // 使用OpenCV进行缩放
            cv::Mat frame(1080, 1920, CV_8UC3, ptrBuffer); // 创建输入帧
            cv::Mat resizedFrame;
            cv::resize(frame, resizedFrame, cv::Size(320, 240), 0, 0, cv::INTER_LINEAR); // 缩放到320*240

            // 将缩放后的帧复制到pixels数组
            memcpy(pixels, resizedFrame.data, resizedFrame.total() * resizedFrame.elemSize());

            newFrame = true;
            freezeCheck = 1;

            LeaveCriticalSection(&critSection);
            SetEvent(hEvent);
      }
      else {
            printf("ERROR: SampleCB() - buffer sizes do not match\n");
      }
    }

    // ...
}


需要注意的是,此示例假设您已经正确设置了临界区(critical section)和相关的全局变量。另外,它使用OpenCV的cv::resize函数将输入帧缩放为所需的大小,并将缩放后的帧数据复制到pixels数组中。

请确保已正确安装和配置了OpenCV库,并在代码中包含了必要的OpenCV头文件和库路径。
如果问题已经解决,请设置最佳答案

isdkz 发表于 2023-8-20 14:28:38

您可以使用DirectShow的图像处理滤镜来对每一帧进行缩放。以下是一种可能的实现方式:

1. 创建一个图像处理滤镜的实例。您可以使用DirectShow提供的现有滤镜,如Transform Filter或Resize Filter,也可以自定义一个滤镜。

2. 配置滤镜的输入和输出格式。将输入格式设置为原始帧的格式(MJPG 1920*1080),将输出格式设置为所需的缩放大小(320*240)。

3. 将滤镜添加到DirectShow图形中。您需要创建一个Filter Graph实例,并将摄像头捕获的数据流连接到滤镜的输入端口。

4. 处理每个新帧。在SampleCB方法中,您可以使用滤镜来处理ptrBuffer中的数据。您需要将数据传递给滤镜的输入端口,并从滤镜的输出端口获取缩放后的数据。

下面是一个示例代码片段,演示如何使用DirectShow的Transform Filter来实现缩放:

#include <dshow.h>
#include <d3d9.h>

IBaseFilter* CreateTransformFilter()
{
    IBaseFilter* pTransformFilter = NULL;
    CoCreateInstance(CLSID_LegacyAmFilterCategory, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pTransformFilter);
    return pTransformFilter;
}

void ConfigureTransformFilter(IBaseFilter* pTransformFilter)
{
    ITransformFilter* pTransform = NULL;
    pTransformFilter->QueryInterface(IID_ITransformFilter, (void**)&pTransform);
   
    // 设置输入和输出格式
    AM_MEDIA_TYPE mtInput, mtOutput;
    ZeroMemory(&mtInput, sizeof(AM_MEDIA_TYPE));
    ZeroMemory(&mtOutput, sizeof(AM_MEDIA_TYPE));
   
    mtInput.majortype = MEDIATYPE_Video;
    mtInput.subtype = MEDIASUBTYPE_MJPG;
    mtInput.formattype = FORMAT_VideoInfo;
    mtInput.bFixedSizeSamples = TRUE;
    mtInput.lSampleSize = 0;
    mtInput.cbFormat = sizeof(VIDEOINFOHEADER);
   
    VIDEOINFOHEADER* pviInput = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
    ZeroMemory(pviInput, sizeof(VIDEOINFOHEADER));
    pviInput->bmiHeader.biWidth = 1920;
    pviInput->bmiHeader.biHeight = 1080;
    pviInput->bmiHeader.biPlanes = 1;
    pviInput->bmiHeader.biBitCount = 24;
    pviInput->bmiHeader.biCompression = MAKEFOURCC('M', 'J', 'P', 'G');
    mtInput.pbFormat = (BYTE*)pviInput;
   
    mtOutput.majortype = MEDIATYPE_Video;
    mtOutput.subtype = MEDIASUBTYPE_RGB24;
    mtOutput.formattype = FORMAT_VideoInfo;
    mtOutput.bFixedSizeSamples = TRUE;
    mtOutput.lSampleSize = 0;
    mtOutput.cbFormat = sizeof(VIDEOINFOHEADER);
   
    VIDEOINFOHEADER* pviOutput = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
    ZeroMemory(pviOutput, sizeof(VIDEOINFOHEADER));
    pviOutput->bmiHeader.biWidth = 320;
    pviOutput->bmiHeader.biHeight = 240;
    pviOutput->bmiHeader.biPlanes = 1;
    pviOutput->bmiHeader.biBitCount = 24;
    pviOutput->bmiHeader.biCompression = BI_RGB;
    mtOutput.pbFormat = (BYTE*)pviOutput;
   
    pTransform->SetMediaType(0, &mtInput);
    pTransform->SetMediaType(1, &mtOutput);
   
    CoTaskMemFree(pviInput);
    CoTaskMemFree(pviOutput);
   
    pTransform->Release();
}

void ProcessFrame(IMediaSample* pSample)
{
    // 获取原始帧数据
    BYTE* ptrBuffer = NULL;
    pSample->GetPointer(&ptrBuffer);
    DWORD bufferSize = pSample->GetSize();
   
    // 创建Filter Graph实例
    IGraphBuilder* pGraphBuilder = NULL;
    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraphBuilder);
   
    // 创建摄像头捕获的数据流
    IBaseFilter* pCaptureFilter = NULL;
    pGraphBuilder->AddFilter(pCaptureFilter, L"Capture Filter");
   
    // 创建缩放滤镜
    IBaseFilter* pTransformFilter = CreateTransformFilter();
    ConfigureTransformFilter(pTransformFilter);
    pGraphBuilder->AddFilter(pTransformFilter, L"Transform Filter");
   
    // 连接滤镜
    pGraphBuilder->ConnectDirect(GetPin(pCaptureFilter, PINDIR_OUTPUT), GetPin(pTransformFilter, PINDIR_INPUT), NULL);
   
    // 运行图形
    IMediaControl* pMediaControl = NULL;
    pGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&pMediaControl);
    pMediaControl->Run();
   
    // 等待滤镜处理完帧
    Sleep(100);
   
    // 从滤镜的输出端口获取缩放后的数据
    IPin* pOutputPin = GetPin(pTransformFilter, PINDIR_OUTPUT);
    IMemInputPin* pInputPin = NULL;
    pOutputPin->QueryInterface(IID_IMemInputPin, (void**)&pInputPin);
   
    BYTE* pScaledBuffer = NULL;
    DWORD scaledBufferSize = 0;
   
    pInputPin->Receive(ptrBuffer, bufferSize);
    pInputPin->GetBuffer(&pScaledBuffer, &scaledBufferSize);
   
    // 处理缩放后的数据
    // ...
   
    // 释放资源
    pInputPin->Release();
    pMediaControl->Stop();
    pGraphBuilder->Release();
}


请注意,这只是一个示例实现,并且可能需要根据您的具体需求进行修改和调整。另外,由于DirectShow已经过时,您可能希望考虑使用更现代的多媒体框架,如Media Foundation或OpenCV来处理摄像头采集数据。
页: [1]
查看完整版本: 大佬directshow 摄像头采集如何对每新到的一帧缩放大小?