Saturday, June 8, 2013

Using QML Camera and passing image to C++ code

I tried to compile one my application with Qt5. Application was using QML camera and sharing image to C++ code for further processing.

Following is sample code, it works with Qt5 and Qt Multimedia 5.

Lets start with ImageProcessor class, the C++ class which is called from QML to further image processing.

Following is header file for ImageProcessor class, it declares processImage() slot which can be invoked from QML code.
#ifndef IMAGEPROCESSOR_H
#define IMAGEPROCESSOR_H

#include <QObject>

class ImageProcessor : public QObject
{
    Q_OBJECT
public:
    explicit ImageProcessor(QObject *parent = 0);
 
public slots:
    void processImage( const QString& image);   
};
#endif // IMAGEPROCESSOR_H
Following is cpp file for ImageProcessor class. processImage() function retrieves Image from camera image provider. Once we have valid image, we can process it further.
#include "imageprocessor.h"
#include <QtQml/QmlEngine>
#include <QtQml/QmlContext>
#include <QtQuick/QQuickImageProvider>
#include <QDebug>

ImageProcessor::ImageProcessor(QObject *parent)
    : QObject(parent)
{}

void ImageProcessor::processImage( const QString& path)
{
    QUrl imageUrl(path);
    QQmlEngine* engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase* imageProviderBase = engine->imageProvider(
     imageUrl.host());
    QQuickImageProvider* imageProvider = static_cast<QQuickImageProvider>
     (imageProviderBase);
    
    QSize imageSize;
    QString imageId = imageUrl.path().remove(0,1);
    QImage image = imageProvider->requestImage(imageId, &imageSize, imageSize);
    if( !image.isNull()) {
        //process image
    }
}
Now we need to register ImageProcessor class with QML. so that we can use it from QML code. This can be done by using qmlRegisterType global function.
#include  <QtGui/QGuiApplication>
#include  <QQmlEngine>
#include  <QQmlComponent>
#include  <QtQuick/QQuickView>

#include "imageprocessor.h"

int main(int argc, char *argv[])
{
    qmlRegisterType<ImageProcessor>("ImageProcessor", 1, 0, "ImageProcessor");

    QGuiApplication app(argc, argv);

    QQuickView view;

    QObject::connect(view.engine(),SIGNAL(quit()),&app,SLOT(quit()));    
    view.setSource(QUrl::fromLocalFile("qml/main.qml"));
    view.show();

    return app.exec();
}
That's all from C++ side, QML code is event easier. Following how you can use ImageProcess class from QML code.
import QtQuick 2.0
import QtMultimedia 5.0
import ImageProcessor 1.0

Rectangle {
    width: 360
    height: 360

    //shows live preview from camera
    VideoOutput {
        source: camera
        anchors.fill: parent
        focus : visible
    }

    //shows captured image
    Image {
        id: photoPreview
        anchors.fill: parent
        fillMode: Image.PreserveAspectFit
    }

    Camera {
        id: camera
        imageProcessing.whiteBalanceMode: CameraImageProcessing.WhiteBalanceFlash
        captureMode: Camera.CaptureStillImage

        exposure {
            exposureCompensation: -1.0
            exposureMode: Camera.ExposurePortrait
        }

        flash.mode: Camera.FlashRedEyeReduction

        imageCapture {
            onImageCaptured: {
                photoPreview.source = preview
                imageProcessor.processImage(preview);
            }
        }
    }

    MouseArea{
        anchors.fill: parent
        onClicked: {
            camera.imageCapture.capture();
        }
    }

    //image processor for further image processing
    ImageProcessor{
        id: imageProcessor
    }
}

10 comments:

  1. Qt5 QML Camera has camera.mediaObject property, which provides access to C++ QCamera object. It can be passed to C++ side to get access to viewfinder frames, preview of full size captured frames.

    It's also possible to use it for processing viewfinder frames and displaying processed ones for example, in this case ImageProcessor may have it's own implementation of simple mediaObject propery with VideoRendererControl to provide frames to QML VideoOutput.

    ReplyDelete
    Replies
    1. Hay, Thanks for information. I will try to update post with your feedback.

      Delete
    2. Hi Dmytro,

      Is there an example of this? I don't know how to do 2nd paragraph. I am trying to process viewfinder frames from the QCamera, which I have done already but I couldn't do it using QML.

      I need it because (I think) currently the only way to use the camera in Android is using QML. I am using Qt 5.2 beta.

      Thanks in advance!

      Delete
  2. Do you know how to take the buffer of videoOutput?
    I want to capture the frame postprocess by glsl

    ReplyDelete
    Replies
    1. HI, I think you can instead set custom view finder and access the raw image from camera. Like shown in this blogspot (http://kunalmaemo.blogspot.kr/2012/04/using-camera-api-and-getting-raw-image.html)

      Delete
  3. Error: no matching function for call to 'QQuickImageProvider::QQuickImageProvider(QQmlImageProviderBase*&)'
    (imageProviderBase);
    ^
    I always get this error, when i copy your code. Don't you know what is the problem?

    ReplyDelete
    Replies
    1. Looks like some how constructor is getting called, may be if you post your code, I can help...

      Delete
    2. static_cast TO QQuickImageProvider*
      There is a missing * in the sample code

      Delete
  4. Hello!

    Very nice post.

    I would like to know how could I return the QImage from imageProcessor to QML?

    Thanks.

    ReplyDelete
    Replies
    1. Something like this,
      http://kunalmaemo.blogspot.com/2011/12/using-qdeclarativeimageprovider-to-load.html

      Delete