How to get separate contours (and fill them) in OpenCV? - c

I'm trying to separate the contours of an image (in order to find uniform regions) so I applied cvCanny and then cvFindContours, then I use the following code to draw 1 contour each time I press a key:
for( ; contours2 != 0; contours2 = contours2->h_next ){
cvSet(img6, cvScalar(0,0,0));
CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255 );
cvDrawContours(img6, contours2, color, cvScalarAll(255), 100);
//cvFillConvexPoly(img6,(CvPoint *)contours2,sizeof (contours2),color);
area=cvContourArea(contours2);
cvShowImage("3",img6);
printf(" %d", area);
cvWaitKey();
}
But in the first iteration it draws ALL the contours, in the second it draws ALL but one, the third draws all but two, and so on.
And if I use the cvFillConvexPoly function it fills most of the screen (although as I wrote this I realized a convex polygon won't work for me, I need to fill just the insideof the contour)
So, how can I take just 1 contour on each iteration of the for, instead of all the remaining contours?
Thanks.

You need to change the last parameter you are passing to the function, which is currently 100, to either 0 or a negative value, depending on whether you want to draw the children.
According to the documentation (http://opencv.willowgarage.com/documentation/drawing_functions.html#drawcontours),
the function has the following signature:
void cvDrawContours(CvArr *img, CvSeq* contour, CvScalar external_color,
CvScalar hole_color, int max_level, int thickness=1, int lineType=8)
From the same docs, max_level has the following purpose (most applicable part is in bold):
max_level – Maximal level for drawn contours. If 0, only contour is
drawn. If 1, the contour and all contours following it on the same
level are drawn. If 2, all contours following and all contours one
level below the contours are drawn, and so forth. If the value is
negative, the function does not draw the contours following after
contour but draws the child contours of contour up to the
$|\texttt{max_ level}|-1$ level.
Edit:
To fill the contour, use a negative value for the thickness parameter:
thickness – Thickness of lines the contours are drawn with. If it is
negative (For example, =CV_FILLED), the contour interiors are drawn.

Related

openGL 2D pixel rotation

I'm trying to rotate a 2D pixel matrix, but nothing actually happens.
my origin is a stored bitmap[w x h x 3].
why isn't the shown image being rotated?
Here's the display function:
void display()
{
uint32_t i = 0,j = 0,k = 0;
unsigned char pixels[WINDOW_WIDTH * WINDOW_HEIGHT * 3];
memset(pixels, 0, sizeof(pixels));
for(j = bitmap_h -1; j > 0; j--) {
for(i = 0; i < bitmap_w; i++) {
pixels[k++]=bitmap[j][i].r;
pixels[k++]=bitmap[j][i].g;
pixels[k++]=bitmap[j][i].b;
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(90,0,0,1);
glDrawPixels(g_img.descriptor.size_w, g_img.descriptor.size_h, GL_RGB, GL_UNSIGNED_BYTE, &pixels);
glutSwapBuffers();
}
First and foremost glDrawPixels should not be used. The problem you have is one of the reasons. The convoluted rules by which glDrawPixels operate are too vast to outline here, let's just say, that there's a so called "raster position" in your window, at which glDrawPixels will place the lower left corner of the image it draws. No transformation whatsoever will be applied to the image.
However when setting the raster position, that's when transformations get applied. And should, for whatever reason, the raster position lie outside the visible window nothing will get drawn at all.
Solution: Don't use glDrawPixels. Don't use glDrawPixels. DON'T USE glDrawPixels. I repeat DON'T USE glDrawPixels. It's best you completely forget that this function actually exists in legacy OpenGL.
Use a textured quad instead. That will also transform properly.
I did something similar. I'm creating a 3D space shooter game using OpenGL/C++. For one of my levels, I have a bunch of asteroids/rocks in the background each rotating and moving at a random speed.
I did this by taking the asteroid bitmap image and creating a texture. Then I applied the texture to a square (glBegin(GL_QUADS)). Each time I draw the square, I multiply each of the vertex coordinates (glVertex3f(x, y, z)) with a rotation matrix.
|cos0 -sin0|
|sin0 cos0 |
0 is the theta angle. I store this angle as part of my Asteroid class. each iteration I increment it by a value, depending on how fast I want the asteroid to spin. It works great.

Read vertex color from screen space

For some reason, I need to know the color of the vertices of an object. The way I can think of is to render the vertex to the screen and then call glReadPixels to fetch the color of the vertices from screen space.
My program is implemented as follows:
Render the ith vertex:
glPointSize(8.0);
glDrawArrays(GL_POINTS, i, 1);
Compute the screen coordinates of this vertex:
oPos[3] = 1.0
// assume the object space coordinates of the vertex is oPos.
multiply oPos by the model-view-projection matrix to get the normalized device coordinates of this vertex, denoted as ndcPos;
ndcPos[1~3] /= ndcPos[3]
finally, multiply ndcPos with the viewport matrix to get the screen coordinates, denoted as screenPos. The viewport matrix is defined as:
GLfloat viewportMat[] = {
screen_width/2, 0, 0, 0,
0, screen_height/2, 0, 0,
0, 0, 1, 0,
(screen_width-1)/2.0, (screen_height-1)/2.0, 0, 1};
Finally, call glReadPixels as:
glReadPixels(int(screenPos[0]+0.5), int(screenPos[1]+0.5),
1, 1, GL_RGB, GL_FLOAT, currentColor);
The resulting color will then be stored at currentColor, which is a vector of length three.
My questions are:
Is there any better ways to get the vertex color rather than query them from screen space?
Any ideas about the correctness of my second and third step?
OpenGL transform feedback allows a shader to write arbitrary values into a buffer object, which can then be read by the host program. You can use this to make your vertex shader pass the computed vertex colors back to the host program.
The nice thing about transform feedback is that you can use it while drawing to the screen, so you can draw your geometry and capture the vertex colors in a single pass. Or, if you prefer, you can draw the geometry with rasterization turned off to capture the feedback data without touching the screen.
Since the data produced by transform feedback is stored in a buffer object, you can use it as input for other drawing operations, too. Depending on what you plan to do with the computed vertex colors, you may be able to avoid transferring them back to the host program at all.

Determining if rectangles overlap, if so return the area of overlapping rectangle compare with given set

I am a beginner programmer that is working on elementary tests for myself to grasp core values of working with C. I have a test case and don't really know where to begin in structuring it for compiling with GCC. I have a basic theory and pseudocode summary but mainly needing a little help stepping forward.
I have googled the related questions and permutations to this question and have been unable to make heads or tails of the logic for C.
Given the following logic:
Using the C language, have the function OverlappingRectangles(strArr)
read the strArr parameter being passed which will represent two
rectangles on a Cartesian coordinate plane and will contain 8
coordinates with the first 4 making up rectangle 1 and the last 4
making up rectange 2. It will be in the following format:
"(0,0),(2,2),(2,0),(0,2),(1,0),(1,2),(6,0),(6,2)." Your program should
determine the area of the space where the two rectangles overlap, and
then output the number of times this overlapping region can fit into
the first rectangle. For the above example, the overlapping region
makes up a rectangle of area 2, and the first rectangle (the first 4
coordinates) makes up a rectangle of area 4, so your program should
output 2. The coordinates will all be integers. If there's no overlap
between the two rectangles return 0.
I'm lost.
Should have added this at first:
Given a string(n1,n2,n3,n4,m1,m2,m3,m4)
Split string into string1(n1,n2,n3,n4) string2(m1,m2,m3,m4)
If n1+n4 < m1 or n2+n3 < m2 or m1+m4 < n1 or m2+m3 < m1
Calculate area of intersecting rectangle and divide into area of first rectangle.
Else
Print 0
You have a string of the form:
(x1,y1)(x2,y2)(x2,y1)(x1,y2)(x3,y3)(x4,y4)(x4,y3)(x3,y4)
defining 2 rectangles:
r1 = (x1,y1) to (x2,y2)
r2 = (x3,y3) to (x4,y4)
You need to first:
define a representation (structure) for the rectangles
parse (read) the string to extract the numbers for x1-x4 and y1-y4 -- look at e.g. sscanf and its return value for doing this
You can create a helper function, e.g.:
const char *parse_rectangle(const char *str, rectangle *r);
That will read a rectangle r from str in the form (x1,y1)(x2,y2)(x2,y1)(x1,y2)(x3,y3) (including any validation) and return a pointer to the next character.
Now, you will have two rectangles.
You can then compute the intersection of these rectangles as a third rectangle, e.g.:
int intersection(const rectangle *r1, const rectangle *r2, rectangle *result);
which will return 1 if the rectangles intersect, or 0 if they don't and fill result with the intersection. If you are using C99, you can use _Bool instead.
Now, you need a function to compute the area, e.g.:
int area(const rectangle *r);
You can pass this through the intersected rectangle and the first rectangle to get the areas of both.
Now, you simply divide the first rectangle area by the intersected rectangle area and print the result.

HVS color space in Open CV

I am going to detect a yellow color object when i open up my System CAM using Open CV programming, i got some help from the tutorial Object Recognition in Open CV but i am not clear about this line of code, what it does, i don't know. please elaborate me on the below line of code, which i am using.
cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgThreshed);
other part of program:
CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
cvMoments(imgYellowThresh, moments, 1);
// The actual moment values
double moment10 = cvGetSpatialMoment(moments, 1, 0);
double moment01 = cvGetSpatialMoment(moments, 0, 1);
double area = cvGetCentralMoment(moments, 0, 0);
What about reading documentation?
inRange:
Checks if array elements lie between the elements of two other arrays.
And actually that article contains clear explanation:
And the two cvScalars represent the lower and upper bound of values
that are yellowish in colour.
About second code. From that calculations author finds center of object and its square. Quote from article:
You first allocate memory to the moments structure, and then you
calculate the various moments. And then using the moments structure,
you calculate the two first order moments (moment10 and moment01) and
the zeroth order moment (area).
Dividing moment10 by area gives the X coordinate of the yellow ball,
and similarly, dividing moment01 by area gives the Y coordinate.

how to rasterize rotated rectangle (in 2d by setpixel)

I have got a four 2d vertices A B C D of rotated rectangle,
I need to rasterize/draw it (efficiently) in pixelbufer
with setpixel(x,y,color)
how to do it?
i was trying with some code like
// convertilg a b c d do up down left right,
// calculating some dx_left dx_right on y--
// etc (frustrating on special cases when there are 2 up_y vertices in same line etc)
for(;;)
{
drawhorizontalline(y, xstart, xend, color);
if(y==downy) break;
y--;
xstart+=dxstart;
xend+=dxend;
if(y==lefty) dxstart = dxright;
if(y==righty) dxend = dxleft;
}
but it is most frustrating (terribly bug prone and most frustrating)
i am really tired of debuging this all day yesterday and i need to find
maybe some working code rather than to try to debug this
To fill your rectangle handle it as closed convex polygon (almost the same as triangle filling)
order your points to match winding rule
so there are lines AB BC CD DA or reverse
create left and right buffer
address is y-coordinate, its an array of x-positions and if needed also array of color,texture coordinates,.... for starters:
int buf_x0[ys],buf_x1[ys];
where ys is screen y-resolution
implement any draw line algorithm
but instead of draw to screen just store x coordinate of pixel to buffer.
instead of: setpixel(x,y,color); do: buf_x?[y]=x;.
Which buffer is the destination depends on the line Y direction
if dy<0 then fill buff_x0
if dy>0 then fill buff_x1
if dy==0 then buf_x0[y]=min(x) and buf_x1[y]=max(x)
Beware you have to sort the line endpoints by x coordinate before rasterizing to avoid seams/holes in meshes caused by different pixels produced for reversed endpoints lines.
apply this line algorithm to all border lines of polygon (AB,BC,CD,DA)
after this the buffers contains start and end x-positions of your horizontal lines
fill the rectangle on screen
for (y=min(Ay,By,Cy,Dy);y<=max(Ay,By,Cy,Dy);y++)
draw_horizontal_line(y,buf_x0[y],buf_x1[y],color);
Image for clarity (taken from my lectures on low level computer graphics)
image description:
vertical rectangles represents the border buffers buf_x0[],buf_x1[]
clockwise winding rule ensures the destination buffer. If its coded properly than buf_x0[y] <= buf_x1[y] so draw of horizontal line colapses to single for loop
Also se these:
simple 2D raster C++ example of mine
simple 3D voxel grid C++ example of mine

Resources