简体   繁体   English

在Windows(C ++)中从USB相机拍摄高分辨率照片

[英]Take high resolution photo from USB camera in Windows (C++)

I am developing an C++ application which should use an USB camera to capture high resolution photos. 我正在开发一个C ++应用程序,该应用程序应使用USB相机捕获高分辨率照片。 It should have same behavior as the Camera application in Windows 10. I am trying to use DirectShow for doing it. 它的行为应与Windows 10中的“相机”应用程序相同。我正在尝试使用DirectShow。 Now I am only able to take high resolution photo which is delayed or take a photo in time but low resolution. 现在,我只能拍摄延迟的高分辨率照片,或者只能及时拍摄但分辨率低的照片。 Also I am very confused from MS documentation, lot of things are deprecated and nowhere mentioned what replaces them. 另外,我对MS文档感到非常困惑,不赞成使用许多功能,没有地方提到用什么代替它们。 I'll describe my hopeless steps awaiting there will be somebody who could be able to show me a way. 我将描述我绝望的步骤,等待有可能向我展示方法的人。

Let's start from beginning... 让我们从头开始...

Knowing nothing about video capturing in Window I started by searching suitable library. 我对Window中的视频捕获一无所知,我从搜索合适的库开始。 After some googling I found there are four main libraries for capturing video in Windows. 经过一番谷歌搜索后,我发现有四个用于在Windows中捕获视频的主要库。

  1. Video for Windows Windows视频
  2. DirectShow DirectShow的
  3. Windows Media Foundation Windows Media基础
  4. OpenCV OpenCV的

Let's observe: 让我们观察一下:

  1. Video for Windows Windows视频
    This library is unfortunately marked as deprecated but it seems it still works. 不幸的是,该库已被标记为已弃用,但似乎仍然可以使用。 I have written "unfortunately", because I think this is the only which is easy to use. 我写了“不幸的是”,因为我认为这是唯一易于使用的。 There are only a few lines of code needed for seeing video from camera. 从摄像机观看视频仅需几行代码。 The only think I miss here is a "TakePhoto" function. 我唯一想念的是“ TakePhoto”功能。 You can use VFW for capture a video or single frames to an avi file. 您可以使用VFW将视频或单个帧捕获到avi文件。 Or am I missing something? 还是我错过了什么?

  2. DirectShow DirectShow的
    This is much more complicated library. 这个库要复杂得多。 You need hundreds of lines of code to see a video preview. 您需要数百行代码才能查看视频预览。 But you can obtain this code on MS Docs. 但是您可以在MS Docs上获得此代码。 Ok, now I have a video preview and I need only to take a photo. 好的,现在我有了视频预览,我只需要拍照。 One would expect this should be just one function call. 有人希望这应该只是一个函数调用。 But where is the function? 但是功能在哪里? I did not find it. 我没找到。

You can simply use GetCurrentImage from IVMRWindowlessControl but this takes only one frame from preview with low resolution. 您可以简单地使用IVMRWindowlessControl GetCurrentImage ,但这仅以低分辨率从预览中获取一帧。 If you set a higher resolution for preview the video is not fluent. 如果为预览设置更高的分辨率,则视频不流畅。

Best approach I could achieve is from an article called "Capturing an Image From a Still Image Pin" available here https://docs.microsoft.com/en-us/windows/desktop/directshow/capturing-an-image-from-a-still-image-pin . 我可以实现的最佳方法是来自一篇名为“从静止图像图钉捕获图像”的文章, 网址为https://docs.microsoft.com/en-us/windows/desktop/directshow/capturing-an-image-from-静止图像引脚 When I had found this site I thought I won and my task was almost finished. 当我找到这个站点时,我以为我赢了,我的任务几乎完成了。 But it wasn't. 但事实并非如此。

The first advice which the article gives you is not to use it: "The recommended way to get still images from the device is to use the Windows Image Acquisition (WIA) APIs. For more information, see "Windows Image Acquisition" in the Platform SDK documentation. However, you can also use DirectShow to capture an image." 本文为您提供的第一个建议是不要使用它: “从设备获取静止图像的推荐方法是使用Windows Image Acquisition(WIA)API。有关更多信息,请参见平台中的“ Windows Image Acquisition”。 SDK文档。不过,您也可以使用DirectShow捕获图像。” I tried to explore the WIA. 我试图探索WIA。 But this stopped to work on Vista. 但这已停止在Vista上运行。 I continued to study the article. 我继续研究这篇文章。
Everything seems to be clear but you need to implement your class which inherits ISampleGrabberCB marked as deprecated here https://docs.microsoft.com/en-us/windows/desktop/directshow/isamplegrabbercb . 一切似乎都很清楚,但是您需要实现继承ISampleGrabberCB的类, ISampleGrabberCB在此处https://docs.microsoft.com/zh-cn/windows/desktop/directshow/isamplegrabbercb标记为已弃用。 Why???? 为什么???? Where to find some alternative? 在哪里找到替代方案?
I found an acceptable solution here https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/2ab5c212-5824-419d-b5d9-7f5db82f57cd/qedith-missing-in-current-windows-sdk-v70?forum=windowsdirectshowdevelopment . 我在这里找到了可接受的解决方案https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/2ab5c212-5824-419d-b5d9-7f5db82f57cd/qedith-missing-in-current-windows-sdk-v70? forum = windowsdirectshowdevelopment You need to add header file from elder SDK. 您需要从旧版SDK添加头文件。 (BTW This is an advice almost ten years old.) After I compiled the application with this header I was able to read high resolution picture but I need to wait a few seconds which is unacceptable. (顺便说一句,这是将近十年的建议。)在使用此标头编译应用程序之后,我能够读取高分辨率图片,但是我需要等待几秒钟,这是不可接受的。 I know the problem is not in camera, because in the it works in the Camera application. 我知道问题不在相机中,因为它可以在相机应用程序中使用。 Furthermore the image is obtained in function SampleCB instead of BufferCB and is in some strange format. 此外,图像是通过函数SampleCB而不是BufferCB获得的,并且格式有些奇怪。 I can save it as jpg but it is not compressed enough. 我可以将其另存为jpg,但压缩程度不足。

  1. Windows Media Foundation Windows Media基础
    I think MS doesn't like programmers and that's why it released WMF. 我认为MS不喜欢程序员,这就是为什么它发布了WMF。 I understand nothing. 我完全不懂。 I found this tutorial https://www.dreamincode.net/forums/topic/347938-a-new-webcam-api-tutorial-in-c-for-windows/ . 我找到了本教程https://www.dreamincode.net/forums/topic/347938-a-new-webcam-api-tutorial-in-c-for-windows/ It works but it only stores one frame from preview and this is not what I want. 它可以工作,但是只能存储预览中的一帧,这不是我想要的。
    Next I explored some WMF interfaces on MS Docs. 接下来,我探讨了MS Docs上的一些WMF接口。 IMFCapturePhotoSink interface should do the stuff. IMFCapturePhotoSink接口应该做的事情。 But how implement it. 但是如何实施。 The documentation is useless. 该文档是无用的。

  2. OpenCV OpenCV的
    During my research I found also this library. 在研究过程中,我也找到了这个库。 But again I'm not able to take a high resolution photo. 但是我又不能拍高分辨率的照片。 It only stores one frame from preview. 它仅存储预览中的一帧。

Could someone tell me what should I focus on? 有人可以告诉我我应该关注什么吗? I believe it cannot be so difficult. 我相信这不会那么困难。 There are tens and hundreds of applications for webcams. 网络摄像头有成千上万的应用程序。 How could other programmers implement them? 其他程序员如何实现它们? What's wrong with me? 我怎么了 I'd like to find an easy way to implement an easy task. 我想找到一种简单的方法来执行简单的任务。 Thank a lot for any help. 非常感谢您的帮助。

You question is not related to the topic - the question must be related to the code - but I faced with the similar problem many years ago and I had found solution: 您的问题与主题无关-该问题必须与代码相关-但是很多年前我遇到了类似的问题,并且找到了解决方案:

DirectShow is declared as deprecated for Windows 10 and it has problem with supporting of the USB web cam. DirectShow声明为Windows 10不推荐使用,并且在支持USB网络摄像头方面存在问题。 In Windows 10 there is USB Video Class which is supported only by Media Foundation. 在Windows 10中,只有Media Foundation支持USB Video Class。

So, I have wrote a simple C++ wrapper around Media Foundation code which simplify getting of the raw images Capturing Video from Web-camera on Windows 7 and 8 by using Media Foundation 因此,我围绕Media Foundation代码编写了一个简单的C ++包装器,该代码简化了使用Media Foundation在Windows 7和8上从Web摄像头捕获视频的原始图像获取过程。

Also, there is project CaptureManager SDK - it is DLL COM component with the simple interfaces, huge functionality and with many demo programs on C++, Python, C#, Java. 此外,还有一个项目CaptureManager SDK-它是DLL COM组件,具有简单的界面,强大的功能以及许多基于C ++,Python,C#,Java的演示程序。

Thanks to Evgeny. 感谢Evgeny。

Recapitulation: 概括:

  1. Download the CaptureEngine video capture sample 下载CaptureEngine视频捕获样本

  2. Edit CaptureManager::TakePhoto method. 编辑CaptureManager::TakePhoto方法。 Add the code to find highest resolution media type just before CreatePhotoMediaType(pMediaType, &pMediaType2); CreatePhotoMediaType(pMediaType, &pMediaType2);之前添加代码以查找最高分辨率的媒体类型CreatePhotoMediaType(pMediaType, &pMediaType2); line 线

Extra code for setup the photo stream to highest resolution: 用于将照片流设置为最高分辨率的额外代码:

DWORD dwMediaTypeIndex = 0;
UINT32 maxSize = 0;
DWORD maxSizeIndex = 0;
while (1) {
    IMFMediaType* pMediaType = NULL;
    hr = pSource->GetAvailableDeviceMediaType((DWORD)MF_CAPTURE_ENGINE_PREFERRED_SOURCE_STREAM_FOR_PHOTO, dwMediaTypeIndex, &pMediaType);
    if (hr == MF_E_NO_MORE_TYPES)
        break;

    UINT32 w, h;
    MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &w, &h);
    UINT32 size = w * h;
    if (size > maxSize) {
        maxSize = size;
        maxSizeIndex = dwMediaTypeIndex;
    }
    SafeRelease(&pMediaType);
    dwMediaTypeIndex++;
}

SafeRelease(&pMediaType);
pSource->GetAvailableDeviceMediaType((DWORD)MF_CAPTURE_ENGINE_PREFERRED_SOURCE_STREAM_FOR_PHOTO, maxSizeIndex, &pMediaType);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM