Letterboxing Images and Iterating VipsImage pixel data #2261
Replies: 6 comments 7 replies
-
Hello @Transigent, libvips has efficient operation compositing -- you can run one operation after another, and behind the scenes they join together into a fast and low-memory-use combined operation. So the idea behind the design of the API is that operations only implement the minimum functionality, and you get complex effects by combining primitives.
thumb = pyvips.Image.thumbnail(filename, 640)
boxed = thumb.gravity("centre", 640, 640, extend="white") You can't really iterate over pixels in libvips, since images don't really exist. Everything is a delayed computation and pixels are only created on demand. You can either implement a new vips operation (needs good C or C++), or render the whole image to an area of memory and then treat it like any other array. Have a look at You can split your image up like this (in Python, again):
Then write to memory to make a huge float array. You'll find python is as fast as C for libvips, so it might be more convenient. |
Beta Was this translation helpful? Give feedback.
-
OK I thought I had it under control but it seems I am doing something wrong. I set up a basic test harness to try this out. Here is my code so far:
It is being called from this method:
I started from the code sample at the bottom of the C API documentation page and translated from your python sample. This code works fine until I reenable the section:
at which point I get an exception on the vips_gravity line:
If you are wondering why I didn't just leave it as:
its because it only gets one pass through ShrinkImage then hangs at
And if I used
like in the C sample, it hangs on return(0) with
I must be doing something wrong, if you have any thoughts they would be greatly welcome. |
Beta Was this translation helpful? Give feedback.
-
You're almost there -- you need NULLs at the end of arg lists in C, and your reference counting it not quite right. I made you a small sample program: /* compile with
*
* gcc -g -Wall try325.c `pkg-config vips --cflags --libs`
*/
#include <vips/vips.h>
int
main( int argc, char **argv )
{
VipsImage *image;
VipsImage *x;
if (VIPS_INIT (argv[0]))
vips_error_exit (NULL);
if (vips_thumbnail (argv[1], &image, 640, NULL))
vips_error_exit (NULL);
if (vips_gravity (image, &x, VIPS_COMPASS_DIRECTION_CENTRE, 640, 640,
"extend", VIPS_EXTEND_BLACK,
NULL)) {
g_object_unref (image);
vips_error_exit (NULL);
}
g_object_unref (image);
image = x;
if (vips_image_write_to_file (image, argv[2],
"Q", 70,
"strip", TRUE,
NULL)) {
g_object_unref (image);
vips_error_exit (NULL);
}
g_object_unref (image);
return 0;
} |
Beta Was this translation helpful? Give feedback.
-
Ooop, pressed ctrl-enter by mistake and posted too early. NULLs to terminate arg listsC functions aren't told how many argument they are passed, so you need to mark the end of the argument list with a NULL. gcc will warn if you forget, perhaps MSVC has some warning you can enable for this? Reference countingThe C API creates the output image for you, so the pattern is always: VipsImage *input-image1 = some-code;
VipsImage *input-image2 = some-code;
VipsImage *output-image;
if (vips_xxxxx(input-image1, input-image2, &output-image, optional-args, NULL))
error-handling The That example above uses a single image variable pointing to the head of the pipeline, and moves it along as new nodes are added. libvips also supports reference pools which can be less work for complex cases. libvips C++ bindingThe libvips C++ API does not use varargs, so it's a bit simpler. It might be worth looking at this -- it'll automate ref counting too. It's slightly awkward to set up under Windows. The problem is that C++ does not have a ABI, so you must use exactly the same C++ compiler for your whole project. This means the libvips C++ win binary (built with g++) won't work with MSVC C++. You need to copy the libvips C++ API source code into your own project and build it with your own code. It's just a few files and pretty simple to incorporate: https://github.com/libvips/libvips/tree/master/cplusplus The C++ API source is notionally LGPL since it's shipped with the rest of libvips, but we let people do anything they like with it because of this problem. Perhaps it should be broken out into a separate MIT-licenced project. |
Beta Was this translation helpful? Give feedback.
-
In C++, that test prog would be: /* compile with
*
* g++ -g -Wall try325.cpp `pkg-config vips-cpp --cflags --libs`
*/
#include <iostream>
#include <vips/vips8>
using namespace vips;
using namespace std;
int
main( int argc, char **argv )
{
if (VIPS_INIT (argv[0]))
vips_error_exit (NULL);
try {
VImage image = VImage::thumbnail(argv[1], 640);
image = image.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, 640, VImage::option()
->set("extend", "black"));
image.write_to_file(argv[2], VImage::option()
->set("strip", TRUE)
->set("Q", 70));
}
catch (const VError &err ) {
cout << err.what();
}
return 0;
} So no annoying NULLs, and ref counting is done for you. |
Beta Was this translation helpful? Give feedback.
-
Sorry I wasn't sure if you got the previous message. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi and sorry about the noobness of this question, I am fairly new to C and VIPS.
I am successfully using libvips in a VS2017 C++ project to load thumbnails from files on disk, using the C API. Its so FAST compared to the existing opencv implementation! Thanks for the great library.
My questions are several:
1) Existing code requires 640 x 640 thumbnails, I am currently using code like this:
vips_thumbnail(FileName, &out, 640)
which gets me nearly what I need except that only the longest axis is 640, I need to supply the image data letterboxed (or pillarboxed) ie. so that it fills the whole 640 x 640 but centered and maintaining aspect ratio. I saw a weserv enhancement discussing this weserv/images#80 (comment) but I couldn't find if this has been implemented in libvips or in the thumbnailer. If not is there another fast way?
2) Theres probably an obvious answer but I could not find how to directly access the image data in the VipsImage object. The documentation description of VipsImage states that "VIPS images are three-dimensional arrays, the dimensions being width, height and bands" but I cant find examples that show how to iterate through the data, the closest I could find is a region example here which I dont know how to transmogrify so it works with an VipsImage. Is there an example of this somewhere?
3) I want to use libvips to do what an existing block of opencv code does using a cv::Mat. It iterates through the (BGR) pixel data to build a new array organized like this :
(It is formatted like this for feeding to a neural network)
At first I thought I would do the transformation manually like the original code but I have seen some really powerful code snippets like this and it occurs that libvips might already have the tools to reformat the data the way I need it. Is there any inbuilt functionality to do that?
Thanks for any advice!
Beta Was this translation helpful? Give feedback.
All reactions