Я занимаюсь разработкой приложения на C ++, которое должно использовать USB-камеру для съемки фотографий с высоким разрешением. Оно должно иметь такое же поведение, как и приложение Camera в Windows 10. Я пытаюсь использовать DirectShow для этого. Теперь я могу делать только снимки с высоким разрешением, которые задерживаются, или снимать во времени, но с низким разрешением. Также я очень запутался в документации MS, многие вещи устарели и нигде не упоминается, что их заменяет. Я опишу мои безнадежные шаги, ожидающие, что найдется кто-то, кто мог бы показать мне путь.
Давайте начнем с начала …
Ничего не зная о захвате видео в Window, я начал с поиска подходящей библиотеки. После некоторого поиска в Google я обнаружил, что есть четыре основные библиотеки для захвата видео в Windows.
1 / Видео для Windows
2 / DirectShow
3 / Windows Media Foundation
4 / OpenCV
Давайте посмотрим:
1 / Видео для Windows
Эта библиотека, к сожалению, помечена как устаревшая, но, похоже, все еще работает. Я написал «к сожалению», потому что я думаю, что это единственный, который прост в использовании. Для просмотра видео с камеры требуется всего несколько строк кода. Единственное, что мне здесь не хватает — это функция «TakePhoto». Вы можете использовать VFW для захвата видео или отдельных кадров в файл AVI. Или я что-то упустил?
2 / DirectShow
Это гораздо более сложная библиотека. Вам нужны сотни строк кода, чтобы увидеть предварительный просмотр видео. Но вы можете получить этот код на MS Docs. Хорошо, теперь у меня есть предварительный просмотр видео, и мне нужно только сделать фотографию. Можно ожидать, что это должен быть только один вызов функции. Но где функция? Я не нашел это.
Вы можете просто использовать GetCurrentImage из IVMRWindowlessControl, но для этого требуется только один кадр из предварительного просмотра с низким разрешением. Если вы установите более высокое разрешение для предварительного просмотра, видео не будет плавным.
Лучший подход, которого я мог бы достичь, — это статья «Захват изображения из булавки неподвижного изображения», доступная здесь https://docs.microsoft.com/en-us/windows/desktop/directshow/capturing-an-image-from-a-still-image-pin. Когда я нашел этот сайт, я думал, что выиграл, и моя задача была почти завершена. Но это не так.
Первый совет, который дает вам статья, — не используйте его: «Рекомендуемый способ получения неподвижных изображений с устройства — это использование API-интерфейсов Windows Image Acquisition (WIA). Для получения дополнительной информации см.« Windows Image Acquisition »на платформе. Документация SDK. Однако вы также можете использовать DirectShow для захвата изображения. » Я пытался исследовать WIA. Но это перестало работать на Vista. Я продолжил изучать статью.
Кажется, все понятно, но вам нужно реализовать свой класс, который наследует ISampleGrabberCB, помеченный как устаревший https://docs.microsoft.com/en-us/windows/desktop/directshow/isamplegrabbercb. Зачем???? Где найти альтернативу?
Я нашел приемлемое решение здесь https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/2ab5c212-5824-419d-b5d9-7f5db82f57cd/qedith-missing-in-current-windows-sdk-v70?forum=windowsdirectshowdevelopment. Вам нужно добавить заголовочный файл из Elder SDK. (Кстати, это совет почти десяти лет.) После того, как я скомпилировал приложение с этим заголовком, я смог прочитать изображение с высоким разрешением, но мне нужно подождать несколько секунд, что недопустимо. Я знаю, что проблема не в камере, потому что она работает в приложении Камера. Кроме того, изображение получается в функции SampleCB вместо BufferCB и находится в каком-то странном формате. Я могу сохранить его как JPG, но он недостаточно сжат.
3 / Windows Media Foundation
Я думаю, что MS не любит программистов и поэтому выпустила WMF. Я ничего не понимаю. Я нашел этот урок https://www.dreamincode.net/forums/topic/347938-a-new-webcam-api-tutorial-in-c-for-windows/. Это работает, но он сохраняет только один кадр из предварительного просмотра, и это не то, что я хочу.
Затем я изучил некоторые интерфейсы WMF в MS Docs. Интерфейс IMFCapturePhotoSink должен делать вещи. Но как это реализовать. Документация бесполезна.
4 / OpenCV
Во время моего исследования я нашел также эту библиотеку. Но опять же я не могу сделать снимок в высоком разрешении. Он сохраняет только один кадр из предварительного просмотра.
Может ли кто-нибудь сказать мне, на чем я должен сосредоточиться? Я считаю, что это не может быть так сложно. Существуют десятки и сотни приложений для веб-камер. Как могли другие программисты реализовать их? Что со мной не так? Я хотел бы найти простой способ реализовать простую задачу. Большое спасибо за любую помощь.
Ваш вопрос не относится к теме — вопрос должен быть связан с кодом — но я столкнулся с подобной проблемой много лет назад, и я нашел решение: DirectShow объявлен устаревшим для Windows 10, и у него есть проблемы с поддержкой USB веб-камера — в Windows 10 есть USB Video Class, который поддерживается только Media Foundation. Итак, я написал простую оболочку C ++ вокруг кода Media Foundation, которая упрощает получение необработанных изображений Захват видео с веб-камеры в Windows 7 и 8 с помощью Media Foundation
Также есть проект CaptureManager SDK — это DLL COM компонент с простыми интерфейсами, огромной функциональностью и множеством демонстрационных программ на C ++, Python, C #, Java.
Спасибо Евгению.
Рекапитуляция:
1 / Скачать Образец захвата видео CaptureEngine
2 / Редактировать метод CaptureManager :: TakePhoto. Добавьте код, чтобы найти тип носителя с самым высоким разрешением непосредственно перед «CreatePhotoMediaType (pMediaType, &pMediaType2); «line
Дополнительный код для настройки фотопотока на максимальное разрешение:
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);