Do you need to free the buffer pointer passed to Halide - c++

If I create a Halide::Buffer by constructing it with a pointer from an STB_Image function call like so:
inline Halide::Buffer<uint8_t> LoadFromFile(const char* filename)
{
int w, h, d;
unsigned char* image_data = stbi_load(filename, &w, &h, &d, 0);
Halide::Buffer buff = Halide::Buffer(image_data, std::vector<int>{w, h, d});
return buff;
}
Who is responsible for freeing the underlying buffer? I assumed it would be me since I allocated the memory so I should free it. If I am responsible, where should it be done?
Thanks

Whenever you pass a raw pointer to the Halide::Buffer constructor, it does not take ownership. It's unfortunate that STBI doesn't include a way to load an image to a pre-allocated buffer.
If the Halide image io library meets your needs, you might find it more convenient.
#include <Halide.h>
#include <halide_image_io.h>
// ...
Halide::Buffer<uint8_t> input = Halide::Tools::load_image("images/rgb.png");
Now input owns the image data and will be freed when the destructor is called. The Halide image io library supports the following formats:
PNG (via libpng)
JPEG (via libjpeg)
TIFF
Matlab .mat files

Related

Read video frame with OpenCV to specified pointer (C++)

Is there a way to read a video frame with videocapture and specify where it should go in memory? Let's say given I have a pointer char *p and have preallocated the correct amount of memory for the frame, can I read in the frame to p's address?
cv::Mat is designed to handle memory management of images automatically, but it can also be used with externally allocated buffers. To do this, pass in a pointer to the external buffer to the Mat constructor.
Make sure the buffer size, Mat size, and type (channels, depth, etc.) match the output coming out of VideoCapture.
Example:
unsigned char *data; // Points to buffer of appropriate size.
cv::VideoCapture cap; // A valid capture
// This only allocates the Mat header with a reference to "data"
cv::Mat frame {
rows,
cols,
CV_8UC3, // image type, here 3-channel, 8 bits per channel, unsigned
data
};
cap >> frame; // Image data stored into buffer at "data"

How to append a char* to the end of a void*?

Assume we have defined a char* as follow:
char *x;
And we have a function like it:
void append(void *y, char *z);
This function appends it's second parameter (where the pointer z is pointing at) to the end of a string that the pointer y is pointing to it's beginning. The reason that I am restricted to have the first parameter to be void* is that I need to override a libcurl function:
size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);
Any time the header_callback function is called I need to append buffer to the end of userdata. The userdata pointer is pointing to beginning of a string.
According to documentation you linked, userdata is a pointer previously supplied to CURLOPT_HEADERDATA. Something like this might work for you.
size_t header_callback(char *buffer, size_t size, size_t nitems, vector<string> *userdata)
{
userdata->push_back(string(buffer, size*nitems));
return size*nitems;
}
//...
vector<string> headers;
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
//...
It is impossible to implement your
void append(void *y, char *z);
in such a way that it could append a non-null terminated character sequence.
The char *buffer given to the callback is non-null terminated.
Also, you can convert the void pointer to the correct type of the buffer in the callback, before calling the append. That must be done eventually, since you cannot append anything to void.
You hardly need an external function since appending is quite trivial. Assuming your void* points to a std::string:
auto bytes = size * nitems;
auto str = (std::string*)userdata;
str->append(buffer, bytes);
To append data to buffer those things should be defined:
allowed size of destination buffer
amount of data in buffer present in destination buffer
amount of data to be copied to destination buffer
In C realloc() can be used to create new buffer with content of old one.. that may or may not change location of buffer. In C++ there is flavor of new operator that allows similar action.
If we assume that data stored is strictly null-terminated string (but even that wasn't specified!) then 2nd and 3rd are known - the size of buffer is unknown to append() is size of buffer. Therefore, the function
void append(void *y, char *z);
looks either unfit for the task or very unsafe and possibly ill-defined, unless void y is actually some structure or class (but passing that as void???) .
You did not provide implementation OR description of it. By the look is should be rather limited one. We should pre-allocate a buffer of proper size and ensure that append() won't run outside of its bounds. It cannot reallocate target buffer, so it is limited by already allocated memory. To actually reallocate target buffer append would have void **y or void &* y as formal parameter (realloc() may change pointer and does copy data from old buffer to new buffer)
This poses an architecture problem - ownership of buffer. If we pass buffer we control, we can allocate it properly and pass it to append() OR pass ownership to append() so it would reallocate it. If we don't, we have to create a temporal buffer... but can we use that temporal buffer afterwards?
The point is moot unless you are using custom header write function. user data pointer is CURLOPT_HEADERDATA, which is either pointer to valid FILE and you should _fwrite() data to it... Or, if you are implementing CURLOPT_WRITEFUNCTION and CURLOPT_READFUNCTION callback, that pointer can be used at discretion of designer of callbacks, as a pointer to some useful data container (libcurl uses fwrite as default callback).
Your question looks more referring to C (not C++) approach. Then you need the following:
know the size of the y
realloc the y to be of the size + 1
memcpy/memmove y to the new place
set the last byte of the new buffer to z
return to the user the pointer and the size of the new buffer
free the old buffer y (depends on the need).
In C++ hovewer you need to use some container like std::vector, which will allow you to append one byte.

Confusion with void* type memory allocation?

I am pretty inexperienced in C++ programming and now I'm trying to make a small program using dctmk to modify the pixel data of the dicom image. In doing so while reading documentation I found a c++ method about which I'm not quite clear. In the documention for the class DicomImage I found the following method:
int DicomImage::getOutputData ( void * buffer,
const unsigned long size,
const int bits = 0,
const unsigned long frame = 0,
const int planar = 0
)
My confusion is about buffer. It's quoted in the link as
buffer : pointer to memory buffer (must already be allocated)
Here my confusion is how do a I allocate? I'm not sure how I could allocate a memory that's a pointer of void type. Could you please explain. Thank you.
You can do it in the following way (for example):
void * mem = malloc(1024); // 1 kb
image.GetOutputData(mem, 1024);
// Don't forget to free(mem);
Another way:
char * mem = new char[1024];
image.GetOutputData((void *)mem, 1024);
// Don't forget to delete[] mem;
Another way:
char mem[1024];
image.GetOutputData((void *)&mem, 1024);
A pointer to void can point to anything, it's a generic nondescript anonymous pointer to some memory. This means that you can pass any kind of pointer as the first argument of the function, as all pointers can implicitly be converted to void*.
You can allocate any type of buffer. It will be converted using void*. However you will need to pass proper size of element. You will need to refer to documentation of api for size of each buffer element. In the example below it is 1 byte. And total buffer size is 10.
int size_of_buffer = 10;
unsigned char *buffer = malloc(sizeof(unsigned char)*size_of_buffer);
It looks like DicomImage::getOutputData does not care how you allocated your bytes. Simply take take the pointer to some blob of your choice (object, struct, array, whatever) and cast it to void*. You can get the memory with new, malloc or it can be a local variable.
Thing to be sure of:
Make sure you allocate enough space.
Make sure you accurately send the size parameter.
Make sure that you understand what format of data DicomImage::getOutputData works with.

Specifying the pointer when copying with OpenCV

I'm having an image memory that I stocked and saved it in a pointer to not loose its address.
I would like now to assign it to an IplImage by the following function memcpy (what I have tested):
IplImage* img=cvCreateImage(cvSize(640, 480), IPL_DEPTH_16U, 1);
VOID* ImgMem;
memcpy(img->imageData, ImgMemory, (640*480));
It really doesn't work. It stated Unhandled exception at 0x001b96dd in ex4.exe: 0xC0000005: Access violation reading location 0x00000044.
Any idea how to deal with that?
Your image is 640x480, but you copied 916x916 pixals.
There are two problems in your code. The first issue is you are not initializing 'ImgMem'.
VOID* ImgMem;
// ^^^^^^ Points to whatever
If you need to use a buffer prior to copying the data to the image buffer you need to allocate memory for it.
int bufferSize = 640*480*2;
char* ImgMem = new char[bufferSize];
Make sure that you delete the memory once you are done with it or you will end up leaking memory.
delete[] ImgMem;
A better alternative would be to use std::vector;
std::vector<char> ImgMem(bufferSize, 0);
memcpy(img->imageData, &ImgMem[0], ImgMem.size());
This way the memory is allocated, managed and freed by std::vector instead of you having to do it every time.
The second problem is you are trying to copy more memory into the image buffer than it can hold.
memcpy(img->imageData, ImgMemory, (916*916));
This will copy 839,056 bytes when img->imageData can only hold 307,200 bytes (assuming 8bpp).
[Edit: This answer does not take into account the attributes provided by the IplImage structure. This includes size AND alignment which are fairly important here in regards to memcpy. For more information on members of IplImage see here]
pixel type is unsigned short IPL_DEPTH_16U and it is 2 bytes, therefore you need to calculate total byte size accordingly:
int totalSize = 640*480*2;
char* ImgMemory = new char[totalSize];
memcpy(img->imageData, ImgMemory, (totalSize ));

Is it safe to manipulate the internal buffer of a cv::Mat like this?

I need to create a cv::Mat from a buffer, but I don't want the data to be shared, so I can't use the Mat(height, width, type, data) constructor:
int data[100];
cv::Mat m;
m.create(10, 10, CV_32SC1); // allocate own buffer for m
for (size_t i = 0; i < 100; ++i)
{
reinterpret_cast<int*>(m.data)[i] = data[i];
}
I need to cast the internal buffer (which is always uchar*) to be able to copy data of my desired type (int in this case) directly, and it seems to work. However, I recall that the docs preferred the method of doing all operations using uchar*, that is casting the source buffer into uchar* and using a parameter called stepWidth to obtain the correct offset in uchar*-units. Will I get in trouble doing this the other way around, or is the buffer of a CV_32SC1-type Mat simply a buffer of int, and it doesn't make a difference?
Yes, the cv::Mat internal buffers are just a block of data - do with them as you will (just don't free them!)
The only complexity, for multidimensional arrays (such as images) is that each new row doesn't necessarily follow directly from the end of the last row.
The rows are padded so they always start on a 32bit (64bit for 64bit builds??) boundary - so you need to use data(row).
There is a topic on 'foreign data' in the cv::Mat docs