使用 VNRectangleObservation 裁剪 UIImage

Cropping UIImage Using VNRectangleObservation

我正在使用 Vision 框架检测所拍摄照片中的矩形文档。检测并绘制文档周围的路径运行良好。然后我想将图像裁剪为仅检测到的文档。我成功裁剪了图像,但坐标似乎没有对齐,裁剪后的图像只是检测到的文档的一部分,其余只是文档后面的桌子。我正在使用以下裁剪代码:

private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
    var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
    using (var cgImage = image.CGImage.WithImageInRect(drawRect))
    {
        var croppedImage = UIImage.FromImage(cgImage);
        return croppedImage;
    };
}

使用以下参数:

图像与我成功绘制矩形路径的 UIImage 相同。

rect 是 VNRectangleObservation.BoundingBox。这是标准化的,所以我使用 image.size 对其进行缩放。这与我在绘制矩形路径时所做的缩放比例相同。

比例是 1f,但我目前忽略了这一点。

裁剪后的图像通常看起来尺寸合适,但它向上和向左移动,切断了文档的下侧和右侧。任何帮助将不胜感激。

The cropped image generally seems to be the right size, but it is shifted up and to the left which cuts off the lower and right side of the document.

Apple 文档 CGImageCreateWithImageInRect 中有关于裁剪尺寸的讨论。

CGImageCreateWithImageInRect 执行以下任务来创建子图像:

  • 调用CGRectIntegral函数调整rect参数为整数范围

  • 将rect与原点(0,0)的矩形相交,大小等于image参数指定的图像大小

  • 它读取结果矩形内的像素,将其中的第一个像素视为子图像的原点。

如果WH分别是图像的宽度和高度,那么点(0,0)对应图像数据的第一个像素。点(W–1, 0)是图像数据第一行的最后一个像素,而(0, H–1)是图像数据最后一行的第一个像素,(W–1, H–1)是图像数据的最后一个像素。图像数据的最后一行。

然后你可以用一张图片(大小是:1920 * 1080)签入你的本地项目,如下所示:

UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 1080), 1);
View.AddSubview(imageView);

CropImage 方法:

    private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
    var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
    using (var cgImage = image.CGImage.WithImageInRect(drawRect))
    {
        if(null != cgImage)
        {
            var croppedImage = UIImage.FromImage(cgImage);
            return croppedImage;
        }
        else
        {
            return image;
        }

    };
}

这将显示图像的原始尺寸:

现在您可以按如下方式修改裁剪后的尺寸:

UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 100), 1);
View.AddSubview(imageView);

这里我设置了x = 0y = 0,意思是从(0,0)开始,宽度是1920,高度是100。我只是裁剪原始 Image 的高度。效果如下:

那么如果修改x/y,裁剪后的图片会移动到其他区域进行裁剪。如下:

UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 100, 1920, 100), 1);
View.AddSubview(imageView);

然后你会发现它与第二个效果不同:

所以在裁剪图片的时候,你应该清楚image.CGImage.WithImageInRect(drawRect)drawRect

注意 来自文档:

请务必指定子矩形相对于原始图像全尺寸的坐标,即使 UIImageView 仅显示缩放版本。

对于发现此问题的任何其他人,问题似乎是在裁剪图像时 CGImage 旋转导致 VNRectangleObservation 不再对齐。我使用这篇文章 Tracking and Altering Images 来获得使用 CIFilter 的有效解决方案。裁剪代码如下:

var ciFilter = CIFilter.FromName("CIPerspectiveCorrection");
if (ciFilter == null) continue;

var width = inputImage.Extent.Width;
var height = inputImage.Extent.Height;
var topLeft = new CGPoint(observation.TopLeft.X * width, observation.TopLeft.Y * height);
var topRight = new CGPoint(observation.TopRight.X * width, observation.TopRight.Y * height);
var bottomLeft = new CGPoint(observation.BottomLeft.X * width, observation.BottomLeft.Y * height);
var bottomRight = new CGPoint(observation.BottomRight.X * width, observation.BottomRight.Y * height);

ciFilter.SetValueForKey(new CIVector(topLeft), new NSString("inputTopLeft"));
ciFilter.SetValueForKey(new CIVector(topRight), new NSString("inputTopRight"));
ciFilter.SetValueForKey(new CIVector(bottomLeft), new NSString("inputBottomLeft"));
ciFilter.SetValueForKey(new CIVector(bottomRight), new NSString("inputBottomRight"));

var ciImage = inputImage.CreateByApplyingOrientation(CGImagePropertyOrientation.Up);
ciFilter.SetValueForKey(ciImage, CIFilterInputKey.Image);
var outputImage = ciFilter.OutputImage;
var uiImage = new UIImage(outputImage);
imageList.Add(uiImage);

imageListList<UImage> 因为我正在处理多个检测到的矩形。

observationVNRectangleObservation.

类型的单个观察