data conversion between FlyCaptureImage and OpenCV Mat - pointers

I'm working with a PointGrey camera which returns an image having type:
typedef struct FlyCaptureImage
{
// Rows, in pixels, of the image.
int iRows;
// Columns, in pixels, of the image.
int iCols;
// Row increment. The number of bytes per row.
int iRowInc;
// Video mode that this image was captured with. This member is only
// populated when the image is returned from a grab call.
FlyCaptureVideoMode videoMode;
// Timestamp of this image.
FlyCaptureTimestamp timeStamp;
// Pointer to the actual image data.
unsigned char* pData;
//
// If the returned image is Y8, Y16, RAW8 or RAW16, this flag indicates
// whether it is a greyscale or stippled (bayer tiled) image. In all
// other modes, this flag has no meaning.
//
bool bStippled;
// The pixel format of this image.
FlyCapturePixelFormat pixelFormat;
// This field is always 1 for single lens cameras. This field is
// used to indicate the number of images contained in the structure
// when dealing with multi-imager systems such as the Bumblebee2
// or XB3? int iNumImages;
int iNumImages;
// Reserved for future use.
unsigned long ulReserved[ 5 ];
} FlyCaptureImage;
whereas I want to process the image in OpenCV Mat, therefore, a conversion is needed. I did successfully try to iterate every element in the image to copy. But it's slow. So, it's better to copy just the pointer. This is my code using Mat initialization, simply like:
MatImg = Mat::Mat(FCImg.iRows, FCImg.iCols, CV_8UC3, FCImg.pData);
Please give me some advices on this. Is it the correct way to do?? I put this conversion in a separate class from the main program which received returned Mat image, e.g., mycam.getframe(image)
Thanks!

Often, each pixel row contains extra padding pixels at the end.
The full row size in bytes has several names including step, stepWidth and stride.
In the struct FlyCaptureImage this is called row increment: iRowInc.
Thus, in your case, you should specify the stride as in:
cv::Mat pgImg(FCImg.iRows, FCImg.iCols, CV_8UC3, FCImg.pData, FCImg.iRowInc);

Related

Failed conversion of a QImage image to a CV image

I am new to both opencv and opencv. What I am doing is to convert a QImage image to an opencv Mat image, and then display both of them. Here is my code for this conversion:
i = new QImage("lena.png");
QImage lena = i->scaled(labW,labH,Qt::IgnoreAspectRatio);
//Original
QImage lenaRGB = lena.convertToFormat(QImage::Format_RGB888);
ui->imgWindow->setPixmap(QPixmap::fromImage(lena,Qt::AutoColor));
//method 1
Mat lena_cv, out;
QImage lena2 = lenaRGB.rgbSwapped();
QImage swapped = lena2;
swapped = swapped.rgbSwapped();
lena_cv = Mat(swapped.width(),swapped.height(),CV_8UC3, swapped.bits(),swapped.bytesPerLine()).clone();
namedWindow("CV Image");
imshow("CV Image", lena_cv);
//method 2
Mat out2,out3;
out2.create(Size(lena2.width(),lena2.height()),CV_8UC3);
int width = lena2.width();
int height = lena2.height();
memcpy(out2.data, lena2.bits(), sizeof(char)*width*height*3);
cvtColor(out2,out3,CV_RGB2GRAY);
namedWindow("CV Image2");
imshow("CV Image2",out3);
Both of the above two conversions cannot yield desired images, as shown below:
It is also noted that the conversion cannot proceed without using rgbSwapped, i.e.,:
lena_cv = Mat(lenaRGB.width(),lenaRGB.height(),CV_8UC3, lenaRGB.bits(),lenaRGB.bytesPerLine());
because:
The resulting image lena_cv cannot be displayed. If an additional step to convert lena_cv to BGR format using cvtColor before image display:
Exception at 0x7ffdff394008, code: 0xe06d7363: C++ exception, flags=0x1
(execution cannot be continued) (first chance) at c:\opencv-3.2.0
\sources\modules\core\src\opencl\runtime\opencl_core.cpp:278
This indicates the post conversion to BGR fails. I am not sure RGB to BGR conversion (of QImage) is necessary or not for converting QImage to CV image.
Can anyone help identify the issue with the above codes. Thanks :)
The "skew" in the third image is almost likely a result of assuming that each scan line occupies exactly width*3 bytes. There's typically a "stride" (or "steps") factor with each row in many image formats image such that the number of bytes per row is on some 4-byte or 16-byte boundary. Fortunately, QImage has a helper method called bytesPerLine that tells you how long each source row is.
So instead of this:
memcpy(out2.data, lena2.bits(), sizeof(char)*width*height*3);
Do this:
unsigned char* src = lena2.bits();
unsigned char* dst = out2.data;
int stride = lena2.bytesPerLine();
for (int row = 0; row < height; row++)
{
memcpy(dst + width*3*row, src+row*stride, width*3); // copy a single row, accounting for stride bytes
}
All of this assume it's the QImage that has the stride bytes and not the target Mat image you are transforming the bits too. If I have this backwards, then adjust the code to account for the steps member of Mat. (I don't see you using this, so I'm willing to be the above code is what you need).
The "blue" image is mostly likely just the RGB color bytes needing to be swapped for every pixel. Not sure why you are calling rgbSwapped unless that was the effect you were going for. Oh wait, you're probably referring to that noise effect at the bottom of the image. I'm willing to bet you need to think about "stride" bytes as well here too.

create array of ubo and present each at a time to its shader

i want to create array of ubo object in my cpu update it and then upload it to the gpu in one call like that. (for the example lets say i have only two objects).
std::vector<UniformBufferObject> ubo(m_allObject.size());
int index = 0;
for (RenderableObject* rendObj : m_allObject)
{
ubo[index].proj = m_camera->getProjection();
ubo[index].view = m_camera->getView();
ubo[index].model = rendObj->getTransform().getModel();
ubo[index].proj[1][1] *= -1;
index++;
}
int size = sizeof(UniformBufferObject) *m_allObject.size();
void* data;
m_instance->getLogicalDevice().mapMemory(ykEngine::Buffer::m_uniformBuffer.m_bufferMemory, 0, size , vk::MemoryMapFlags(), &data);
memcpy(data, ubo.data(), size);
m_instance->getLogicalDevice().unmapMemory(ykEngine::Buffer::m_uniformBuffer.m_bufferMemory);
i created one buffer with the size of two ubo. (the create do work because it do work with ubo in size one).
vk::DeviceSize bufferSize = sizeof(UniformBufferObject) * 2;
createBuffer(logicalDevice, bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, m_uniformBuffer.m_buffer, m_uniformBuffer.m_bufferMemory);
and than i put an offset in the descriptor set creation :
vk::DescriptorBufferInfo bufferInfo;
bufferInfo.buffer = uniformBuffer;
bufferInfo.offset = offsetForUBO;
bufferInfo.range = sizeof(UniformBufferObject);
the offset is the size of UniformBufferObject * the index of the object.
every object have is own descriptorsetLayout but the samepipline
when i try to update the descriptor set i get the error :
i couldnt find any aligment enum that specify that information.
if anyone know how to do that it will help alot.
thanks.
i couldnt find any aligment enum that specify that information.
Vulkan is not OpenGL; you don't use enums to query limits. Limits are defined by the VkPhysicalDeviceLimits struct, queried via vkGetPhysicalDeviceProperties/2KHR.
The error tells you exactly which limitation you violated: minUniformBufferOffsetAlignment. Your implementation set this to 0x100, but your provided offset was insufficient for this.
Also, you should not map buffers in the middle of a frame. All mapping in Vulkan is "persistent"; map it once and leave it that way until you're ready to delete the memory.

Computing the memory footprint (or byte length) of a map

I want to limit a map to be maximum X bytes. It seems there is no straightforward way of computing the byte length of a map though.
"encoding/binary" package has a nice Size function, but it only works for slices or "fixed values", not for maps.
I could try to get all key/value pairs from the map, infer their type (if it's a map[string]interface{}) and compute the length - but that would be both cumbersome and probably incorrect (because that would exclude the "internal" Go cost of the map itself - managing pointers to elements etc).
Any suggested way of doing this? Preferably a code example.
This is the definition for a map header:
// A header for a Go map.
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
// ../reflect/type.go. Don't change this structure without also changing that code!
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint32
hash0 uint32 // hash seed
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
}
Calculating its size is pretty straightforward (unsafe.Sizeof).
This is the definition for each individual bucket the map points to:
// A bucket for a Go map.
type bmap struct {
tophash [bucketCnt]uint8
// Followed by bucketCnt keys and then bucketCnt values.
// NOTE: packing all the keys together and then all the values together makes the
// code a bit more complicated than alternating key/value/key/value/... but it allows
// us to eliminate padding which would be needed for, e.g., map[int64]int8.
// Followed by an overflow pointer.
}
bucketCnt is a constant defined as:
bucketCnt = 1 << bucketCntBits // equals decimal 8
bucketCntBits = 3
The final calculation would be:
unsafe.Sizeof(hmap) + (len(theMap) * 8) + (len(theMap) * 8 * unsafe.Sizeof(x)) + (len(theMap) * 8 * unsafe.Sizeof(y))
Where theMap is your map value, x is a value of the map's key type and y a value of the map's value type.
You'll have to share the hmap structure with your package via assembly, analogously to thunk.s in the runtime.

QMap Memory Error

I am doing one project in which I define a data types like below
typedef QVector<double> QFilterDataMap1D;
typedef QMap<double, QFilterDataMap1D> QFilterDataMap2D;
Then there is one class with the name of mono_data in which i have define this variable
QFilterMap2D valid_filters;
mono_data Scan_data // Class
Now i am reading one variable from a .mat file and trying to save it in to above "valid_filters" QMap.
Qt Code: Switch view
for(int i=0;i<1;i++)
{
for(int j=0;j<1;j++)
{
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
The transferring is done successfully but then it gives run-time error
Windows has triggered a breakpoint in SpectralDataCollector.exe.
This may be due to a corruption of the heap, and indicates a bug in
SpectralDataCollector.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
Can anyone help in solving this problem. It will be of great help to me.
Thanks
Different issues here:
1. Using double as key type for a QMap
Using a QMap<double, Foo> is a very bad idea. the reason is that this is a container that let you access a Foo given a double. For instance:
map[0.45] = foo1;
map[15.74] = foo2;
This is problematic, because then, to retrieve the data contained in map[key], you have to test if key is either equal, smaller or greater than other keys in the maps. In your case, the key is a double, and testing if two doubles are equals is not a "safe" operation.
2. Using an int as key while you defined it was double
Here:
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
i is an integer, and you said it should be a double.
3. Your loop only test for (i,j) = (0,0)
Are you aware that
for(int i=0;i<1;i++)
{
for(int j=0;j<1;j++)
{
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
is equivalent to:
Scan_Data.valid_filters[0][0]=valid_filters[0][0];
printf("\nValid_filters=%f",Scan_Data.valid_filters[0][0]);
?
4. Accessing a vector with operator[] is not safe
When you do:
Scan_Data.valid_filters[i][j]
You in fact do:
QFilterDataMap1D & v = Scan_Data.valid_filters[i]; // call QMap::operator[](double)
double d = v[j]; // call QVector::operator[](int)
The first one is safe, and create the entry if it doesn't exist. The second one is not safe, the jth element in you vector must already exist otherwise it would crash.
Solution
It seems you in fact want a 2D array of double (i.e., a matrix). To do this, use:
typedef QVector<double> QFilterDataMap1D;
typedef QVector<QFilterDataMap1D> QFilterDataMap2D;
Then, when you want to transfer one in another, simply use:
Scan_Data.valid_filters = valid_filters;
Or if you want to do it yourself:
Scan_Data.valid_filters.clear();
for(int i=0;i<n;i++)
{
Scan_Data.valid_filters << QFilterDataMap1D();
for(int j=0;j<m;j++)
{
Scan_Data.valid_filters[i] << valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
If you want a 3D matrix, you would use:
typedef QVector<QFilterDataMap2D> QFilterDataMap3D;

OpenCL void pointer arithmetic - strange behavior

I have wrote an OpenCL kernel that is using the opencl-opengl interoperability to read vertices and indices, but probably this is not even important because I am just doing simple pointer addition in order to get a specific vertex by index.
uint pos = (index + base)*stride;
Here i am calculating the absolute position in bytes, in my example pos is 28,643,328 with a stride of 28, index = 0 and base = 1,022,976. Well, that seems correct.
Unfortunately, I cant use vload3 directly because the offset parameter isn't calculated as an absolute address in bytes. So I just add pos to the pointer void* vertices_gl
void* new_addr = vertices_gl+pos;
new_addr is in my example = 0x2f90000 and this is where the strange part begins,
vertices_gl = 0x303f000
The result (new_addr) should be 0x4B90000 (0x303f000 + 28,643,328)
I dont understand why the address vertices_gl is getting decreased by 716,800 (0xAF000)
I'm targeting the GPU: AMD Radeon HD5830
Ps: for those wondering, I am using a printf to get these values :) ( couldn't get CodeXL working)
There is no pointer arithmetic for void* pointers. Use char* pointers to perform byte-wise pointer computations.
Or a lot better than that: Use the real type the pointer is pointing to, and don't multiply offsets. Simply write vertex[index+base] assuming vertex points to your type containing 28 bytes of data.
Performance consideration: Align your vertex attributes to a power of two for coalesced memory access. This means, add 4 bytes of padding after each vertex entry. To automatically do this, use float8 as the vertex type if your attributes are all floating point values. I assume you work with position and normal data or something similar, so it might be a good idea to write a custom struct which encapsulates both vectors in a convenient and self-explaining way:
// Defining a type for the vertex data. This is 32 bytes large.
// You can share this code in a header for inclusion in both OpenCL and C / C++!
typedef struct {
float4 pos;
float4 normal;
} VertexData;
// Example kernel
__kernel void computeNormalKernel(__global VertexData *vertex, uint base) {
uint index = get_global_id(0);
VertexData thisVertex = vertex[index+base]; // It can't be simpler!
thisVertex.normal = computeNormal(...); // Like you'd do it in C / C++!
vertex[index+base] = thisVertex; // Of couse also when writing
}
Note: This code doesn't work with your stride of 28 if you just change one of the float4s to a float3, since float3 also consumes 4 floats of memory. But you can write it like this, which will not add padding (but note that this will penalize memory access bandwidth):
typedef struct {
float pos[4];
float normal[3]; // Assuming you want 3 floats here
} VertexData;

Resources