Read video frame with OpenCV to specified pointer (C++) - 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"

Related

Do you need to free the buffer pointer passed to Halide

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

How to convert cv::Mat to void*

I am making a DLL in C++ to use it in LabView, I get an RGB image and I convert it to grayscale. My code is the following:
DLLIMPORT void function (void* ImageSrc, void* ImageF)
{
cv::Mat greyMat, colorMat;
colorMat = cv::Mat(488, 648, CV_8U, (uchar*)ImageSrc);
greyMat = (colorMat, CV_LOAD_IMAGE_GRAYSCALE);
}
ImageF would be the gray image and I do not know how to copy grayMat in ImageF.
According to the following post it supposed to be very simple:
DLLIMPORT void function(void* ImageSrc, void* ImageF)
{
cv::Mat colorMat = cv::Mat(488, 648, CV_8UC3, ImageSrc);
cv::Mat greyMat = cv::Mat(488, 648, CV_8UC1, ImageF);
cv::cvtColor(colorMat, greyMat, cv::COLOR_RGB2GRAY); //You may also try cv::COLOR_BGR2GRAY
}
The ImageSrc is RGB, so it is has 3 color channels, and the type should be CV_8UC3 and not CV_8U.
Create the gray cv::Mat with ImageF as data argument (and type CV_8UC1).
There are multiple options for creating cv:Mat objects (constructor overloading).
The above option sets ImageF to point the data of the image.
Execute cv::cvtColor with cv::COLOR_RGB2GRAY conversion type, for converting from RGB to gray.
Note:
The resolution of the output image (684x488) and the type (gray type with one byte per pixel) must be defined in LabView before executing the function.
The size and type information are not passed from function to LabView.
Only the "raw" image data is passed to LabView.
Please let me know if it works, because I have no way to test it.

std::vector<uchar> to std::vector<char> for opencv mask

In opencv a function takes a mask array as std::vector<char>.
another method returns a std::vector<uchar> as a mask.
internally its using the mask to do
if(mask[i])
{
}
now, is there a way to cast std::vector<uchar> to std::vector<char> without having to loop over the array and the if statemetn will still hold?

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