Как обрезать изображение по координатам VNRecognizedObjectObservation в Swift?
Мне нужно обрезать UIImage из признанных VNRecognizedObjectObservation и VNImageRectForNormalizedRect. Я пробовал много способов обрезки изображений, но ничего не работает, только один метод был близок, но не совсем обрезан, другие возвращали черное изображение (или не в прямом).
@IBOutlet weak var recognitionImageView: UIImageView!
var chosenImage: UIImage?
private var bufferSize: CGSize = .zero
func handleClassifications(request: VNRequest, error: Error?) {
DispatchQueue.main.async { [weak self] in
guard let self = self, let predictions = request.results as? [VNRecognizedObjectObservation] else { return }
let objectBounds = VNImageRectForNormalizedRect(predictions.first!.boundingBox, Int(self.bufferSize.width), Int(self.bufferSize.height))
let img = self.chosenImage!.cropped(rect: objectBounds)
self.recognitionImageView.image = img
}
}
Средство выбора изображений
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let selectedImage = info[.originalImage] as? UIImage
else {
fatalError("")
}
chosenImage = selectedImage
recognitionImageView.image = selectedImage
let heightInPoints = selectedImage.size.height
let heightInPixels = heightInPoints * selectedImage.scale
let widthInPoints = selectedImage.size.width
let widthInPixels = widthInPoints * selectedImage.scale
bufferSize.height = heightInPixels
bufferSize.width = widthInPixels
updateClassifications(for: selectedImage)
}
Обрезка изображения, но большинство проверенных решений возвращают черный экран или неправильное изображение
private func cropImage(object: VNDetectedObjectObservation) -> CGImage? {
let objectBounds = VNImageRectForNormalizedRect(object.boundingBox, Int(self.bufferSize.width), Int(self.bufferSize.height))
let width = objectBounds.width * CGFloat(self.detectable!.width)
let height = objectBounds.height * CGFloat(self.detectable!.height)
let x = objectBounds.origin.x * CGFloat(self.detectable!.width)
let y = (1 - objectBounds.origin.y) * CGFloat(self.detectable!.height) - height
let croppingRect = CGRect(x: x, y: y, width: width, height: height)
let image = self.detectable!.cropping(to: croppingRect)
return image
}
private func CropImage( image:UIImage , cropRect:CGRect) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(cropRect.size, false, 0);
let context = UIGraphicsGetCurrentContext();
context?.translateBy(x: 0.0, y: image.size.height);
context?.scaleBy(x: 1.0, y: -1.0);
context?.draw(image.cgImage!, in: CGRect(x:0, y:0, width:image.size.width, height:image.size.height), byTiling: false);
context?.clip(to: [cropRect]);
let croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage!;
}
func cropImage(imageToCrop:UIImage, toRect rect:CGRect) -> UIImage{
let imageRef:CGImage = imageToCrop.cgImage!.cropping(to: rect)!
let cropped:UIImage = UIImage(cgImage:imageRef)
return cropped
}
func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
return CGRect(x: x, y: y, width: width, height: height)
}
func cropImage2(image: UIImage, rect: CGRect, scale: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width / scale, height: rect.size.height / scale), true, 0.0)
image.draw(at: CGPoint(x: -rect.origin.x / scale, y: -rect.origin.y / scale))
let croppedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return croppedImage
}
Это расширение близко к тому, что мне нужно, но иногда оно возвращает неправильное изображение. Я знаю, что это неправильно, потому что у меня boundingBoxView с блоками распознавания
func cropped(rect: CGRect) -> UIImage? {
let rad: (Double) -> CGFloat = { deg in
return CGFloat(deg / 180.0 * .pi)
}
var rectTransform: CGAffineTransform
switch imageOrientation {
case .left:
let rotation = CGAffineTransform(rotationAngle: rad(90))
rectTransform = rotation.translatedBy(x: 0, y: -size.height)
case .right:
let rotation = CGAffineTransform(rotationAngle: rad(-90))
rectTransform = rotation.translatedBy(x: -size.width, y: 0)
case .down:
let rotation = CGAffineTransform(rotationAngle: rad(-180))
rectTransform = rotation.translatedBy(x: -size.width, y: -size.height)
default:
rectTransform = .identity
}
rectTransform = rectTransform.scaledBy(x: scale, y: scale)
let transformedRect = rect.applying(rectTransform)
let imageRef = cgImage!.cropping(to: transformedRect)!
let result = UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
return result
}