Currently I am trying to understand the OpenCV's face detection API DetectionBasedTracker. Inside the code, I found the definition
#define CALC_SUM_(p0, p1, p2, p3, offset) \
((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])
I can't figure out the followings
(1)p0, p1, p2, p3 are integer values. What is the return value of (p0)[offset] and what does it do?
(2)Actually offset is the number of integers in one row of image matrix. Say if image matrix is 480 x 640. There are 640 integer values in one row of image data. Say for the second row, offset = 640. It is calculated as offset = pt.y * ((int)image.step/sizeof(int)) + pt.x; By changing the offset value, how (p0)[offset]has effect?
My guess is that p0 is not an integer, but rather a one-dimensional array.
If that is correct, the macro would be calculating the "sum" of the offsetth items in arrays p0, p1, p2, and p3, except that it's a strange sum because of all those - signs.
Edited: having now looked at the code in question
I find the code hard to follow, but let's try anyway:
My conclusion is that p0[offset] is a pointer to a pixel in an image (an integer value). That pixel is one corner of a rectangle in the image. p1[offset], p2[offset], and p3[offset] are pointers to the pixels at the other corners of the same rectangle.
In more detail...
CALC_SUM_ is called by CALC_SUM which is called in a lot of places, such as in HaarEvaluator::Feature :: calc.
In that calc function, CALC_SUM is called with p[0] as an argument. p is defined in struct Feature as const int* p[RECT_NUM][4], so p[0] is an array of four pointers to ints.
What might these four ints be? Well, they are undefined immediately after the Feature constructor is called, since the pointers are set to be NULL.
But assuming HaarEvaluator::Feature :: updatePtrs has been called at some point, the pointers are updated by the CV_TILTED_PTRS or CV_SUM_PTRS macros.
Both of those macros take a pointer to a matrix of values, which I assume is a matrix of pixels in an image (given the task at hand, which is finding a feature in an image). That pointer is called titled or sum. Let's work with sum. The four pointers in p[0] are set by CV_SUM_PTRS to point to four corners of a rectangle within sum.
When the calc function is called, the four pointers (p[0] contains the four pointers to corners p[0][0]-p[0][3]) are passed in along with an offset. This offset is effectively added to each of the four pointers, using array notation, which shifts the rectangle around the image.
The actual sum looks like it could be doing the fast computation described here.
Related
I got a vector with n rows with xy coordinates of points. These points form a conture of an given CAD model. Now I want to restore the conture of the model. So I tried to sort the point with the atan2 function.
This is the code I use to sort the points.
std::sort(matrix.begin(), matrix.end(), sort1);
matrix.erase(std::unique(matrix.begin(), matrix.end(), compare2),matrix.end());
matrix.push_back(std::vector<double>(3, 0));
So first I sort the points in the vector matrix. As compare function i use this code
bool sort1(vector<double> const& s1, vector<double> const& s2)
{
return atan2(s1[1],s1[0])<atan2(s2[1],s2[0]);
}
After the vector has been sorted, I just delete duplicates to reduce the size of the vector. The last step is to push back the first point to the end of the vector to close the conture.
For standard models like a cube, or a ball this works fine, but for more complicate models the atan2 function is note working fine.
So this image show the unsorted points.
When I sort the vector I get this conture as result
My first approach was to check the atan2 function but it's working fine. The problem seem to be the result of the atan2 function. So this list shows the actual coordinates and the result of the atan2 function
x y z atan2
-5.44283 -1.94995 0 -2.79758
-5.36969 -1.93228 0 -2.79617
-5.33637 -1.92454 0 -2.79547
-13.15 -4.76500 0 -2.79395
-5.26308 -1.90750 0 -2.79389
-5.22970 -1.90005 0 -2.7931
-5.15626 -1.88364 0 -2.79134
As you can see while the x and y coordinate change the atan2 stays in the same range as the other values. For me that's the problem, why my conture isn't correct. Do I have to add something to my sort function to get the correct results?
One idea i had was to sort the coordinates not just by the atan2, but also by the length of the vector between the point, with the lowest atan2, and all other points. But here's my problem. I would first sort by atan2, and then sort again by the length. But the second sort process would destroy the hole result of the first sort function.
atan2 obviously won't help in generic case. It is mostly good for convex figures. Consider a narrow rectangle with (0,0) inside and an adjacent rectangle and try to sort their points by their atan2.
Have you tried painting a point in the set and then looking for the closest not yet painted point as an iteration step?
If you're dealing with curves only then I'd suggest to use following algorithm:
Define angle range R
Take initial point A, mark it as visited
Find closest to A point B, mark it as visited
Calculate the direction formed by vector [A, B]
Find closest to B unvisited point C in angle range R and mark it visited
Go to step 4 with B as A and C as B
This is not an ultimate solution but it should be able to find basic curves and some polygons. With wider angle range R you can approximate more curved lines.
I am in a lost. I have been trying to implement this code at:http://www.blackpawn.com/texts/pointinpoly/default.html
However, I don't know how is it possible that the cross-product present there between two 2D vectors can result also in a 2D vector. It does not make sense to me. That is also present in some examples of intersection between polygons and lines, in the fine book "Realtime Collision Detection" - where even scalar triples between 2D vectors appear in the codes (see page 189, for instance).
The issue is that, as far as I can think of it, the pseudo cross-product of two 2D vectors can only result in a scalar (v1.xv2.y-v1.yv2.x) or at most in a 3D vector if one adds two zeros, since that scalar represents the Z dimension. But how can it result in a 2D vector?
I am not the first one to ask this and, coincidently, when trying to use the same code example: Cross product of 2 2D vectors However, as can be easily seen, the answer, the original question when updated and the comments in that thread ended up being quite a mess, if I dare say so.
Does anyone know how should I get these 2D vectors from the cross-product of two 2D vectors? If code is to be provided, I can handle C#, JavaScript and some C++.
EDIT - here is a piece of the code in the book as I mentioned above:
int IntersectLineQuad(Point p, Point q, Point a, Point b, Point c, Point d, Point &r)
{
Vector pq = q - p;
Vector pa = a - p;
Vector pb = b - p;
Vector pc = c - p;
// Determine which triangle to test against by testing against diagonal first
Vector m = Cross(pc, pq);
float v = Dot(pa, m); // ScalarTriple(pq, pa, pc);
if (v >= 0.0f) {
// Test intersection against triangle abc
float u = -Dot(pb, m); // ScalarTriple(pq, pc, pb);
if (u < 0.0f) return 0;
float w = ScalarTriple(pq, pb, pa);
....
For the page you linked, it seems that they talk about a triangle in a 3d space:
Because the triangle can be oriented in any way in 3d-space, ...
Hence all the vectors they talk about are 3d vectors, and all the text and code makes perfect sense. Note that even for a 2d vectors everything also makes sense, if you consider a cross product to be a 3d vector pointing out of screen. And they mention it on the page too:
If you take the cross product of [B-A] and [p-A], you'll get a vector pointing out of the screen.
Their code is correct too, both for 2d and 3d cases:
function SameSide(p1,p2, a,b)
cp1 = CrossProduct(b-a, p1-a)
cp2 = CrossProduct(b-a, p2-a)
if DotProduct(cp1, cp2) >= 0 then return true
else return false
For 2d, both cp1 and cp2 are vectors pointing out of screen, and the (3d) dot product is exactly what you need to check; checking just the product of corresponding Z components is the same. If everything is 3d, this is also correct. (Though I would write simply return DotProduct(cp1, cp2) >= 0.)
For int IntersectLineQuad(), I can guess that the situation is the same: the Quad, whatever it is, is a 3d object, as well as Vector and Point in code. However, if you add more details about what is this function supposed to do, this will help.
In fact, it is obvious that any problem stated in 2d can be extended to 3d, and so any approach which is valid in 3d will also be valid for 2d case too, you just need to imagine a third axis pointing out of screen. So I think this is a valid (though confusing) technique to describe a 2d problem completely in 3d terms. You might yourself doing some extra work, because some values will always be zero in such an approach, but in turn the (almost) same code will work in a general 3d case too.
I am using m.conservativeResize() to do the equivalent in Eigen as the reshape function in MatLab. So let N = 3, and then...
static MatrixXd m(N*N,1);
and then I assign this matrix some values, and it looks like this:
1
1
0
1
0
1
0
1
1
and then try to reshape it...
m.conservativeResize(N,N);
So now the same values should be there, but now in N rows and N columns rather than N*N rows and one column.
However that's not what I get. The first column has the first three values in the column vector - OK so far - but then the remaining values just look like garbage values from uninitialized memory:
1 3.08116e-309 0.420085
1 -2.68156e+154 1.2461e-47
0 -2.68156e+154 0.634626
Any idea what I am doing wrong?
conservativeResize() doesn't ``move" the elements around (in other words, doesn't work like MATLABs reshape, since it performs memory re-allocation even if the initial and final sizes are the same). From the documentation:
Resizes the matrix to rows x cols while leaving old values untouched.
...
Matrices are resized relative to the top-left element. In case values need to be appended to the matrix they will be uninitialized.
These statements seem a bit confusing. What it means is the following: think about the initial matrix as a rectangle, of size A x B. Then think about the resized matrix as another rectangle of size C x D. Then mentally overlap the two rectangles, making sure the top-left corner is common to both. The common elements of the intersection are the ones that are preserved by the conservativeResize. The rest just correspond to uninitialized memory.
In case you want a true reshaping, use resize() instead (making absolutely sure that A x B == C x D, otherwise reallocation takes place and all bets are off).
So I have a Node class that contains a member variable "center" that is a Vec2float*. The reason for this is because I want to use the drawSolidCircle function, and I need a Vec2float variable to represent the center. One of the questions I have is, is a Vec2float a vector, or a point in space? A lot of the member functions make it sound like some kind of vector class, yet the set() function only takes in two arguments which makes it seem like a point in space, and in order to draw a circle, you would need a point and a radius, not a vector. Also another problem I am having, is that if someone gives me 2 doubles, how can I convert them to Vec2float properly and set the x and y of center (if it even has an x and y). So for example in the function below, I am given an array of Entries and the length of it, 'n'. An entry has two member variables 'x' & 'y' which are both doubles. I want to create an array of Nodes and copy over that data to use it to draw circles.
cinder::Vec2<float>* center;//in my Node class
void function::build(Entry* c, int n) {
Node* nd = new Node[n];
for(int i = 0;i<n;i++) {
nd[i].center = //what goes here if c[i].x and c[i].y are doubles?
}
references:
Vec2 class: http://libcinder.org/docs/v0.8.4/classcinder_1_1_vec2.html
list of functions that draw shapes, im using drawSolidCircle: http://libcinder.org/docs/v0.8.4/namespacecinder_1_1gl.html
Any suggestions?
To make your life easy, you can use the cinder namespace. Add the following line after the includes at the top of your file.
using namespace ci;
which then enables you to simply write, for example:
Vec2f center(1.5f, 1.5f);
std::cout << center << std::endl;
Indeed, Vec2<float> is typedef'ed as Vec2f in Cinder.
Also, you shouldn't have to cast doubles into floats because they are casted implicitly, just pass them in!
Lastly, you really have to be careful with pointers. Most of the time, if I want an array of objects, I would use a std::vector, and use shared_ptr. Here's where I learned how to do just that: https://forum.libcinder.org/topic/efficiency-vector-of-pointers
I won't cover the whole theory behind vectors. Here's a good reference (using the Processing language): http://natureofcode.com/book/chapter-1-vectors/ In short, yes you should use them to store positions, but mathematically they are still vectors (you can think of a position vector as an arrow from the origin (0,0) to your current position).
I also suggest you have a look at the numerous samples provided with the library.
well i figured something out, it compiles for now, whether it will work for my program in the future is debatable. But here is what i did:
float f1 = (float)(c[i].x);
float f2 = (float)(c[i].y);
cinder::Vec2<float>* p = new cinder::Vec2<float>(f1,f2);
nd[i].center = p;
i casted the doubles to floats separately, then made a variable p using the Vec2 constructor, and then set center equal to that. like i said it compiles, we shall see if it works :D
How to access individual pixels in OpenCV 2.3 using C++?
For my U8C3 image I tried this:
Scalar col = I.at<Scalar>(i, j);
and
p = I.ptr<uchar>(i);
First is throwing an exception, the second one is returning some unrelated data. Also all examples I was able to find are for old IIPimage(?) for C version of OpenCV.
All I need is to get color of pixel at given coordinates.
The type you call cv::Mat::at with needs to match the type of the individual pixels. Since cv::Scalar is basically a cv::Vec<double,4>, this won't work for a U8C3 image (it would work for a F64C4 image, of course).
In your case you need a cv::Vec3b, which is a typedef for cv::Vec<uchar,3>:
Vec3b col = I.at<Vec3b>(i, j);
You can then convert this into a cv::Scalar if you really need to, but the type of the cv::Mat::at instantiation must match the type of your image, since it just casts the image data without any conversions.
Your second code snippet returns a pointer to the ith row of the image. It is no unrelated data, but just a pointer to single uchar values. So in case of a U8C3 image, every consecutive 3 elements in the data returned to p should represent one pixel. Again, to get every pixel as a single element use
Vec3b *p = I.ptr<Vec3b>(i);
which again does nothing more than an appropriate cast of the row pointer before returning it.
EDIT: If you want to do many pixel accesses on the image, you can also use the cv::Mat_ convenience type. This is nothing more than a typed thin wrapper around the image data, so that all accesses to image pixels are appropriately typed:
Mat_<Vec3b> &U = reinterpret_cast<Mat_<Vec3b>&>(I);
You can then freely use U(i, j) and always get a 3-tuple of unsigned chars and therefore pixels, again without any copying, just type casts (and therefore at the same performance as I.at<Vec3b>(i, j)).