鱼C论坛

 找回密码
 立即注册
查看: 1807|回复: 2

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

[复制链接]
发表于 2023-8-20 14:24:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
格式是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函数进行修改的示例代码:

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

  3. // ...

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

  7.     HRESULT hr = pSample->GetPointer(&ptrBuffer);
  8.     if (hr == S_OK) {
  9.         latestBufferLength = pSample->GetActualDataLength();
  10.         if (latestBufferLength == numBytes) {
  11.             EnterCriticalSection(&critSection);

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

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

  18.             newFrame = true;
  19.             freezeCheck = 1;

  20.             LeaveCriticalSection(&critSection);
  21.             SetEvent(hEvent);
  22.         }
  23.         else {
  24.             printf("ERROR: SampleCB() - buffer sizes do not match\n");
  25.         }
  26.     }

  27.     // ...
  28. }
复制代码


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

请确保已正确安装和配置了OpenCV库,并在代码中包含了必要的OpenCV头文件和库路径。
如果问题已经解决,请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-8-20 14:25:55 | 显示全部楼层    本楼为最佳答案   
要对每一帧进行缩放操作,您可以使用OpenCV库来实现。以下是对SampleCB函数进行修改的示例代码:

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

  3. // ...

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

  7.     HRESULT hr = pSample->GetPointer(&ptrBuffer);
  8.     if (hr == S_OK) {
  9.         latestBufferLength = pSample->GetActualDataLength();
  10.         if (latestBufferLength == numBytes) {
  11.             EnterCriticalSection(&critSection);

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

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

  18.             newFrame = true;
  19.             freezeCheck = 1;

  20.             LeaveCriticalSection(&critSection);
  21.             SetEvent(hEvent);
  22.         }
  23.         else {
  24.             printf("ERROR: SampleCB() - buffer sizes do not match\n");
  25.         }
  26.     }

  27.     // ...
  28. }
复制代码


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

请确保已正确安装和配置了OpenCV库,并在代码中包含了必要的OpenCV头文件和库路径。
如果问题已经解决,请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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来实现缩放:

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

  3. IBaseFilter* CreateTransformFilter()
  4. {
  5.     IBaseFilter* pTransformFilter = NULL;
  6.     CoCreateInstance(CLSID_LegacyAmFilterCategory, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pTransformFilter);
  7.     return pTransformFilter;
  8. }

  9. void ConfigureTransformFilter(IBaseFilter* pTransformFilter)
  10. {
  11.     ITransformFilter* pTransform = NULL;
  12.     pTransformFilter->QueryInterface(IID_ITransformFilter, (void**)&pTransform);
  13.    
  14.     // 设置输入和输出格式
  15.     AM_MEDIA_TYPE mtInput, mtOutput;
  16.     ZeroMemory(&mtInput, sizeof(AM_MEDIA_TYPE));
  17.     ZeroMemory(&mtOutput, sizeof(AM_MEDIA_TYPE));
  18.    
  19.     mtInput.majortype = MEDIATYPE_Video;
  20.     mtInput.subtype = MEDIASUBTYPE_MJPG;
  21.     mtInput.formattype = FORMAT_VideoInfo;
  22.     mtInput.bFixedSizeSamples = TRUE;
  23.     mtInput.lSampleSize = 0;
  24.     mtInput.cbFormat = sizeof(VIDEOINFOHEADER);
  25.    
  26.     VIDEOINFOHEADER* pviInput = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
  27.     ZeroMemory(pviInput, sizeof(VIDEOINFOHEADER));
  28.     pviInput->bmiHeader.biWidth = 1920;
  29.     pviInput->bmiHeader.biHeight = 1080;
  30.     pviInput->bmiHeader.biPlanes = 1;
  31.     pviInput->bmiHeader.biBitCount = 24;
  32.     pviInput->bmiHeader.biCompression = MAKEFOURCC('M', 'J', 'P', 'G');
  33.     mtInput.pbFormat = (BYTE*)pviInput;
  34.    
  35.     mtOutput.majortype = MEDIATYPE_Video;
  36.     mtOutput.subtype = MEDIASUBTYPE_RGB24;
  37.     mtOutput.formattype = FORMAT_VideoInfo;
  38.     mtOutput.bFixedSizeSamples = TRUE;
  39.     mtOutput.lSampleSize = 0;
  40.     mtOutput.cbFormat = sizeof(VIDEOINFOHEADER);
  41.    
  42.     VIDEOINFOHEADER* pviOutput = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
  43.     ZeroMemory(pviOutput, sizeof(VIDEOINFOHEADER));
  44.     pviOutput->bmiHeader.biWidth = 320;
  45.     pviOutput->bmiHeader.biHeight = 240;
  46.     pviOutput->bmiHeader.biPlanes = 1;
  47.     pviOutput->bmiHeader.biBitCount = 24;
  48.     pviOutput->bmiHeader.biCompression = BI_RGB;
  49.     mtOutput.pbFormat = (BYTE*)pviOutput;
  50.    
  51.     pTransform->SetMediaType(0, &mtInput);
  52.     pTransform->SetMediaType(1, &mtOutput);
  53.    
  54.     CoTaskMemFree(pviInput);
  55.     CoTaskMemFree(pviOutput);
  56.    
  57.     pTransform->Release();
  58. }

  59. void ProcessFrame(IMediaSample* pSample)
  60. {
  61.     // 获取原始帧数据
  62.     BYTE* ptrBuffer = NULL;
  63.     pSample->GetPointer(&ptrBuffer);
  64.     DWORD bufferSize = pSample->GetSize();
  65.    
  66.     // 创建Filter Graph实例
  67.     IGraphBuilder* pGraphBuilder = NULL;
  68.     CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraphBuilder);
  69.    
  70.     // 创建摄像头捕获的数据流
  71.     IBaseFilter* pCaptureFilter = NULL;
  72.     pGraphBuilder->AddFilter(pCaptureFilter, L"Capture Filter");
  73.    
  74.     // 创建缩放滤镜
  75.     IBaseFilter* pTransformFilter = CreateTransformFilter();
  76.     ConfigureTransformFilter(pTransformFilter);
  77.     pGraphBuilder->AddFilter(pTransformFilter, L"Transform Filter");
  78.    
  79.     // 连接滤镜
  80.     pGraphBuilder->ConnectDirect(GetPin(pCaptureFilter, PINDIR_OUTPUT), GetPin(pTransformFilter, PINDIR_INPUT), NULL);
  81.    
  82.     // 运行图形
  83.     IMediaControl* pMediaControl = NULL;
  84.     pGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&pMediaControl);
  85.     pMediaControl->Run();
  86.    
  87.     // 等待滤镜处理完帧
  88.     Sleep(100);
  89.    
  90.     // 从滤镜的输出端口获取缩放后的数据
  91.     IPin* pOutputPin = GetPin(pTransformFilter, PINDIR_OUTPUT);
  92.     IMemInputPin* pInputPin = NULL;
  93.     pOutputPin->QueryInterface(IID_IMemInputPin, (void**)&pInputPin);
  94.    
  95.     BYTE* pScaledBuffer = NULL;
  96.     DWORD scaledBufferSize = 0;
  97.    
  98.     pInputPin->Receive(ptrBuffer, bufferSize);
  99.     pInputPin->GetBuffer(&pScaledBuffer, &scaledBufferSize);
  100.    
  101.     // 处理缩放后的数据
  102.     // ...
  103.    
  104.     // 释放资源
  105.     pInputPin->Release();
  106.     pMediaControl->Stop();
  107.     pGraphBuilder->Release();
  108. }
复制代码


请注意,这只是一个示例实现,并且可能需要根据您的具体需求进行修改和调整。另外,由于DirectShow已经过时,您可能希望考虑使用更现代的多媒体框架,如Media Foundation或OpenCV来处理摄像头采集数据。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 02:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表