I'm new with C++, and try to figuring out what this line of code means:
cur_rect = cv::Rect(cur_rect) & cv::Rect(0, 0, mat->cols, mat->rows); // here
if( cv::Rect(cur_rect) == cv::Rect() ) //here
{
.......
}
The Rect & Rect part intersects two rectangles and gives a non-empty rectangle back when the two inputs overlap.
So you can compare the result to Rect() to see whether there was an intersection. Your code crops cur_rect to (0, 0, mat->cols, mat->rows) and then checks whether it is empty or not.
Sources:
http://opencv.willowgarage.com/documentation/cpp/core_basic_structures.html?highlight=rect
How can one easily detect whether 2 ROIs intersects in OpenCv?
Edit
An alternative implementation, a bit cleaner:
// crop cur_rect to rectangle with matrix 'mat' size:
cur_rect &= cv::Rect(0, 0, mat->cols, mat->rows);
if (cur_rect.area() == 0) {
// result is empty
...
}
I am assuming that cv::Rect(...) methods (or family of them) returns a rectangle object. The line that you do not understand, I assume is an overloaded operator (==) that compares rectangles.
But I am making a lot of assumptions here as I do not have the code for cv class.
As to the & overloaded operator - one assumes that this is doing an intersection or union. Once again without the code it is hard to say.
Related
I'm trying to teach myself opencv and c++ and this example program for face and eye detection includes the line:
for(size_t i = 0; i < faces.size(); i++)
I don't understand what faces.size() means, and following from that at what point i can be greater than faces.size().
How does it acquire a numerical value?
I see plenty of instances of faces throughout the rest of the program, but the only time I see size is as a parameter for face_cascade.detectMultiScale. It is capitalized though, which makes me think that it has nothing to do with faces.size().
faces.size()
Returns the size of 'faces', i.e. how many faces there are in 'faces'.
In general a basic for loop is structured like so:
for ( init; condition; increment )
{
//your code...
}
It will run as long as the condition is true, i.e. as long as 'i' is less than faces.size() (which might be '10' or some other integer value).
'i' will get bigger as for each loop iteration 1 is added to it. This is managed by the i++ instruction.
I'd suggest if you're struggling with loop syntax that openCV might not be the best place to start learning C++ as a lot of the examples expect a level of competence higher than 'beginner' (intentionally and unintentionally via simple bad coding/lack of commenting etc.)
faces is being populated here :
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
According to OpenCV documentation :
void cv::CascadeClassifier::detectMultiScale ( InputArray image,
std::vector< Rect > & objects,
double scaleFactor = 1.1,
int minNeighbors = 3,
int flags = 0,
Size minSize = Size(),
Size maxSize = Size()
)
where std::vector< Rect > & objects (faces in your case) is a
Vector of rectangles where each rectangle contains the detected
object, the rectangles may be partially outside the original image.
As you can see, objects is passed by reference to allow its modification inside the function.
Also std::vector<Type>::size() will give you the size of your vector, so, i<faces.size() is necessary to get the index i inside the bounds of the vector.
I have a dataset of 500 cv::Point.
For each point, I need to determine if this point is contained in a ROI modelized by a concave polygon.
This polygon can be quite large (most of the time, it can be contained in a bounding box of 100x400, but it can be larger)
For that number of points and that size of polygon, what is the most efficient way to determine if a point is in a polygon?
using the pointPolygonTest openCV function?
building a mask with drawContours and finding if the point is white or black in the mask?
other solution? (I really want to be accurate, so convex polygons and bounding boxes are excluded).
In general, to be both accurate and efficient, I'd go with a two-step process.
First, a bounding box on the polygon. It's a quick and simple matter to see which points are not inside the box. With that, you can discard several points right off the bat.
Secondly, pointPolygonTest. It's a relatively costly operation, but the first step guarantees that you will only perform it for those points that need better accuracy.
This way, you mantain accuracy but speed up the process. The only exception is when most points will fall inside the bounding box. In that case, the first step will almost always fail and thus won't optimise the algorithm, will actually make it slightly slower.
Quite some time ago I had exactly the same problem and used the masking approach (second point of your statement). I was testing this way datasets containing millions of points and found this solution very effective.
This is faster than pointPolygonTest with and without a bounding box!
Scalar color(0,255,0);
drawContours(image, contours, k, color, CV_FILLED, 1); //k is the index of the contour in the array of arrays 'contours'
for(int y = 0; y < image.rows, y++){
const uchar *ptr = image.ptr(y);
for(int x = 0; x < image.cols, x++){
const uchar * pixel = ptr;
if((int) pixel[1] = 255){
//point is inside contour
}
ptr += 3;
}
}
It uses the color to check if the point is inside the contour.
For faster matrix access than Mat::at() we're using pointer access.
In my case this was up to 20 times faster than the pointPolygonTest.
I am trying to write code that will fill a rectangular region with a gradient that varies along a diagonal of that region. I had thought that I could play with the direction parameter as follows:
context->GradientFillLinear(
wxrect,
get_wx_colour(gradient.front()),
get_wx_colour(gradient.back()),
wxNORTH | wxEAST);
When I do this, the compiler converts the direction subexpression to an int and fails to compile because of a type mismatch. I suspect that gradients can only be filled horizontally or vertically and this is why the parameter is written expecting an enum value. Can anyone confirm this suspicion?
As of wxWidget-3.0.2, the implementation of GradientFillLinear eventually calls a specific implementation which looks somewhat like:
wxDCImpl::DoGradientFillLinear()
{
...
if ( nDirection == wxEAST || nDirection == wxWEST )
{
...
}
else // nDirection == wxNORTH || nDirection == wxSOUTH
{
...
}
So, your suspicion appears to be correct and even if you did manage to somehow coerce the direction as wxNORTH | wxEAST in the argument of GradientFillLinear, the implementation would not have supported it.
As SleuthEye's answer correctly says, this can't be done directly, but you can always apply a transformation to rotate the horizontal or vertical gradient by 45 degrees.
Is there a way to easily add padding to a QPainter area?
The whole idea is to have a border, within the drawable area, where I can't draw so that when I draw a line from (0, 0) to (10, 10) I'm actually drawing at (0 + padding, 0 + padding) to (10 + padding, 10 + padding). The padding border should be seen though.
Assuming a QPainterĀ is created as:
QPainter painter(aWidget); // aWIdget is a Widget*
and a padding integer variable. Now let's consider the area that is drawable of the widget as "A". How can I get to have a drawable area "B", so that B has:
B_width = A_width - 2 * padding;
B_height = A_height - 2 * padding;
and what would have been at QPoint(padding, padding) in A would now be at QPoint(0, 0) in B?
I began to implement it by my own (which is going to be painful), but I was wondering if there way an easier and "pre-made" way to do this in Qt? Maybe Transformations?
Thanks.
Yes, doing a transform would be the best way. If you apply a transformation, then all subsequent draw calls will be transformed by that transform. For example applying a translation of (5,5) would make a line (0,0) to (10,0) become (5,5) to (15,5).
The QPainter documentation can be found here and if you look near the bottom you will see a translate method. That's exactly what you're looking for.
painter.translate(5, 5); // that should do it
Edit:
To allow the draw calls to only edit a specific part of the surface use QPainter's setClipRect method.
painter.setClipRect(5, 5, originalWidth - 5, originalHeight - 5);
You can set the window area too. If you take a look in documentation of QPainter, you will se two interesting methods: setWindow (which you can transform your printable area into custom coordinates) and setViewport (which you can use to limit your printable area to a given rect).
I'm having a problem with color picking and antialiasing in OpenGL. When AA is activated results from glReadPixels are obviously wrong on object edges and object intersections. For example:
I render a box #28 (RGBA: 28, 0, 0, 0) near a box #32 (RGBA: 32, 0, 0, 0). With AA, I can get a wrong ReadPixel value (e.g. 30) where the cube and triangle overlap, or value of 14 on boxes edge, due to the AA algorithm.
I have ~4000 thousand objects I need to be able to pick (it's a jigsaw puzzle game). It is vital to be able to select objects by shape.
I've tried to disable AA with glDisable(GL_MULTISAMPLE) but it does not works with certain AA modes (I read it depends on AA implementation - SS, MS, CS ..)
So, how do I pick an underlying object?
A way do temporary disable AA?
Using a different buffer or even rendering context?
Any other suggestion?
Why not use an FBO as your pick buffer?
I use this hack: pick not just one pixel, but all the 3x3=9 pixels around the picking point. If they are all same, we are safe. Otherwise, it must be on edge and we can skip that.
int renderer::pick_(int x, int y)
{
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
"only works on little-endian architecture");
static_assert(sizeof(int) == 4,
"only works on architecture that has int size of 4");
// sort of edge detection. selection only happens at non-edge
// since the edge may cause anti-aliasing glitch
int ids[3*3];
glReadPixels(x-1, y-1, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, ids);
for (auto& id: ids) id &= 0x00FFFFFF; // mask out alpha
if (ids[0] == 0x00FFFFFF) return -1; // pure white for background
// prevent anti-aliasing glitch
bool same = true;
for (auto id: ids) same = (same && id == ids[0]);
if (same) return ids[0];
return -2; // edge
}