用于在不移除图像的指定部分的情况下裁剪图像的算法

时间:2013-01-12 17:26:13

标签: ios objective-c crop cgrect

我希望写出来可能有助于解决我的问题。我有包含面孔的图像,我想重新调整这些图像,尊重纵横比,同时保持尽可能多的面部。

我想将图像裁剪为任意矩形,可以是高,短,正方形或任何高达4:1的宽高比。尽可能地,我想避免裁剪出我指定的面部或特征(作为图像矩形的内部矩形)。例如。我有一个(0,0,500,300)的图像矩形和一个(20,40,75,75)的特征矩形,我想将它(相对于它的纵横比)裁剪为(0,0,320,200的矩形) ),尽可能最小化裁剪面部矩形。

我有一个中心裁剪的工作实现,我确定图像的较大边,并根据相同的比例缩放另一边,将x和y设置为缩放w / h的中心 - 目标w / h。

为清楚起见,签名看起来像这样(在Obj-C中):

(CGRect)crop:(CGSize)sourceSize toFitSize:(CGSize)fitSize withoutCroppingRect:(CGRect)featuresRect

sourceSize是原始图片的大小,fitSize是我要将图片裁剪成的形状,而featuresRect是一个矩形,位于(0,0,sourceSize.width, sourceSize,height)的范围内

也许这应该作为“中心裁剪”完成,以特征矩形为中心?试图绕过这甚至意味着什么。

1 个答案:

答案 0 :(得分:0)

顺便说一句,我认为它可以满足您的需求,或者至少可以帮助您朝着正确的方向前进。输出rect保持与源图像rect相同的宽高比。

使用示例:

 CGRect sizedRect = [self cropSize:self.inputView.image.size
                         toFitSize:self.outputView.bounds.size
               withoutCroppingRect:self.regionOfInterest.frame];

 CGImageRef cgImage = self.inputView.image.CGImage;

 CGImageRef cgCroppedImage =  CGImageCreateWithImageInRect (
                                         cgImage,
                                         sizedRect
                                         );

 self.outputView.image = [UIImage imageWithCGImage:cgCroppedImage];

您需要考虑许多问题,尤其是:
- 您返回的rect可能比fitSize大,因为它不会裁剪featuresRect,因此您可能必须检查这个并在应用裁剪后缩放图像(或者适当地设置输出imageView的scaleToFit)。 - 您从哪里获得ROI框架数据?它是相对于原始源图像还是包含源图像的imageView。如果是后者,则需要确保源图像的大小为1:1,并使用imageView,因为裁剪矩形应用于图像,而不是图像视图。
- 输出imageView小于输入imageView。如果它更大,我不确定它会起什么作用,但它可能会引入类似的缩放问题 - 您需要添加被零除错误检查。

-     (CGRect)cropSize:(CGSize)sourceSize 
             toFitSize:(CGSize)fitSize
   withoutCroppingRect:(CGRect)featuresRect
{
    CGRect result = CGRectZero;
    BOOL fitSizeIsTaller;
    CGFloat sourceRatio = sourceSize.width / sourceSize.height;
    CGFloat fitRatio    = fitSize.width    / fitSize.height;
     if (sourceRatio > fitRatio)
            fitSizeIsTaller = YES;
     else   fitSizeIsTaller = NO;

        //size sourceRect to fitSize
    if (fitSizeIsTaller){
        result.size.width  = fitSize.width;
        result.size.height = result.size.width / sourceRatio;
    } else {
        result.size.height = fitSize.height;
        result.size.width  = result.size.height * sourceRatio;
    }
        //make sure it is at least as large as fitSize
    if (result.size.height < featuresRect.size.height) {
        result.size.height = featuresRect.size.height;
        result.size.width  = result.size.height * sourceRatio;
    }

    if (result.size.width  < featuresRect.size.width) {
        result.size.width  = featuresRect.size.width;
        result.size.height = result.size.width / sourceRatio;
    }

            //locate resultRect in center
    result.origin.x = (sourceSize.width  - result.size.width )/2;
    result.origin.y = (sourceSize.height - result.size.height)/2;

            //shift origin of result to make sure it includes ROI

    if (featuresRect.origin.x < result.origin.x )    //shift right?
              result.origin.x = featuresRect.origin.x;
    else
        if ((featuresRect.origin.x + featuresRect.size.width)  
               >  (result.origin.x + result.size.width))  //shift left?
            result.origin.x = (featuresRect.origin.x + featuresRect.size.width)
                            - result.size.width;

    if (featuresRect.origin.y < result.origin.y )    //shift up?
              result.origin.y = featuresRect.origin.y;
    else
        if ((featuresRect.origin.y + featuresRect.size.height)  
                > (result.origin.y + result.size.height))  //shift down?
            result.origin.y = (featuresRect.origin.y+featuresRect.size.height)
                            - result.size.height;
    return result;
}