OpenCV: How to get corners of CvBox2D? - opencv

I need to find corner positions of CvBox2D (or MCvBox2D) to map found contours on game object in XNA. I have a problem with correct translation of rotation angle. I thought that this is kind of basic operation but I kind find any solution in Internet.
I tried:
rotationAngle = box.angle * (180.0/ CV_PI);
angle = box.angle;
box.angle=rotationAngle;
alien.X = box.center.X - box.Width / 2;
alien.Y = box.center.Y - box.Height / 2;
alien.angle=angle;
but it wasn't translating it correctly.
Had someone ever tried to get corners on this kind of structure?

In EmguCV you just need to call
PointF[] corners = box.GetVertices();
if box is a MCvBox2D.

The simplest way to get the vertices of a CvBox2D is to convert it to a RotatedRect:
CvBox2D box = ...
cv::RotatedRect rr(box);
cv::Point2f vertices[4];
rr.points(vertices);
// vertices now has the four corners your seek

Related

How to attach sprites that collide?

I essentially want the "sprites" to collide when they stick together. However, I don't want the "joint" to be rigid; I essentially want the sprites to be able to move around as long as they are in contact with each other. Imagine two circles connected, and you can move one circle around the other, as long as it remains in contact.
I found this question: How to make one body stick to another moving object in SpriteKit and a lot of other resources that explain how to make sprites stick upon collision, but they all use SKJoints, which are rigid are not really flexible.
I guess another way to phrase it would be to say that I want the sprites to stick, but I want them to be able to "slide" on each other.
Well, I can think of one workaround, but this wouldn't work with non-normal polygons.
Sticking (pun unintended) with your circles example, what if you lock the position of the circle?
let circle1 = center circle
let circle2 = movable circle
Knowing the width of both circles, you can place in the update function that the position should be exactly the distance of:
((circle1.frame.width / 2) + (circle2.frame.width / 2))
If you're up to it, here's some code to help you on your way.
override func update(currentTime: CFTimeInterval) {
{
let distance = hypotf(Float(circle1.position.x - circle2.position.x), Float(circle1.position.y - circle2.position.y))
//calculate circle distances from each other
let radius = ((circle1.frame.width / 2) + (circle2.frame.width / 2))
//distance of circle positions
if distance != radius
{
//if distance is less or more than radius
let pointA = circle1.position
let pointB = circle2.position
let pointC = CGPointMake(pointB.x + 2, pointB.y)
let angle_ab = atan2(pointA.y - pointB.y, pointA.x - pointB.x)
let angle_cb = atan2(pointC.y - pointB.y, pointC.x - pointB.x)
let angle_abc = angle_ab - angle_cb
//get angle of circles from each other using atan2
let vectorx = cos(angle_abc)
let vectory = sin(angle_abc)
//convert angle into vectors
let x = circle1.position.x + radius * vectorx
let y = circle1.position.y + radius * vectory
//get new coordinates from vector, radius and center circle position
circle2.position = CGPointMake(x, y)
//set new position
}
}
Well you need to write code to make sure the movable circle, is well movable.
But, this should work.
I haven't tested this yet though, and I haven't even learned geometry let alone trig in school yet.
If I'm reading your question as you intended it, you can still use joints- just create actions with Inverse Kinematic constraints that allow rotation and translation around the contacting circles' joint.
https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKAction_Ref/index.html#//apple_ref/doc/uid/TP40013017-CH1-SW72

Make a line thicker in 3D?

In reference to this question
Drawing a line between two points using SceneKit
I'm drawing a line in 3D and want to make it thicker by using this code
func renderer(aRenderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: NSTimeInterval) {
//Makes the lines thicker
glLineWidth(20)
}
but it doesn't work, iOS 8.2.
Is there another way?
Update
From the docs
https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNSceneRendererDelegate_Protocol/index.html#//apple_ref/occ/intfm/SCNSceneRendererDelegate/renderer:updateAtTime:
I did add SCNSceneRendererDelegate and a valid line width but still could not get the line width to increase.
You cannot assign any number to glLineWidth().
You can check the range of possible values of glLineWidth()by:
glGetFloatv(GL_LINE_WIDTH_RANGE,sizes);
One crazy idea is to use a cylinder for drawing lines ;). I use it when I want to have nice and controllable lines but I am not aware of a handy OpenGl function to do so.
#G Alexander: here you go my implementation of cylinder. It is a bit tedious but it is what I have at the moment.
If you give me points p0 and p1, Vector normal=(p1-p0).normalize() would be the axis of the cylinder.
pick point p2 that is not on the vector Normal.
q=(p2-p0).normalize();
normal.crossproduct(q)=v0;
normal.crossproduct(v0)=v1;
Having these two vectors you can have circles with any radius that are stacked along the axis of the cylinder using the following function (A cylinder is a stack of circles):
public Circle make_circle(Point center, Vector v0, Vector v1, double radius)
{
Circle c;
for (double i = 0; i < 2 * Math.PI; i += 0.05)
{
Point p = new Point(center + radius * Math.Cos(i) * v0 + radius * Math.Sin(i) * v1);
c.Add(p);
}
return c;
}
You only need to make circles using this function along the axis of the cylinder:
List<Circle> Cylinder = new List<Circle>();
for(double i=0;i<1;i+=0.1)
{
Cylinder.add( make_circle(P0+i*normal, v0, v1,radius);
}
Now you should take two consecutive circles and connect them with quads by sampling uniformly.
I have implemented it this way since I had circles implemented already.
A simpler way to implement is make the circle along the x axis and then rotate and translate it to p0 and make it align with normal or to use gluCylinder if you are the fan of Glu....
Hopefully it works for you.

How to support larger tiles

I've been working on a small platformer and decided to try new collision detection. I followed ray wenderlich's tutorial on how to make an iOS platformer and a couple of questions came up. In the tutorial its set up to support a very specific tile size and I was wondering how to modify it correctly to support a tile size of 80x80. This was the method used to get the tile coordinates and bounding boxes.
- (CGPoint)tileCoordForPosition:(CGPoint)position
{
float x = floor(position.x / map.tileSize.width);
float levelHeightInPixels = map.mapSize.height * map.tileSize.height;
float y = floor((levelHeightInPixels - position.y) / map.tileSize.height);
return ccp(x, y);
}
-(CGRect)tileRectFromTileCoords:(CGPoint)tileCoords
{
float levelHeightInPixels = map.mapSize.height * map.tileSize.height;
CGPoint origin = ccp(tileCoords.x * map.tileSize.width, levelHeightInPixels - ((tileCoords.y + 1) * map.tileSize.height));
return CGRectMake(origin.x, origin.y, map.tileSize.width, map.tileSize.height);
}
Since this code uses the values from the tilemap, if setup correctly in the tilemap you don't need to change the code.
I certainly don't see any magic numbers, which is good. Only fools and wizards use magic numbers. :)

Approximating a contour with rotated rectangles

After some color detection and binary thresholding, I use the following code to find the contours and draw them onto the image:
using (MemStorage stor = new MemStorage())
{
Contour<Point> contours = img.FindContours(
Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST,
stor);
for (; contours != null; contours = contours.HNext)
{
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * poly, stor);
img.Draw(currentContour,new Bgr(255,255,255),1);
Rectangle currentrect = currentContour.BoundingRectangle;
img.Draw(currentrect,new Bgr(255,255,255),2);
}
}
My problem is, as I expected, that if the contour is a rectangle but is rotated in the image, the bounding rectangle does not change its orientation to fit the rotation. Is their another way to accomplish this function? Any help would be greatly appreciated.
Yes, there is another way to accomplish this. You can use
contour.GetConvexHull(ORIENTATION.CV_CLOCKWISE);
using Moments, you can easily get the orientation and adjust the rectangle accordingly.
The method you are looking for is:
PointCollection.MinAreaRect(points);
Worked example is here:
http://www.emgu.com/wiki/index.php/Minimum_Area_Rectangle_in_CSharp
Complete documentation (which has little more than the above) is located here:
http://www.emgu.com/wiki/files/2.4.0/document/html/0d5fd148-0afb-fdbf-e995-6dace8c8848d.htm

UIImage transform/scaling issues

Finally, I have a reason to ask something, instead of scouring endless hours of the joys of Stack Overflow.
Here's my situation: I have an UIImageView with one UIImage inside it. I'm transforming the entire UIImageView via CGAffineTranforms, to scale it height-wise and keep it at a specific angle.
I'm feeding it this transform data through two CGPoints, so it's essentially just calculating the angle and scale between these two points and transforming.
Now, the transforming is working like a charm, but I recently came across the UIImage method resizableImageWithCapInsets, which works just fine if you set the frame of the image manually (ie. scale using a frame), but it seems that using transforms overrides this, which I guess is sort of to be expected since it's Core Graphics doing it's thing.
My question is, how would I go about either a) adding cap insets after transforming the image or b) doing the angle & scaling via a frame?
Note that the two points providing the data are touch points, so they can differ very much, which is why creating a scaled rectangle at a specific angle is tricky at best.
To keep you code hungry geniuses happy, here's a snippet of the current way I'm handling scaling (only doing cap insets when creating the UIImage):
float xDiff = (PointB.x - PointA.x) / 2;
float yDiff = (PointB.y - PointA.y) / 2;
float angle = [self getRotatingAngle:PointA secondPoint:PointB];
CGPoint pDiff = CGPointMake(PointA.x + xDiff, PointA.y + yDiff);
self.center = pDiff;
// Setup a new transform
// Set it up with a scale and an angle
double distance = sqrt(pow((PointB.x - PointA.x), 2.0) + pow((PointB.y - PointA.y), 2.0));
float scale = 1.0 * (distance / self.image.size.height);
CGAffineTransform transformer = self.transform;
transformer = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, scale), CGAffineTransformMakeRotation(angle));
// Apply the transformer
self.transform = transformer;
Adding a proper answer to this. The answer to the problem can be found here.

Resources