There is a QSvgRenderer class in QtSvg module which can render image onto QPaintDevice. This one can be QImage. In that case we will create:
Image svgBufferImage(renderer.defaultSize(), QImage::Format_ARGB32);
But how to render to a QImage of different size than default from the SVG renderer? Since the SVG format image can be scaled without quality loss, is it possible to generate static images, like PNG, from SVG files using QSvgRenderer?
Does anyone have a better idea? Basically I need to create images like PNG from SVG files in different sizes.
Just give your QImage the desired size. The SVG renderer will scale to fit the whole image.
#include <QApplication>
#include <QSvgRenderer>
#include <QPainter>
#include <QImage>
// In your .pro file:
// QT += svg
int main(int argc, char **argv)
{
// A QApplication instance is necessary if fonts are used in the SVG
QApplication app(argc, argv);
// Load your SVG
QSvgRenderer renderer(QString("./svg-logo-h.svg"));
// Prepare a QImage with desired characteritisc
QImage image(500, 200, QImage::Format_ARGB32);
image.fill(0xaaA08080); // partly transparent red-ish background
// Get QPainter that paints to the image
QPainter painter(&image);
renderer.render(&painter);
// Save, image format based on file extension
image.save("./svg-logo-h.png");
}
This will create an 500x200 PNG image from the passed in SVG file.
Example output with an SVG image from the SVG logos page:
Here is complete answer:
QImage QPixmap::toImage()
If the pixmap has 1-bit depth, the returned image will also be 1 bit deep. Images with more bits will be returned in a format closely represents the underlying system. Usually this will be QImage::Format_ARGB32_Premultiplied for pixmaps with an alpha and QImage::Format_RGB32 or QImage::Format_RGB16 for pixmaps without alpha.
QImage img = QIcon("filepath.svg").pixmap(QSize(requiredsize)).toImage()
Also copy from above answer
// Save, image format based on file extension
image.save("./svg-logo-h.png");
If you have simple svg, like icon or small image, for replacing color for example, it's better to use NanoSVG lib
It has Qt wrapper, coded by me Qt Svg Render.
It's very small, only 2 headers and one cpp.
Usage:
QString svgPath="your svg Path";
QString pngPath="path for png";
QSize imageSize(your image Path size);
const QSize resultSize(size that you want to get);
QImage image(sizeW, sizeH, Format);//End of param
QFile svgFile(svgPath);
if (svgFile.open(QIODevice::ReadOnly))
{
int svgFileSize=svgFile.size();
QByteArray ba;
ba.resize(svgFileSize + 1);
svgFile.read(ba.data(), svgFileSize);
ba.back() = {};
if (auto const nsi(nsvgParse(ba.data(), "px", 96)); nsi)
{
image.fill(Qt::transparent);
QPainter p(&image);
p.setRenderHint(QPainter::Antialiasing, true);
drawSVGImage(&p, nsi, resultSize.width(), resultSize.height());
nsvgDelete(nsi);
image.save(pngPath);// if you want to save image
}
}
Related
I need a way to overlay text on opencv image without actually modifying the underlying image. For example inside a while loop i create a random point for each iteration and I want to display it. If I use puttext the matrix gets overwritten with the added text in each cycle.
My questions is how to overlay text on opencv image without modifying the underlying matrix. I know I could use a temporary copy of the original image and upload it every time. However I want to avoid it.
My attempt(which fails) is as below:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char * argv[])
{
RNG rng( 0xFFFFFFFF );
cv::Mat image(480, 640, CV_8UC3, cv::Scalar(0,255,0));
int fontFace = FONT_HERSHEY_COMPLEX_SMALL;
double fontScale_small=1.5;
double fontScale_large=10.;
std::string text="X";
Point p;
while(1)
{
p.x = rng.uniform( 0, 639 );
p.y = rng.uniform( 0, 479 );
putText(image, "X", p, fontFace, 1, Scalar(0,0,255), 2);
imshow("IMAGE", image);
waitKey(1);
}
return 0;
}
If you are on OpenCV 3+ and have built OpenCV with Qt, then you can use the highgui functions on the Qt GUI window to overlay text, instead of actively modifying your image. See displayOverlay(). You can also simply change the status bar text, which is sometimes more useful (so that you don't cover the image or have to deal with color clashes) with displayStatusBar(). However, note that displayOverlay() does not allow you to give specific positions for your text.
Without QT support, I don't believe this is possible in OpenCV. You'll need to either modify your image via putText() or addText(), or roll your own GUI window that you can overlay text on.
You can output your text on black image, then make XOR with source image for put your text, and the second XOR will clear your text from source image.
I've certain data set of images which has annotations for objects in that image. Annotations as in [xmin, xmax, ymin, ymax] for the object in the image. How do I transform these coordinates to their new values when I resize the image while maintaining the aspect ratio ?
If you are simply resizing, use resize. For example:
using namespace cv;
Mat img;
img = imread("image.jpg", CV_LOAD_IMAGE_COLOR);
Mat dst;
resize(img, dst, Size(xmax-xmin,ymax-ymin));
If you are extracting sub image, use Rect. For example:
using namespace cv;
Mat original_img;
Rect roi;
roi.x = xmin;
roi.y = ymin;
roi.width = xmax-xmin;
roi.height = ymax-ymin;
Mat subimage = original_img(roi);
If you are trying to find out the coordinates(xmin,xmax,ymin,ymax) after resize,
multiply them by the factor of the resize.
For example, if the resize is by the factor of 0.5,
the coordinates(xmin,xmax,ymin,ymax) are now (xmin*0.5,xmax*0.5,ymin*0.5,ymax*0.5).
you can use this package too: https://github.com/italojs/resize_dataset_pascalvoc
it's easy to use python3 main.py -p <IMAGES_&_XML_PATH> --output <IMAGES_&_XML> --new_x <NEW_X_SIZE> --new_y <NEW_X_SIZE> --save_box_images <FLAG>"
Is there an easy way to give a size to a picture we load or do we have to change the size of the picture before using it in Qt?
What I want is my image to take 10% of my scene, and be localised in the right bottom corner (for instance).
I have seen some questions/answers about that topic but there should be an easiest way than loading it in a QPixmap in a QLabel ...
I'm not using any layout, I juste have a QGraphicsView which fills my MainWindow. I just want my picture to be here (x,y) and to have this size (w,h) in my scene.
Have you tried implementing paint event after loading a pixmap?
void mapwidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap(int x, int y, int w, int h, pixMap);
}
Use a QLabel as a frame and load your pixmap into the label for easy size manipulation and positioning.
QLabel *label = new Label;
QPixmap pic("C:/Users/Pic_Location.png");
label->setPixmap(pic);
label->setAlignment(Qt::AlignBottom | Qt::AlignRight);
From there you can grab the active scene size and resize the label as needed.
I want to crop an image of 1176*640 to save the ROI of 1176*400 size. I am using the following snippet to acheive bit I am still getting the original image as output.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI)
{
IplImage *mROI = cvCreateImage(cvGetSize(*pImage), IPL_DEPTH_8U, 1);
cvSetImageROI(pImage, rect_ROI);
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
return mROI;
}
For cvCopy() the source and destination should be same size and type, that is the parameter like width, height, depth, and number of channel should be equal for both image. In your case you can change your code either like
IplImage *mROI = cvCreateImage(cvGetSize(pImage), pImage->depth, pImage->nChannels); //create dest with same size as source
cvSetImageROI(pImage, rect_ROI); //Set roi on source
cvSetImageROI(mROI, rect_ROI); //set roi on dest
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
cvResetImageROI(mROI);
or
IplImage *mROI = cvCreateImage(cvSize(rect_ROI.width,rect_ROI.height), pImage->depth, pImage->nChannels); // create an image of size as rect
cvSetImageROI(pImage, rect_ROI); //set roi on source
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
I understood that the pointer when leaves the function is no longer stable and declared a new IplImage* outside of the function and pass it as a parameter which proved to be efficient.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI, IplImage* FinalImage)
I want to write to an image a formatted text. OpenCV offers only a limited set of default fonts. Is it possible to use others? For example to read them from the *.ttf file (in Ubuntu)?
If you cannot or don't want to use the Qt bindings, here is a way to do it with CAIRO:
#include <opencv2/opencv.hpp>
#include <cairo/cairo.h>
#include <string>
void putTextCairo(
cv::Mat &targetImage,
std::string const& text,
cv::Point2d centerPoint,
std::string const& fontFace,
double fontSize,
cv::Scalar textColor,
bool fontItalic,
bool fontBold)
{
// Create Cairo
cairo_surface_t* surface =
cairo_image_surface_create(
CAIRO_FORMAT_ARGB32,
targetImage.cols,
targetImage.rows);
cairo_t* cairo = cairo_create(surface);
// Wrap Cairo with a Mat
cv::Mat cairoTarget(
cairo_image_surface_get_height(surface),
cairo_image_surface_get_width(surface),
CV_8UC4,
cairo_image_surface_get_data(surface),
cairo_image_surface_get_stride(surface));
// Put image onto Cairo
cv::cvtColor(targetImage, cairoTarget, cv::COLOR_BGR2BGRA);
// Set font and write text
cairo_select_font_face(
cairo,
fontFace.c_str(),
fontItalic ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
fontBold ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cairo, fontSize);
cairo_set_source_rgb(cairo, textColor[2], textColor[1], textColor[0]);
cairo_text_extents_t extents;
cairo_text_extents(cairo, text.c_str(), &extents);
cairo_move_to(
cairo,
centerPoint.x - extents.width/2 - extents.x_bearing,
centerPoint.y - extents.height/2- extents.y_bearing);
cairo_show_text(cairo, text.c_str());
// Copy the data to the output image
cv::cvtColor(cairoTarget, targetImage, cv::COLOR_BGRA2BGR);
cairo_destroy(cairo);
cairo_surface_destroy(surface);
}
Example call:
putTextCairo(mat, "Hello World", cv::Point2d(50,50), "arial", 15, cv::Scalar(0,0,255), false, false);
It assumes that the target image is BGR.
It puts the text's center to the given point. If you want some different positioning, you have to modify the cairo_move_to call.
It's possible to use other fonts but you need to link the Qt library to OpenCV and use the cvAddText function with a cvFontQt
http://docs.opencv.org/modules/highgui/doc/qt_new_functions.html#addtext
http://docs.opencv.org/modules/highgui/doc/qt_new_functions.html#fontqt
There are other solutions you might try, with more or less the same performance as OpenCV. For instance, you can use CAIRO to write fonts into the image.