CGContext转换,以提取旋转矩形 [英] CGContext transformation, to extract rotated rect

查看:86
本文介绍了CGContext转换,以提取旋转矩形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的意图是编写一个函数,该函数可以提取较大图像的旋转矩形部分。用中心点(从0到整个图像宽度/高度)的大小和旋转角度描述该旋转的矩形部分。

My intention is to write a function which can extract a rotated rectangular portion of a larger image. That rotated rectangular portion is described with a center point (from 0,0 to full image width/height) a size, and a rotation angle.

我担心我不了解CGContexts。我知道旋转后,我的坐标空间旋转了。

I worry that I'm not understanding something about CGContexts. I know that after a rotation, my coordinate space is rotated.

该函数始终在角度为0时起作用,而在角度较小时似乎是正确的。但是,随着角度的增加,一切都会偏移不正确。

This function always works if the angle is 0 and appears to be correct if the angle is small. However, as the angle increases, everything is offset improperly.

我正在使用类似于图像变换的仿射变换来计算左上角,以避免出现任何不准确之处。我还尝试通过对其应用图像变换来进一步更改左上角,以及图像变换的逆变换(只是作为一个随机想法)。

I am calculating the top-left corner with an affine transform similar to the image transformation to avoid any inaccuracy. I have also tried further changing the top-left corner by applying the image transformation to it, as well as the inverse of the image transformation (just as a random thought).

这种方法行得通吗?我在某处是否缺少空间变换?

Will this approach work? Am I missing a space transformation somewhere?

注意:通过绘制完整图像然后在正确位置绘制黑色矩形非常容易使图像区域变黑具有正确的大小和旋转度。鉴于此,我知道我的输入是正确的。

Note: It was extremely easy to black out the image area by drawing the full image and then drawing a black rectangle at the correct position with the right size and rotation. Given this, I know my inputs are correct.

可视化效果:

这代表了完整图像,以及我要采样的旋转矩形:

This represents the full image, and the rotated rect I am trying to sample:

此图像代表此功能的所需输出:

This image represents the desired output of this function:

- (UIImage*) croppedImage:(UIImage*) image center:(CGPoint) rotationCenter size:(CGSize) size rotation:(CGFloat) rotation
{
    CGFloat fullWidth = image.size.width;
    CGFloat fullHeight = image.size.height;
    CGRect imageRect = CGRectMake(0, 0, fullWidth, fullHeight);

    //must convert UI space to CG space, in this case that just means adjusting the y coordinate
    rotationCenter.y = fullHeight - rotationCenter.y;

    CGFloat width = size.width;
    CGFloat height = size.height;

    int flags = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGContextRef btx = CGBitmapContextCreate(NULL, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), flags);
    CGContextSetAllowsAntialiasing(btx, YES);
    CGContextSetShouldAntialias(btx, YES);

    //use a transformation to rotate at the center of the request area
    CGAffineTransform imageTransform = CGAffineTransformIdentity;
    imageTransform = CGAffineTransformTranslate(imageTransform, rotationCenter.x, rotationCenter.y);
    imageTransform = CGAffineTransformRotate(imageTransform, rotation);
    imageTransform = CGAffineTransformTranslate(imageTransform, -rotationCenter.x, -rotationCenter.y);

    //use a transformation to determine the top-left coordinate of the rect
    CGAffineTransform ptTransform = CGAffineTransformIdentity;
    ptTransform = CGAffineTransformTranslate(ptTransform, rotationCenter.x, rotationCenter.y);
    ptTransform = CGAffineTransformRotate(ptTransform, rotation);
    ptTransform = CGAffineTransformTranslate(ptTransform, -width/2.0, -height/2.0);

    //this gets me the position of the top-left corner of the image no matter the rotation
    CGPoint topleft  = CGPointApplyAffineTransform(CGPointZero, ptTransform);

    CGContextConcatCTM(btx, imageTransform);

    //move the image away from the origin, to align origin with where i want my image sampled from
    CGContextTranslateCTM(btx, -topleft.x,
                                -topleft.y);

    //Close... but wrong
    CGContextDrawImage(btx, imageRect, image.CGImage);

    CGImageRef img = CGBitmapContextCreateImage(btx);
    UIImage* uiimage =  [UIImage imageWithCGImage:img scale:image.scale orientation:image.imageOrientation];

    CGContextRelease(btx);
    CGImageRelease(img);

    return uiimage;
}


推荐答案

您所描述的,我相信,是这样的事情:

What you are describing, I believe, is this sort of thing:

这是一个实际运行的iOS应用,因此您可以看到我所做的事情:在第一张图片中,我用蓝色绘制了要捕获的矩形,并显示了产生图像视图;在第二张图片中,我已经捕获了它,并在图像视图中显示了结果。

That is an actual running iOS app, so you can see what I've done: in the first picture, I've drawn in blue the rectangle I intend to capture, and shown the result in an image view; in the second picture, I've captured it, and shown that result in an image view.

正如您仔细观察第二张图像的边缘所看到的,我们已经捕获了完全是蓝色矩形。

As you can see by looking carefully at the edges of the second image, we've captured the blue rectangle contents exactly.

所以现在我想您想知道我是怎么做到的?使用三个信息绘制蓝色矩形:矩形的左上角 topLeft ,矩形的大小 size ,以及旋转 rot 。为简化起见,我不理会您关于中心的讨论。我已经绕左上方旋转了。

So now I suppose you want to know how I did that? The blue rectangle was drawn using three pieces of information: the top left of the rectangle topLeft, the size of the rectangle size, and the rotation rot. To simplify things, I have disregarded your talk about the "center"; I have rotated around the top left.

然后,通过创建大小为 size 的图形上下文并旋转它来捕获第二张图像 rot 的负数,并在 topLeft 的负数处绘制完整的原始图像。实际的绘图部分只有两行代码(抱歉,我现在在Swift中编写并考虑过,但我确定您可以翻译):

Then the second image was captured by creating a graphics context of size size, rotating it the negative of rot, and drawing the full original image at the negative of topLeft. The actual drawing part is just two lines of code (sorry, I write and think in Swift these days, but I'm sure you can translate):

CGContextRotateCTM(context, -rot)
im.drawAtPoint(CGPointMake(-topLeft.x, -topLeft.y))

所以我想我的答案最终是:这很容易并且可以按您期望的方式工作,如果您将转换要执行的操作的原始描述,从而得到一个 topLeft 而不是中心。

So I guess my answer ultimately is: this is very easy and works just as you would expect, if you will turn convert your original description of what you want to do so that there is a topLeft instead of a center.

这篇关于CGContext转换,以提取旋转矩形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆