I have written a code for creating a matrix which describes the features in a video.I use ROI for cropping the feature in images and saved it in a matrix.The whole program is inside a for loop.Now how to plot these matrix using imshow..
Mat patch;
for(unsigned int i=0;i<boundRect.size();i++)
{
Point centre=Point(boundRect[i].x+(boundRect[i].width)/2,boundRect[i].y+ (boundRect[i].height)/2);
circle(output,centre,5,CV_RGB(0,255,0),-1);
cv::Rect myROI(centre.x-40,centre.y+40,centre.x+40,centre.y-40);
patch=output(myROI);
}
Related
I try to optimize a working compute shader. Its purpose is to create an image: find the good color (using a little palette), and call imageStore(image, ivec2, vec4).
The colors are indexed, in an array of uint, in an UniformBuffer.
One color in this UBO is packed inside one uint, as {0-255, 0-255, 0-255, 0-255}.
Here the code:
struct Entry
{
*some other data*
uint rgb;
};
layout(binding = 0) uniform SConfiguration
{
Entry materials[MATERIAL_COUNT];
} configuration;
void main()
{
Entry material = configuration.materials[currentMaterialId];
float r = (material.rgb >> 16) / 255.;
float g = ((material.rgb & G_MASK) >> 8) / 255.;
float b = (material.rgb & B_MASK) / 255.;
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(r, g, b, 0.0));
}
I would like to clean/optimize a bit, because this color conversion looks bad/useless in the shader (and should be precomputed). My question is:
Is it possible to directly pack a vec4(r, g, b, 0.0) inside the UBO, using 4 bytes (like a R8G8B8A8) ?
Is it possible to do it directly? No.
But GLSL does have a number of functions for packing/unpacking normalized values. In your case, you can pass the value as a single uint uniform, then use unpackUnorm4x8 to convert it to a vec4. So your code becomes:
vec4 color = unpackUnorm4x8(material.rgb);
This is, of course, a memory-vs-performance tradeoff. So if memory isn't an issue, you should probably just pass a vec4 (never use vec3) directly.
Is it possible to directly pack a vec4(r, g, b, 0.0) inside the UBO, using 4 bytes (like a R8G8B8A8) ?
There is no way to express this directly as 4 single byte values; there is no appropriate data type in the shader to allow you to do declare this as a byte type.
However, why do you think you need to? Just upload it as 4 floats - it's a uniform so it's not like you are replicating it thousands of times, so the additional size is unlikely to be a problem in practice.
I want to project the 3D point cloud into a 2D grid over the xy plane, each grid cell size is 20cm*20cm, how to achieve it effectively?
NOT use VoxelGrid method, because I want to retain every point and deal with them in the next step(Gaussian kernel every column and use EM to deal with each grid)
As discussed in the comments, you can achieve what you want with OctreePointCloudPointVector class.
Here is an example how to use the class:
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/octree/octree_pointcloud_pointvector.h>
using Cloud = pcl::PointCloud<pcl::PointXYZ>;
using CloudPtr = Cloud::Ptr;
using OctreeT = pcl::octree::OctreePointCloudPointVector<pcl::PointXYZ>;
int main(int argc, char** argv)
{
if(argc < 2)
return 1;
// load cloud
CloudPtr cloud(new Cloud);
pcl::io::loadPCDFile(argv[1], *cloud);
CloudPtr cloud_projected(new Cloud(*cloud));
// project to XY plane
for(auto& pt : *cloud_projected)
pt.z = 0.0f;
// create octree, set resolution to 20cm
OctreeT octree(0.2);
octree.setInputCloud(cloud_projected);
octree.addPointsFromInputCloud();
// we gonna store the indices of the octree leafs here
std::vector<std::vector<int>> indices_vec;
indices_vec.reserve(octree.getLeafCount());
// traverse the octree leafs and store the indices
const auto it_end = octree.leaf_depth_end();
for(auto it = octree.leaf_depth_begin(); it != it_end; ++it)
{
auto leaf = it.getLeafContainer();
std::vector<int> indices;
leaf.getPointIndices(indices);
indices_vec.push_back(indices);
}
// save leafs to file
int cnt = 0;
for(const auto indices : indices_vec)
{
Cloud leaf(*cloud, indices);
pcl::io::savePCDFileBinary("leaf_" + std::to_string(cnt++) + ".pcd", leaf);
}
}
You can see the output by calling pcl_viewer:
pcl_viewer leaf_*.pcd
See sample output
You can achieve this using https://github.com/daavoo/pyntcloud with the following code:
from pyntcloud import PyntCloud
cloud = PyntCloud.from_file("some_cloud.ply")
# 0.2 asumming your point cloud units are meters
voxelgrid_id = cloud.add_structure("voxelgrid", size_x=0.2, size_y=0.2)
voxelgrid = cloud.structures[voxelgrid_id]
You can learn more about VoxelGrid here:
https://github.com/daavoo/pyntcloud/blob/master/examples/%5Bstructures%5D%20VoxelGrid.ipynb
What do you mean with 2D grid over the xy plane? Do you still want the z value to be the original value, or do you want to project the point cloud to the XY plane first?
Keep Z value
If you want to keep the Z values, just set the leaf size for Z of VoxelGrid to infinite (or a very large number).
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01f, 0.01f, 100000.0f);
sor.filter (*cloud_filtered);
Project Cloud to XY plane first
Project a cloud to the XY plane is nothing else than setting the Z value for each point to 0.
for(auto& pt : cloud)
pt.z = 0.0f;
Now you can do normal VoxelGrid on the projected point cloud.
I have a variable which is vector of vector, And in c++, I am easily able to define and declare it but in OpenCL Kernel, I am facing the issues. Here is an example of what I am trying to do.
std::vector<vector <double>> filter;
for (int m= 0;m<3;m++)
{
const auto& w = filters[m];
-------sum operation using w
}
Now Here, I can easily referencing the values of filters[m] in w, but I am not able to do this OpenCl kernel file. Here is what I have tried,but it is giving me wrong output.
In host code:-
filter_dev = cl::Buffer(context,CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR,filter_size,(void*)&filters,&err);
filter_dev_buff = cl::Buffer(context,CL_MEM_READ_WRITE,filter_size,NULL,&err);
kernel.setArg(0, filter_dev);
kernel.setArg(1, filter_dev_buff);
In kernel code:
__kernel void forward_shrink(__global double* filters,__global double* weight)
{
int i = get_global_id[0]; // I have tried to use indiviadual values of i in filters j, just to check the output, but is not giving the same values as in serial c++ implementation
weight = &filters[i];
------ sum operations using weight
}
Can anyone help me? Where I am wrong or what can be the solution?
You are doing multiple things wrong with your vectors.
First of all (void*)&filters doesn't do what you want it to do. &filters doesn't return a pointer to the beginning of the actual data. For that you'll have to use filters.data().
Second you can't use an array of arrays in OpenCL (or vector of vectors even less). You'll have to flatten the array yourself to a 1D array before you pass it to a OpenCL kernel.
I was trying to plot 8 points in a 3D space from the 8 vertices of the above 3D sphare.
I used the following code:
#include "Coordinates2d.h"
#include "Point3d.h"
const double zoom = 500;
int main()
{
Coordinates2d::ShowWindow("3D Primitives!");
std::vector<Point3d> points;
points.push_back(Point3d(0,0,20));
points.push_back(Point3d(0,100,20));
points.push_back(Point3d(120,100,20));
points.push_back(Point3d(120,0,20));
points.push_back(Point3d(0,0,120));
points.push_back(Point3d(0,100,120));
points.push_back(Point3d(120,100,120));
points.push_back(Point3d(120,0,120));
for(int i=0 ; i<points.size() ; i++)
{
Coordinates2d::Draw(points[i], zoom);
}
Coordinates2d::Wait();
}
Where, the Point3D is like the following:
#ifndef _POINT_3D_
#define _POINT_3D_
#include "graphics.h"
#include "Matrix.h"
#include "Point2d.h"
#include <cmath>
#include <iostream>
struct Point3d
{
double x;
double y;
double z;
public:
Point3d();
Point3d(double x, double y, double z);
Point3d(Point3d const & point);
Point3d & operator=(Point3d const & point);
Point3d & operator+(int scalar);
bool operator==(Point3d const & point);
bool operator!=(Point3d const & point);
Point3d Round()
{
return Point3d(floor(this->x + 0.5), floor(this->y + 0.5), floor(this->z + 0.5));
}
void Show()
{
std::cout<<"("<<x<<", "<<y<<", "<<z<<")";
}
bool IsValid();
double Distance(Point3d & point);
void SetMatrix(const Matrix & mat);
Matrix GetMatrix() const;
Point2d ConvertTo2d(double zoom)
{
return Point2d(x*zoom/(zoom-z), y*zoom/(zoom-z));
}
};
#endif
#ifndef _COORDINATES_2D_
#define _COORDINATES_2D_
#include "graphics.h"
#include "Point2d.h"
#include "Point3d.h"
#include "Line3d.h"
class Coordinates2d
{
private:
static Point2d origin;
public:
static void Wait();
static void ShowWindow(char str[]);
private:
static void Draw(Point2d & pt);
public:
static void Draw(Point3d & pt, double zoom)
{
Coordinates2d::Draw(pt.ConvertTo2d(zoom));
}
};
#endif
I was expecting the output to be the following:
But the output became like the following:
I am actually interested to move my viewing camera.
How can I achieve my desired result?
I see from the comments that you achieved your desired result with a clever formula. If you're interested in doing it the 'standard' graphics way, using matrices, I hope this post will help you.
I found an excellent page written explaining projection matrices for OpenGL, which also extends to the general mathematics of projection.
If you want to go in depth, here is the very well written article, explains it's steps in detail, and is just overall highly commendable.
The below image shows the first part of what you're trying to do.
So the image on the left is the 'viewing volume' that you want your camera to see. You can see that in this case, the Center of Projection (basically the focal point of the camera) is at the origin.
But wait, you say, I don't WANT the center of projection to be at the origin! I know, we'll cover that later.
What we're doing here is taking the strangely shaped volume on the left, and converting it to what we call 'normalized coordinate' on the right. So we're mapping out viewing volume onto the range of -1 to 1 in each direction. Basically, we mathmatically stretch the irregularly shaped viewing volume into this 2x2x2 cube centered at the origin.
This operation is accomplished through the following matrix, again, from the excellent article I linked above.
So note you have six variables.
t = top
b = bottom
l = left
r = right
n = near
f = far
Those six variables define you viewing volume. Far is not labeled on the above image, but it is the distance of the furthest plane from the origin in the image.
The above image shows the projection matrix that puts out viewing volume into normalized coordinates. Once coordinates are in this form, you can make it flat by simply ignoring the z coordinate, which is similar to some of the work you have done (nice work!).
So we're all set with that for viewing things from the origin. But let's say we don't want to view from the origin, and would prefer to view from, say somewhere behind and to the side.
Well we can do that! but instead of moving our viewing area (we have the math all nicely worked out right here), it is perhaps counter intuitively, easier to move all the points we are trying to view.
This can be done by multiplying all of the points by a translation matrix.
Here is the wikipedia page for translation, from which I took the following matrix.
Vx, Vy, and Vz are the amount we want to move things in the x, y, and z directions. Keep in mind, if we want to move the camera in the positive x direction, we need a negative Vx, and vice versa. This is because we are moving the points instead of the camera. Feel free to try it and see, if you want.
You may also have noticed that both of the matrices I showed are 4x4, and your coordinates are 3x1. This is because the matrices are meant to be used with homogeneous coordinates. These seem strange because they use 4 variables to represent a 3D point, but its just x, y, z, and w, where you make w =1 for your points. I believe this variable is used for depth buffers, among other things, but it is basically ubiquitously present in graphics' matrix math, so you'll want to get used to using it.
Now that you have these matrices, you can apply the translation one to your points, then apply the perspective one to those points you got out. Then simply ignore the z components, and there you are! You have a 2D image from -1 to 1 in the x and y directions.
I worked for a long time with QGraphicsItem and it has transform() function. Now I wont to do same thing with QQuickItem but unfortunately it misses transform(). So my question - how can I get transform matrix for QQuickItem?
Actually the QQuickItem provides the transform() method, however it returns the list of all transformations assigned to given item. It is because multiple transformations can be assigned to a single Item. The return type of QQuickItem::transform is QQmlListProperty<QQuickTransform> — it is a wrapper to QML list<Transform> type (see documentation for Item). It can be iterated over, yielding QQuickTransform * elements. QQuickTransform is a base class for a transformation that provides a virtual method applyTo taking a QMatrix4x4 * argument and applying the transformation upon it.
The QML allows instantiating several QQuickTransform subclasses (for translation, rotation and scale) and user is allowed to defined custom transformations (eg. for skew).
To obtain a single transformation matrix you need, you have to start with identity matrix and sequentially apply all the transformations of given QQuickItem.
QMatrix4x4 transformOfItem(QQuickItem *item)
{
QQmlListProperty transformations = item->transform();
const int count = transformations.count(&transformations);
// Prepare result structure, it will be default-initialized to be an identity matrix
QMatrix4x4 transformMatrix;
// Apply sequentially all transformation from the item
for(int i = 0; i applyTo(&transformMatrix);
}
return transformMatrix;
}
Note that the function returns a tranformation matrix as QMatrix4x4 — it is more than old QTransform that was based on 3x3 transformation matrix, so it cannot be converted without loss. If you want, you may use QMatrix4x4::toAffine to get the QMatrix (3x3) and use it to create QTransform object. However, if your QQuickItem transformations contain non-affinic elements, they will be lost.
Edit
There's one more thing to note: the method I posted works only for transformations defined by assigning to transform property. It does not check for scale and rotation properties. If you use them, you should check their values with appropriate QQuickItem methods and adjust returned matrix to include these two additional tranformations.
Here's a correct solution, based on the code provided by Michael earlier, but fixed to work actually, so you don't have to spend 20 minutes figuring out how to use QQmlListProperty
QMatrix4x4 YourQQuickItem::get_model_matrix() {
QMatrix4x4 result;
// Compose model matrix from our transform properties in the QML
QQmlListProperty<QQuickTransform> transformations = transform();
const int count = transformations.count(&transformations);
for (int i=0; i<count; i++) {
QQuickTransform *transform = transformations.at(&transformations, i);
transform->applyTo(&result);
}
return result;
}
In my use case I use this to get the model matrix for my object, then multiply together with view and projection matrixes to calculate the model-view-projection matrix.
The QSGTransformNode class implements transformations in the scene graph. In updatePaintNode function, argument updatePaintNodeData provides a pointer to the QSGTransformNode associated with this QQuickItem.
QSGNode *MyQuickItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data)
{
QSGTransformNode *transformNode = data->transformNode;
qDebug() << transformNode->matrix();