Frage

I Have a cairo Image surface in cairomm library

Cairo::RefPtr cropSurface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, Width,Height);

How can I convert it to an Opencv Mat in c++?

War es hilfreich?

Lösung

Here is a short example of cairo + opencv usage, hope it'll be userful:

#include <iostream>
#include <vector>
#include <stdio.h>
#include "opencv2/opencv.hpp"

#include "cairo/cairo-win32.h"
#include "cairo/cairo-pdf.h" 
#include "cairo/cairo-ps.h"
#include "cairo/cairo-svg.h"
using namespace std;
using namespace cv;
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
void MatToCairo(Mat &MC3,cairo_surface_t *surface)
{
        Mat MC4 = Mat(cairo_image_surface_get_width(surface),cairo_image_surface_get_height(surface),CV_8UC4,cairo_image_surface_get_data(surface),cairo_image_surface_get_stride(surface));
        vector<Mat> Imgs1;
        vector<Mat> Imgs2;
        cv::split(MC4,Imgs1);
        cv::split(MC3,Imgs2);
        for(int i=0;i<3;i++)
        {
        Imgs1[i]=Imgs2[i];
        }
        // Alpha - прозрачность
        Imgs1[3]=255; 
        cv::merge(Imgs1,MC4);
}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
void CairoToMat(cairo_surface_t *surface,Mat &MC3)
{
        Mat MC4 = Mat(cairo_image_surface_get_width(surface),cairo_image_surface_get_height(surface),CV_8UC4,cairo_image_surface_get_data(surface),cairo_image_surface_get_stride(surface));
        vector<Mat> Imgs1;
        vector<Mat> Imgs2;
        cv::split(MC4,Imgs1);
        cv::split(MC3,Imgs2);
        for(int i=0;i<3;i++)
        {
        Imgs2[i]=Imgs1[i];
        }
        cv::merge(Imgs2,MC3);
}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
    int m_spcount;
    double m_compactness(0);
    int width;
    int height;
    Mat Img=imread("D:\\ImagesForTest\\lena.jpg");
    namedWindow("Image");
    width=Img.cols;
    height=Img.rows;

        cairo_surface_t *surface;
        cairo_t *cr;
        surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
        cr = cairo_create(surface);

        MatToCairo(Img,surface);

        cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size (cr, 32.0);
        cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
        cairo_move_to (cr, 10.0, 50.0);
        cairo_show_text (cr, "Hello, world");

        cairo_surface_write_to_png (surface, "hello.png");

        CairoToMat(surface,Img);

        imshow("Image", Img);

        waitKey(0);
        cairo_destroy (cr);
        cairo_surface_destroy (surface);
        destroyAllWindows();
    return 0;
}

Andere Tipps

I use cairomm, a C++ wrapper of cairo, instead of cairo but things should be similar. Once allocate memory for opencv Mat, just simply copy memory from cairo surface to Mat and it works.

#include <opencv2/opencv.hpp>
#include <cairommconfig.h>
#include <cairomm/context.h>
#include <cairomm/surface.h>

int main()
{
    Cairo::RefPtr<Cairo::ImageSurface> surface =
        Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 600, 400);

    Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);

    cr->save(); // save the state of the context
    cr->set_source_rgb(0.86, 0.85, 0.47);
    cr->paint(); // fill image with the color
    cr->restore(); // color is back to black now

    cr->save();
    // draw a border around the image
    cr->set_line_width(20.0); // make the line wider
    cr->rectangle(0.0, 0.0, surface->get_width(), surface->get_height());
    cr->stroke();

    cr->set_source_rgba(0.0, 0.0, 0.0, 0.7);
    // draw a circle in the center of the image
    cr->arc(surface->get_width() / 2.0, surface->get_height() / 2.0, surface->get_height() / 4.0, 0.0, 2.0 * M_PI);
    cr->stroke();

    // draw a diagonal line
    cr->move_to(surface->get_width() / 4.0, surface->get_height() / 4.0);
    cr->line_to(surface->get_width() * 3.0 / 4.0, surface->get_height() * 3.0 / 4.0);
    cr->stroke();
    cr->restore();

    cv::Mat m(surface->get_height(), surface->get_width(), CV_8UC4);
    memcpy(m.data, surface->get_data(), 4 * surface->get_width() * surface->get_height());

    cv::imshow("cairo", m);
    cv::waitKey(0);
}

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top