CGContext转换,提取旋转的rect

时间:2015-07-06 01:16:12

标签: ios quartz-graphics cgcontext cgaffinetransform

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

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

如果角度为0,此功能始终有效,如果角度较小,则此功能似乎正确。但是,随着角度的增加,一切都不正确地抵消了。

我正在使用类似于图像变换的仿射变换来计算左上角,以避免任何不准确。我还尝试通过对其应用图像变换来进一步更改左上角,以及图像变换的反转(就像随机想法一样)。

这种方法有效吗?我在某个地方错过了空间转换吗?

注意:通过绘制完整图像,然后使用正确的大小和旋转在正确的位置绘制黑色矩形,可以非常轻松地将图像区域遮挡。鉴于此,我知道我的输入是正确的。

可视化:

这表示完整的图像,以及我试图采样的旋转的rect: 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;
}

1 个答案:

答案 0 :(得分:1)

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

enter image description here

这是一个实际运行的iOS应用程序,所以你可以看到我做了什么:在第一张图片中,我用蓝色绘制了我打算捕捉的矩形,并在图像视图中显示结果;在第二张图片中,我捕获了它,并在图像视图中显示结果。

正如您所看到的那样,仔细观察第二张图像的边缘,我们已经准确地捕捉到了蓝色矩形内容。

所以现在我想你想知道我是怎么做到的?使用三条信息绘制蓝色矩形:矩形的左上角topLeft,矩形的大小size和旋转rot。为了简化事情,我忽略了你对“中心”的讨论;我绕左上角旋转。

然后通过创建大小为size的图形上下文,将其旋转为rot的负片,并以topLeft的负片绘制完整的原始图像来捕获第二个图像。实际绘图部分只有两行代码(对不起,我现在在Swift中编写并思考,但我相信你可以翻译):

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

所以我猜我的答案最终是:这很容易,并且正如您所期望的那样工作,如果您将转换您想要做的原始描述,以便有topLeft而不是中心。

相关问题