使用 VNRectangleObservation 裁剪 UIImage
Posted
技术标签:
【中文标题】使用 VNRectangleObservation 裁剪 UIImage【英文标题】:Cropping UIImage Using VNRectangleObservation 【发布时间】:2019-12-30 22:36:09 【问题描述】:我正在使用 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,但我目前忽略了这一点。
裁剪后的图像通常看起来是正确的尺寸,但它向上和向左移动,从而切断了文档的下部和右侧。任何帮助将不胜感激。
【问题讨论】:
嗨,您能否分享有问题的原始图像,并与实际截图和想要的截图更好地分享,这将有所帮助。如果图像的原始尺寸不适合裁剪尺寸,则不会显示预期。 【参考方案1】:对于发现此问题的任何其他人,问题似乎是 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);
imageList
是 List<UImage>
,因为我正在处理多个检测到的矩形。
observation
是 VNRectangleObservation
类型的单个观察。
【讨论】:
【参考方案2】:裁剪后的图像通常看起来是正确的尺寸,但它向上和向左移动,从而切断了文档的下部和右侧。
来自 Apple 文档 CGImageCreateWithImageInRect ,有关于裁剪尺寸的讨论。
CGImageCreateWithImageInRect 执行以下任务来创建子图像:
调用CGRectIntegral
函数将rect参数调整为整数范围。
它与矩形相交,矩形的原点为(0,0)
,大小等于image参数指定的图片大小。
它读取生成的矩形内的像素,将其中的第一个像素视为子图像的原点。
如果W
和H
分别是图像的宽度和高度,那么点(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 = 0
,y = 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
仅显示缩放版本,请务必指定子矩形相对于原始图像的完整大小的坐标。
【讨论】:
感谢您的深入回复。不幸的是,种植对我来说从来都不是问题。我相信我的问题源于多种因素。 1. CGImage的东西左下角是0,0,而UIImage的左上角是0,0。 2. 创建 UIImage 时,我正在做一些定位工作。删除似乎有帮助。 3. ImageView 正在做一些它自己的缩放,这让事情变得困难。解决这些问题让我每次都能获得可靠的好收成。感谢您抽出宝贵时间回复。 @ottermatic 这是个好问题,对其他人会有帮助。如果使用CGRect
为CGImage
和UIImage
设置rect,则(0,0)
全部位于左上角。如果回答对你有帮助,有时间可以标记一下:)以上是关于使用 VNRectangleObservation 裁剪 UIImage的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)