CGContext 转换,提取旋转的矩形

CGContext transformation, to extract rotated rect

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

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

如果角度为 0,此功能始终有效,如果角度较小,则显示正确。但是,随着角度的增加,一切都偏移不当。

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

这种方法行得通吗?我在某处缺少 space 转换吗?

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

可视化:

这表示完整图像,以及我尝试采样的旋转矩形:

此图像表示此函数的所需输出:

- (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;
}

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

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

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

那么现在我想你想知道我是怎么做到的?蓝色矩形是使用三个信息绘制的:矩形的左上角 topLeft、矩形的大小 size 和旋转 rot。为简化起见,我忽略了您所说的“中心”;我已经绕左上角旋转了。

然后通过创建大小为 size 的图形上下文捕获第二张图像,将其旋转 rot 的负片,并在 topLeft 的负片处绘制完整的原始图像.真正的绘图部分只有两行代码(不好意思,我这几天写的和想的都是Swift,但我相信你能翻译):

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

所以我想我最终的答案是:这非常简单,并且可以像您预期的那样工作,如果您将转换您对想要执行的操作的原始描述,以便有一个 topLeft一个中心。