[英]How can I get an image from Android camera using Qt/C++ Widgets (Not QML)
[英]Qt QML Camera to C++ QImage on Android
我有一個基於 Qt5.4 的程序,帶有一些圖像處理功能。 我將QCamera
與我的videoSurface
(源自QAbstractVideoSurface
)一起使用來獲取 VideoFrames。 它在 Windows 上運行良好。
但現在我需要我的應用程序的 Android 版本。 我發現QCamera
不適用於 Android。 但我看到 QML Camera 示例在 Android 上運行沒有問題。
所以我決定用 QML 重寫我的應用程序。 主要問題:我無法在 C++ 中訪問 QML 相機表面。
void myVideoOutput::setSource(QObject *source)
{
qDebug() << Q_FUNC_INFO << source;
if (source == m_source.data())
return;
m_source = source;
if (m_source) {
const QMetaObject *metaObject = m_source.data()->metaObject();
QStringList properties;
for(int i = metaObject->propertyOffset(); i < metaObject >propertyCount(); ++i)
properties << QString::fromLatin1(metaObject->property(i).name());
qDebug() << properties;
}
.....
emit sourceChanged();
}
此代碼允許訪問屬性。 但我無法以這種方式訪問 videoSurface(使用QCamera
我可以做到)。 我想知道 QML 相機是如何工作的? 它基於QCamera
嗎? 我在QDeclarativeCamera
中看到QCamera *m_camera
...
所以我有兩個問題:
1)是的,有可能。 我有兩種方法可以做到這一點。
將QAbstractVideoFilter與QVideoFilterRunnable類(僅適用於QT 5.5!)一起使用非常好。 它們是專門為這種情況而開發的,並且非常易於使用。
網絡上有一些使用它的好例子:
https://blog.qt.io/blog/2015/03/20/introducing-video-filters-in-qt-multimedia/
http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl
就像這里所說的那樣,這種方法的缺點是,在Android設備上,QVideoFrame指針沒有原始像素數據,而是具有需要讀取的OpenGL紋理(我發布的第二個示例具有解決此問題的解決方法),因此這種方法對於實時IMHO而言並不是很好。
我最終用來解決此問題的是QVideoProbe類。
首先,您必須命名QML攝像機的實例:
Camera {
id: camera
objectName: "qrCameraQML"
}
然后從C ++端獲取此實例,如下所示:
QObject *qmlCamera = engine.rootObjects().at(0).findChild<QObject*>("qrCameraQML");
QML相機實例實際上具有一個QVariant元素,該元素只能通過C ++訪問,並且可以轉換為QCamera *:
camera_ = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
然后,您要做的就是將探針連接到實際將處理QVideoFrame的插槽,然后將探針的源設置為先前投射的QCamera *:
connect(&probe_,SIGNAL(videoFrameProbed(QVideoFrame)),this,SLOT(handleFrame(QVideoFrame)));
probe_.setSource(camera_);
在我的示例中,camera_和probe_只是:
QCamera *camera_;
QVideoProbe probe_;
根據我的經驗,這種方法(對於android平台)比使用qt視頻過濾器類要快得多,但是它的缺點是您基本上只能讀取qml的視頻輸出,而AFAIK則無法將后處理的視頻幀發送回qml。
如果您確實需要將經過處理的圖像發送回qml,我建議您嘗試第一種方法,看看會發生什么。
2)不支持Qt AFAIK,可能不支持OpenCv或其他一些lib。
我喜歡強調@ waldez-junior第一個答案。 在QML中,將QAbstractVideoFilter
組件添加到VideoOutput。
Camera {
id: camera
}
VideoOutput {
id: videoOutput
source: camera
filters: [ videoFilter ]
autoOrientation: true
}
MyVideoFilter {
id: videoFilter
// orientation: videoOutput.orientation
}
在C ++中,您實現了QAbstractVideoFilter
組件,這是一個最小的示例:
class MyVideoFilter : public QAbstractVideoFilter
{
Q_OBJECT
public:
QVideoFilterRunnable *createFilterRunnable() Q_DECL_OVERRIDE
{
return new CustomFilterRunnable(this);
}
};
class MyVideoFilterRunnable : public QVideoFilterRunnable
{
public:
QVideoFrame run(QVideoFrame* input, const QVideoSurfaceFormat& surfaceFormat, RunFlags flags)
{
if (!input->isValid())
{
return *input;
}
// do stuff with input
return *input;
}
};
```
Qt源代碼中有一個QAbstractVideoFilter示例: http : //code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl 。
為了使事情變得簡單,請考慮使用Qt內部函數qt_imageFromVideoFrame
將QVideoFrame
轉換為QImage
。 此代碼適用於NoHandle
情況,並且適用於大多數平台。 不幸的是,它不適用於許多Android設備,因為QVideoFrame::map()
將返回false
。
extern QImage qt_imageFromVideoFrame(const QVideoFrame& f);
對於Android,您需要在使用OpenGL填充QImage
情況下處理GLTextureHandle
情況。
在某些設備上,圖像內部位緩沖器將被翻轉。
#ifdef Q_OS_ANDROID
bool flip = true;
#else
bool flip = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
#endif
在某些設備上,圖像可能也會旋轉。 處理旋轉的最佳方法是在VideoOutput
組件中設置autoOrientation: true
。 然后,您的組件可以僅獲取videoOutput.orientation
的副本。
知道如何翻轉和旋轉圖像將有助於進行視頻識別(例如面部識別)。
我還在https://github.com/stephenquan/MyVideoFilterApp創建了一個最小的工作示例
import QtQuick 2.3
import QtQuick.Window 2.2
import CVComponents 1.0
Window {
visible: true
CVCAM{
id: camera
width: 640
height: 480
deviceId: "0"
imageHeight: 640
imageWidth: 480
}
}
處理圖像非常簡單。 該類僅繪制項目,因此它可以在QML上使用,所有其他處理都在后端進行,因此可以使用相機使用的Mat圖像進行處理。
import GTServer
import QtQuick
import QtQuick.Controls.Material
import QtMultimedia
Item {
id: preview
GT {
id: gt
}
CaptureSession {
id: captureSession
camera: Camera {
id: camera
}
imageCapture: ImageCapture {
id: imageCapture
onImageCaptured: {
gt.capture(videoOutput.videoSink)
}
}
videoOutput: videoOutput
}
VideoOutput {
id: videoOutput
anchors.fill: parent
}
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.