I am displaying text using Quartz. Here is my code:
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGContextSelectFont(myContext, "Helvetica", 12, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(myContext, 8);
CGContextSetTextDrawingMode(myContext, kCGTextFillStroke);
CGContextSetRGBFillColor(myContext, 0, 0, 0, 1);
CGContextSetRGBStrokeColor(myContext, 0, 0, 0, 1);
CGContextSetTextMatrix(myContext,CGAffineTransformMake(1, 0, 0, -1, 0, 0));
CGContextShowTextAtPoint(myContext, textOrigin.x, textOrigin.y,[way.name UTF8String],[way.name length]);
This displays my text the right way up and in the right direction, however I also need to add a rotation to the text using CGAffineTransformMakeRotation(angle);. I can't seem to work out how to aply two affine transforms to the text matrix, though, without one overwriting the other. Any help would be great.
You can combine matrices with CGAffineTransformConcat, e.g.
CGAffineTransform finalTransf = CGAffineTransformConcat(t1, t2);
If you just need to apply rotation to an existing matrix, use CGAffineTransformRotate, e.g.
CGAffineTransform t = CGAffineTransformMake(1, 0, 0, -1, 0, 0);
CGAffineTransform t = CGAffineTransformRotate(t, M_PI/2);
CGContextSetTextMatrix(myContext, t);
To supplement #kennytm's answer, to apply more than two transforms you can do the following:
var t = CGAffineTransformIdentity
t = CGAffineTransformTranslate(t, CGFloat(100), CGFloat(300))
t = CGAffineTransformRotate(t, CGFloat(M_PI_4))
t = CGAffineTransformScale(t, CGFloat(-1), CGFloat(2))
// ... add as many as you want, then apply it to to the view
imageView.transform = t
Go here to see my full answer.
Related
Apologies if this seems trivial - relatively new to openCV.
Essentially, I'm trying to create a function that can take in a camera's image, the known world coordinates of that image, and the world coordinates of some other point 2, and then transform the camera's image to what it would look like if the camera was at point 2. From my understanding, the best way to tackle this is using a homography transformation using the warpPerspective tool.
The experiment is being done inside the Unreal Game simulation engine. Right now, I essentially read the data from the camera, and add a set transformation to the image. However, I seem to be doing something wrong as the image is looking something like this (original image first then distorted image):
Original Image
Distorted Image
This is the current code I have. Basically, it reads in the texture from Unreal engine, and then gets the individual pixel values and puts them into the openCV Mat. Then I try and apply my warpPerspective transformation. Interestingly, if I just try a simple warpAffine transformation (rotation), it works fine. I have seen this questions: Opencv virtually camera rotating/translating for bird's eye view, but I cannot figure out what I am doing wrong vs. their solution. I would really appreciate any help or guidance any of you may have. Thanks in advance!
ROSCamTextureRenderTargetRes->ReadPixels(ImageData);
cv::Mat image_data_matrix(TexHeight, TexWidth, CV_8UC3);
cv::Mat warp_dst, warp_rotate_dst;
int currCol = 0;
int currRow = 0;
cv::Vec3b* pixel_left = image_data_matrix.ptr<cv::Vec3b>(currRow);
for (auto color : ImageData)
{
pixel_left[currCol][2] = color.R;
pixel_left[currCol][1] = color.G;
pixel_left[currCol][0] = color.B;
currCol++;
if (currCol == TexWidth)
{
currRow++;
currCol = 0;
pixel_left = image_data_matrix.ptr<cv::Vec3b>(currRow);
}
}
warp_dst = cv::Mat(image_data_matrix.rows, image_data_matrix.cols, image_data_matrix.type());
double rotX = (45 - 90)*PI / 180;
double rotY = (90 - 90)*PI / 180;
double rotZ = (90 - 90)*PI / 180;
cv::Mat A1 = (cv::Mat_<float>(4, 3) <<
1, 0, (-1)*TexWidth / 2,
0, 1, (-1)*TexHeight / 2,
0, 0, 0,
0, 0, 1);
// Rotation matrices Rx, Ry, Rz
cv::Mat RX = (cv::Mat_<float>(4, 4) <<
1, 0, 0, 0,
0, cos(rotX), (-1)*sin(rotX), 0,
0, sin(rotX), cos(rotX), 0,
0, 0, 0, 1);
cv::Mat RY = (cv::Mat_<float>(4, 4) <<
cos(rotY), 0, (-1)*sin(rotY), 0,
0, 1, 0, 0,
sin(rotY), 0, cos(rotY), 0,
0, 0, 0, 1);
cv::Mat RZ = (cv::Mat_<float>(4, 4) <<
cos(rotZ), (-1)*sin(rotZ), 0, 0,
sin(rotZ), cos(rotZ), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
// R - rotation matrix
cv::Mat R = RX * RY * RZ;
// T - translation matrix
cv::Mat T = (cv::Mat_<float>(4, 4) <<
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, dist,
0, 0, 0, 1);
// K - intrinsic matrix
cv::Mat K = (cv::Mat_<float>(3, 4) <<
12.5, 0, TexHeight / 2, 0,
0, 12.5, TexWidth / 2, 0,
0, 0, 1, 0
);
cv::Mat warp_mat = K * (T * (R * A1));
//warp_mat = cv::getRotationMatrix2D(srcTri[0], 43.0, 1);
//cv::warpAffine(image_data_matrix, warp_dst, warp_mat, warp_dst.size());
cv::warpPerspective(image_data_matrix, warp_dst, warp_mat, image_data_matrix.size(), CV_INTER_CUBIC | CV_WARP_INVERSE_MAP);
cv::imshow("distort", warp_dst);
cv::imshow("imaage", image_data_matrix)
I have plus sign which i drawn using lines. Now i want to rotate these lines, so that it will look like a X sign. I tried rotating the lines but no way.
self.shapeLayer1.transform = CATransform3DMakeRotation( (CGFloat) (GLKMathDegreesToRadians(-45)),0, 0, 0)
self.shapeLayer2.transform = CATransform3DMakeRotation( (CGFloat) (GLKMathDegreesToRadians(-45)), 0, 0, 0)
You guys can see that, i put zeros in the x, y, z places.!! i tries different values.But colud not get the actual rotation. If somebody got any idea, Please share with me. Sometimes the lines move to another point and rotates.
It looks like the x,y,z parameters define the axis of rotation. Since we want to rotate around xy, your axis of rotation should be the z axis, or 0,0,1.
self.shapeLayer1.transform = CATransform3DMakeRotation( (CGFloat) (GLKMathDegreesToRadians(45)),0, 0, 1)
self.shapeLayer2.transform = CATransform3DMakeRotation( (CGFloat) (GLKMathDegreesToRadians(-45)), 0, 0, 1)
Regarding the issue you're having with rotation around a non-centerpoint of the line, if you're unable to redraw the line centred around 0,0,0, you can also use the following code to transform it to 0,0,0, rotate, then transform it back to where you need it:
CGFloat tx = 1.0,ty = 2.0,tz = 0; // Modify these to the values you need
CATransform3D t = CATransform3DMakeTranslation (tx, ty, tz);
t = CATransform3DRotate(t,(CGFloat) (GLKMathDegreesToRadians(45)),0, 0, 1);
self.shapeLayer1.transform = CATransform3DTranslate(t,-tx,-ty,-tz);
CATransform3D t = CATransform3DMakeTranslation (tx, ty, tz);
t = CATransform3DRotate(t,(CGFloat) (GLKMathDegreesToRadians(-45)),0, 0, 1);
self.shapeLayer2.transform = CATransform3DTranslate(t,-tx,-ty,-tz);
I need to write some text rotated by 90 degrees. I first tried with a UILabel rotated with CGAffineTransform:
this.myLabel.Center = this.myLabel.Frame.Location;
this.myLabel.Transform = CGAffineTransform.MakeRotation (-(float)Math.PI / 2.0f);
It rotated it just right, but fonts now look all blurred and difficult to read.
Is there a way to use the CoreText library to make a simple text rotation in a UILabel that doesn't look blurred?
Thank you in advance!
In case you missed it Xamarin provides a sample on github that use CoreText to draw (non-rotated) text.
Since the text ends up as a path it should not be hard to rotate the whole text. OTOH CoreText is more much complicated than the older API - that's the price to pay to get (way) more control.
You could use Core Graphics. It's a little involved, but will do the trick.
A sample would be:
void MyDrawText (CGContextRef myContext, CGRect contextRect) // 1
{
float w, h;
w = contextRect.size.width;
h = contextRect.size.height;
CGAffineTransform myTextTransform; // 2
CGContextSelectFont (myContext, // 3
"Helvetica-Bold",
h/10,
kCGEncodingMacRoman);
CGContextSetCharacterSpacing (myContext, 10); // 4
CGContextSetTextDrawingMode (myContext, kCGTextFillStroke); // 5
CGContextSetRGBFillColor (myContext, 0, 1, 0, .5); // 6
CGContextSetRGBStrokeColor (myContext, 0, 0, 1, 1); // 7
myTextTransform = CGAffineTransformMakeRotation (myRadianRotation); // 8
CGContextSetTextMatrix (myContext, myTextTransform); // 9
CGContextShowTextAtPoint (myContext, 40, 0, "Quartz 2D", 9); // 10
}
Without my doing anything to request upside down text, CGContextShowText is drawing it in that fashion. It is a mirror image vertically of what it should be.
float font_size = 19.;
CGContextSelectFont (context, "Helvetica", font_size, kCGEncodingMacRoman);
CGContextSetTextDrawingMode (context, kCGTextFill);
CGContextSetRGBStrokeColor (context, 255, 0, 0, 0);
CGContextSetRGBFillColor (context, 255, 0, 0, 0);
CGContextSetTextPosition (context, x, y);
CGContextShowText (context, cstring, strlen(cstring));
How can I fix this? Also why is this the default drawing mode?
Thanks.
This "upsidedownness" commonly comes into play when the API renders to your cgContext from top to bottom, but somehow you're drawing from bottom to top. Anyway, the 2 line solution I use is:
CGAffineTransform trans = CGAffineTransformMakeScale(1, -1);
CGContextSetTextMatrix(tex->cgContext, trans);
Swift 3
let context = UIGraphicsGetCurrentContext()!
let textTransform = CGAffineTransform(scaleX: 1.0, y: -1.0)
context.textMatrix = textTransform
The best solution to this problem is to simply call this at the beginning of your draw routine. (Make sure to only call it once.)
CGAffineTransform transform;
transform = CGAffineTransformConcat(CGContextGetTextMatrix(ctx),
CGAffineTransformMake(1.0, 0.0, 0.0,
-1.0, 0.0, 0.0));
CGContextSetTextMatrix(ctx, transform);
I've a calibrated camera where I exactly know the intrinsic and extrinsic data. Also the height of the camera is known. Now I want to virtually rotate the camera for getting a Bird's eye view, such that I can build the Homography matrix with the three rotation angles and the translation.
I know that 2 points can be transformed from one image to another via Homography as
x=K*(R-t*n/d)K^-1 * x'
there are a few things I'd like to know now:
if I want to bring back the image coordinate in ccs, I have to multiply it with K^-1, right? As Image coordinate I use (x',y',1) ?
Then I need to built a rotation matrix for rotating the ccs...but which convention should I use? And how do I know how to set up my WCS?
The next thing is the normal and the distance. Is it right just to take three points lying on the ground and compute the normal out of them? and is the distance then the camera height?
Also I'd like to know how I can change the height of the virtually looking bird view camera, such that I can say I want to see the ground plane from 3 meters height. How can I use the unit "meter" in the translation and homography Matrix?
So far for now, it would be great if someone could enlighten and help me. And please don't suggest generating the bird view with "getperspective", I ve already tried that but this way is not suitable for me.
Senna
That is the code i would advise (it's one of mine), to my mind it answers a lot of your questions,
If you want the distance, i would precise that it is in the Z matrix, the (4,3) coefficient.
Hope it will help you...
Mat source=imread("Whatyouwant.jpg");
int alpha_=90., beta_=90., gamma_=90.;
int f_ = 500, dist_ = 500;
Mat destination;
string wndname1 = getFormatWindowName("Source: ");
string wndname2 = getFormatWindowName("WarpPerspective: ");
string tbarname1 = "Alpha";
string tbarname2 = "Beta";
string tbarname3 = "Gamma";
string tbarname4 = "f";
string tbarname5 = "Distance";
namedWindow(wndname1, 1);
namedWindow(wndname2, 1);
createTrackbar(tbarname1, wndname2, &alpha_, 180);
createTrackbar(tbarname2, wndname2, &beta_, 180);
createTrackbar(tbarname3, wndname2, &gamma_, 180);
createTrackbar(tbarname4, wndname2, &f_, 2000);
createTrackbar(tbarname5, wndname2, &dist_, 2000);
imshow(wndname1, source);
while(true) {
double f, dist;
double alpha, beta, gamma;
alpha = ((double)alpha_ - 90.)*PI/180;
beta = ((double)beta_ - 90.)*PI/180;
gamma = ((double)gamma_ - 90.)*PI/180;
f = (double) f_;
dist = (double) dist_;
Size taille = source.size();
double w = (double)taille.width, h = (double)taille.height;
// Projection 2D -> 3D matrix
Mat A1 = (Mat_<double>(4,3) <<
1, 0, -w/2,
0, 1, -h/2,
0, 0, 0,
0, 0, 1);
// Rotation matrices around the X,Y,Z axis
Mat RX = (Mat_<double>(4, 4) <<
1, 0, 0, 0,
0, cos(alpha), -sin(alpha), 0,
0, sin(alpha), cos(alpha), 0,
0, 0, 0, 1);
Mat RY = (Mat_<double>(4, 4) <<
cos(beta), 0, -sin(beta), 0,
0, 1, 0, 0,
sin(beta), 0, cos(beta), 0,
0, 0, 0, 1);
Mat RZ = (Mat_<double>(4, 4) <<
cos(gamma), -sin(gamma), 0, 0,
sin(gamma), cos(gamma), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
// Composed rotation matrix with (RX,RY,RZ)
Mat R = RX * RY * RZ;
// Translation matrix on the Z axis change dist will change the height
Mat T = (Mat_<double>(4, 4) <<
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, dist,
0, 0, 0, 1);
// Camera Intrisecs matrix 3D -> 2D
Mat A2 = (Mat_<double>(3,4) <<
f, 0, w/2, 0,
0, f, h/2, 0,
0, 0, 1, 0);
// Final and overall transformation matrix
Mat transfo = A2 * (T * (R * A1));
// Apply matrix transformation
warpPerspective(source, destination, transfo, taille, INTER_CUBIC | WARP_INVERSE_MAP);
imshow(wndname2, destination);
waitKey(30);
}
This code works for me but I don't know why the Roll and Pitch angles are exchanged. When I change "alpha", the image is warped in pitch and when I change "beta" the image in warped in roll. So, I changed my rotation matrix, as can be seen below.
Also, the RY has a signal error. You can check Ry at: http://en.wikipedia.org/wiki/Rotation_matrix.
The rotation metrix I use:
Mat RX = (Mat_<double>(4, 4) <<
1, 0, 0, 0,
0, cos(beta), -sin(beta), 0,
0, sin(beta), cos(beta), 0,
0, 0, 0, 1);
Mat RY = (Mat_<double>(4, 4) <<
cos(alpha), 0, sin(alpha), 0,
0, 1, 0, 0,
-sin(alpha), 0, cos(alpha), 0,
0, 0, 0, 1);
Mat RZ = (Mat_<double>(4, 4) <<
cos(gamma), -sin(gamma), 0, 0,
sin(gamma), cos(gamma), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
Regards