-
Notifications
You must be signed in to change notification settings - Fork 12
Handle image
In some situations, we just need very basic operations to modify an image. In such case, libraries such as OpenCV are too heavy.
Zupply came up with a very light-weight solution to it, providing IO(read/write) to main-stream image formats, pixel access, cropping, resize fuctions to help you out in case you need it.
Let's make it clear first, if you have to do a lot image processing related stuff, use OpenCV or similar libraries instead. This Image class is designed for light-weight use, consistent to the goal of Zupply project.
#include "zupply.hpp"
using namespace zz;
void test_image()
{
Image img("../data/demo.png"); // read image from disk
if (!img.empty())
{
Image img2 = img; // Image class use copy-on-write, see details later
// crop image
img.crop(Point(10, 10), Point(img.cols() - 10, img.rows() - 10));
img.resize(1.5); // resize 1.5x, keep aspect ratio
img.resize(800, 600); // resize to 800x600, regardless of aspect ratio
img(100, 100, 0) = 128; // access pixel and change the value
img.save("demo_out.jpg", 95); // with JPG, you can set quality from 0-100
img2.save("demo_original.jpg"); // img2 is not affected
}
}
ImageHdr is quite similar to Image class(both derived from same templated container), the only difference is ImageHdr uses single float to store data, providing finer precision over 8-bit unsigned char Image.
//ImageHdr provide conversion to/from Image
Image img("test.jpg");
ImageHdr imghdr(img, 1.0); // use 1.0 as range in this case, all value range from [0, 1.0]
Image img2 = imghdr.to_normal(1.0);
// ImagHdr can read any image directly
imghdr.load("test.jpg");
// and HDR image
imghdr.load("hdr_image.hdr");
// save to hdr
imghdr.save("hdr_out.hdr");
- Channel order: RGB(A) by default
- Row major order
The channels are interleaved 1-D array in memory, i.e., the data in memory should look like this: r(0, 0)g(0, 0)b(0, 0)r(0, 1)g(0, 1)b(0, 1)...
To avoid expensive copy operation, and to avoid error-prone explicit use of shallow and deep copy(why .clone() is not a perfect solution), Image class use copy-on-write strategy. That is, when copy instances, only shape info are copied, the underlying data is shared by all instances.
Image img1, img2, img3;
img1.load("xxx.jpg");
img3 = img2 = img1; // they share the same data buffer
When you modify one of the instances, it will detach from the shared resource buffer, to avoid affecting the other instances.
img1.resize(0.5); // img1 now use new data buffer, img2 and img3 not affected.
img2(10, 20, 0) = 100; // img2 changed, img3 not affected.
For all mutable operations, Image class will handle the process properly.
To avoid allocating new storage, read operation is suggested to use immutable operations, i.e.
// use .at() to read
unsigned char value = img.at(row, col, channel);
// instead of mutable operation
unsigned char value = img(row, col, channel)