简体   繁体   English

使用 VNRectangleObservation 裁剪 UIImage

[英]Cropping UIImage Using VNRectangleObservation

I'm using the Vision framework to detect rectangular documents in a captured photo.我正在使用 Vision 框架来检测捕获的照片中的矩形文档。 Detecting and drawing a path around the document is working perfectly.检测和绘制围绕文档的路径工作正常。 I then want to crop the image to be only the detected document.然后我想将图像裁剪为仅检测到的文档。 I'm successfully cropping the image, but it seems the coordinates don't line up and the cropped image is only part of the detected document and the rest is just the desk behind the document.我成功裁剪了图像,但似乎坐标没有对齐,裁剪后的图像只是检测到的文档的一部分,其余部分只是文档后面的桌子。 I'm using the following cropping code:我正在使用以下裁剪代码:

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

Using the following parameters:使用以下参数:

image is the same UIImage that i successfully drew the rectangle path on.图像与我成功绘制矩形路径的 UIImage 相同。

rect is the VNRectangleObservation.BoundingBox. rect 是 VNRectangleObservation.BoundingBox。 This is normalized so i'm scaling it using the image.size.这是标准化的,所以我使用 image.size 对其进行缩放。 it's the same scaling i do when drawing the rectangle path.这与我在绘制矩形路径时所做的缩放相同。

scale is 1f, but i'm currently ignoring this.比例是 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.裁剪后的图像通常看起来大小合适,但它向上和向左移动,从而切断了文档的下侧和右侧。 Any help would be appreciated.任何帮助,将不胜感激。

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.裁剪后的图像通常看起来大小合适,但它向上和向左移动,从而切断了文档的下侧和右侧。

From Apple documentation CGImageCreateWithImageInRect , there is a discussion about the cropped size .从 Apple 文档CGImageCreateWithImageInRect 中,有一个关于裁剪尺寸的讨论。

CGImageCreateWithImageInRect performs the following tasks to create the subimage: CGImageCreateWithImageInRect执行以下任务来创建子图像:

  • It calls the CGRectIntegral function to adjust the rect parameter to integral bounds.它调用CGRectIntegral函数将 rect 参数调整为积分边界。

  • It intersects the rect with a rectangle whose origin is (0,0) and size is equal to the size of the image specified by the image parameter.它将矩形与原点为(0,0)且大小等于 image 参数指定的图像大小的矩形相交。

  • It reads the pixels within the resulting rectangle, treating the first pixel within as the origin of the subimage.它读取生成的矩形内的像素,将其中的第一个像素视为子图像的原点。

If W and H are the width and height of image, respectively, then the point (0,0) corresponds to the first pixel of the image data.如果WH分别是图像的宽度和高度,则点(0,0)对应于图像数据的第一个像素。 The point (W–1, 0) is the last pixel of the first row of the image data, while (0, H–1) is the first pixel of the last row of the image data and (W–1, H–1) is the last pixel of the last row of the image data.(W–1, 0)是图像数据第一行的最后一个像素, (0, H–1)是图像数据最后一行的第一个像素, (W–1, H–1)是图像数据最后一行的最后一个像素。

Then you can check in your local project with an image (size is : 1920 * 1080) as follow:然后您可以使用图像(大小为: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);

The CropImage Method : 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;
        }

    };
}

This will show the Original Size of Image :这将显示图像的原始大小:

在此处输入图片说明

Now you can modify the cropped size as follow :现在您可以修改裁剪尺寸如下:

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);

Here I set x = 0 , y = 0 , that means from (0,0) to start , and width is 1920 ,height is 100 .这里我设置x = 0 , y = 0 ,这意味着从(0,0)开始,宽度为1920 ,高度为100 I just crop the height of the original Image .我只是裁剪原始 Image 的高度。 The effect as follow :效果如下:

在此处输入图片说明

Then if you modify the x/y ,the cropped image will move to other area to crop .As follow:然后如果修改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);

Then you will see it's different with the second effect :然后你会看到它与第二个效果不同:

在此处输入图片说明

So when cropping an image , you should understand the drawRect of image.CGImage.WithImageInRect(drawRect) clearly .所以,裁剪图像时,你应该了解drawRectimage.CGImage.WithImageInRect(drawRect)明确。

Note from doc :来自文档的注释

Be sure to specify the subrectangle's coordinates relative to the original image's full size, even if the UIImageView shows only a scaled version.确保指定子矩形相对于原始图像完整尺寸的坐标,即使UIImageView仅显示缩放版本。

for anyone else that finds this, the issue seemed to be CGImage rotating when cropping the image which caused the VNRectangleObservation to not line up anymore.对于发现这一点的其他任何人,问题似乎是裁剪图像时CGImage旋转导致VNRectangleObservation不再排列。 I used this article, Tracking and Altering Images , to get a working solution using CIFilter .我使用这篇文章Tracking and CIFilter Images来获得一个使用CIFilter的工作解决方案。 Cropping code follows:裁剪代码如下:

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);

imageList is a List<UImage> since i'm handling multiple detected rectangles. imageList是一个List<UImage>因为我正在处理多个检测到的矩形。

observation is a single observation of type VNRectangleObservation . observationVNRectangleObservation类型的单个观察。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM