2017-01-04 5 views
0

У меня возникают трудности с обрезкой изображения; в настоящее время я хочу улучшить две вещи:Проблемы с обрезкой изображения

1) Качество фотографии ухудшается после обрезки.

2) После того, как сделана фотография, вид ориентации неверен.

В целом: Что происходит, качество фотографии после обрезки не соответствует стандарту, и когда изображение появляется в ImageView, оно поворачивается на 90 градусов; почему они происходят? Я пытаюсь обрезать изображение, основанное на представлении захваченного потока.

Вот кадрирование изображения:

func crop(capture : UIImage) -> UIImage { 

     let crop = cameraView.bounds 

     //CGRect(x:0,y:0,width:50,height:50) 

     let cgImage = capture.cgImage!.cropping(to: crop) 

     let image : UIImage = UIImage(cgImage: cgImage!) 

     return image 
    } 

Вот где я звоню урожай

func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 
     if let photoSampleBuffer = photoSampleBuffer { 
      let photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer, previewPhotoSampleBuffer: previewPhotoSampleBuffer) 
      var imageTaken = UIImage(data: photoData!) 

      //post photo 

      let croppedImage = self.crop(capture: imageTaken!) 

      imageTaken = croppedImage 
      self.imageView.image = imageTaken 
      // UIImageWriteToSavedPhotosAlbum(imageTaken!, nil, nil, nil) 
     } 
    } 

& Вот весь класс

import UIKit 
import AVFoundation 

class CameraVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVCapturePhotoCaptureDelegate { 

    var captureSession : AVCaptureSession? 
    var stillImageOutput : AVCapturePhotoOutput? 
    var previewLayer : AVCaptureVideoPreviewLayer? 
    @IBOutlet weak var imageView: UIImageView! 
    @IBOutlet var cameraView: UIView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Do any additional setup after loading the view. 
    } 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
     previewLayer?.frame = cameraView.bounds 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     captureSession = AVCaptureSession() 
     captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080 
     stillImageOutput = AVCapturePhotoOutput() 

     let backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 

     do { 

      let input = try AVCaptureDeviceInput(device: backCamera) 

      if (captureSession?.canAddInput(input))!{ 

       captureSession?.addInput(input) 



       if (captureSession?.canAddOutput(stillImageOutput) != nil){ 
        captureSession?.addOutput(stillImageOutput) 

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
        previewLayer?.videoGravity = AVLayerVideoGravityResizeAspect 
        previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait 
        cameraView.layer.addSublayer(previewLayer!) 
        captureSession?.startRunning() 
        let captureVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession!) 
        captureVideoLayer.frame = self.cameraView.bounds 
        captureVideoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill 
        self.cameraView.layer.addSublayer(captureVideoLayer) 



       } 

      } 

     } catch { 

      print("An error has occured") 

     } 


    } 

    @IBAction func takePhoto(_ sender: UIButton) { 
     didPressTakePhoto() 
    } 

    func didPressTakePhoto(){ 

     if let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo) { 



      videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait 

      let settingsForCapture = AVCapturePhotoSettings() 

      settingsForCapture.flashMode = .auto 
      settingsForCapture.isAutoStillImageStabilizationEnabled = true 
      settingsForCapture.isHighResolutionPhotoEnabled = false 
      stillImageOutput?.capturePhoto(with: settingsForCapture, delegate: self) 

     } 


    } 


    func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 
     if let photoSampleBuffer = photoSampleBuffer { 
      let photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer, previewPhotoSampleBuffer: previewPhotoSampleBuffer) 
      var imageTaken = UIImage(data: photoData!) 

      //post photo 

      let croppedImage = self.crop(capture: imageTaken!) 

      imageTaken = croppedImage 
      self.imageView.image = imageTaken 
      // UIImageWriteToSavedPhotosAlbum(imageTaken!, nil, nil, nil) 
     } 
    } 


    func crop(capture : UIImage) -> UIImage { 

     let crop = cameraView.bounds 

     //CGRect(x:0,y:0,width:50,height:50) 

     let cgImage = capture.cgImage!.cropping(to: crop) 

     let image : UIImage = UIImage(cgImage: cgImage!) 

     return image 
    } 

} 
+0

Вы пробовали CIPerspectiveCorrect для обрезки? – dfd

+1

Что это такое? Я не могу найти для этого никакой документации; Я относительно новичок в программировании iOS –

+0

Фильтр основного изображения. Выберите 4 очка и урожай. Так как использует CIImage, нет никакой потери качества изображения. – dfd

ответ

0

альтернатива для использования фильтра Core Image, называемого CIPspectiveCorrect. Поскольку он использует CIImage - это не истинный образ, а «рецепт» для изображения - он не страдает деградацией.

В основном, поверните ваш UIImage/CGImage в CIImage, выберите все 4 точки в нем и обрезайте. Это не должен быть параллелограмм (или CGRect), всего 4 балла. При использовании фильтров CI есть две отличия:

  • Вместо использования CGRect вы используете CIVector. Вектор может иметь 2, 3, 4, еще больше параметров в зависимости от фильтра. В этом случае вам нужно 4 CIVectors с двумя параметрами, соответствующими верхнему левому (TL), верхнему правому (TR), нижнему левому (BL) и нижнему праву (BR).

  • Изображения CI имеют свою точку отсчета (X/Y == 0/0) внизу слева, а не вверху слева. Это в основном означает, что ваша координата Y перевернута из изображений CG или UI.

Вот пример кода. Во-первых, некоторые заявления образцов, в том числе контексте CI:

let uiTL = CGPoint(x: 50, y: 50) 
let uiTR = CGPoint(x: 75, y: 75) 
let uiBL = CGPoint(x: 100, y: 300) 
let uiBR = CGPoint(x: 25, y: 200) 

var ciImage:CIImage! 
var ctx:CIContext! 

@IBOutlet weak var imageView: UIImageView! 

В viewDidLoad мы устанавливаем контекст и получить наш CIImage из UIImageView:

override func viewDidLoad() { 
    super.viewDidLoad() 
    ctx = CIContext(options: nil) 
    ciImage = CIImage(image: imageView.image!) 
} 

UIImageViews имеют рамку или CGRect и UIImages есть размер или CGSize. CIImages имеют степень, которая в основном ваша CGSize. Но помните, что ось Y перевернута, и это возможно в бесконечной степени! (Это не теки для источника UIImage, хотя.) Вот некоторые вспомогательные функции для преобразования вещи:

func createScaledPoint(_ pt:CGPoint) -> CGPoint { 
    let x = (pt.x/imageView.frame.width) * ciImage.extent.width 
    let y = (pt.y/imageView.frame.height) * ciImage.extent.height 
    return CGPoint(x: x, y: y) 
} 
func createVector(_ point:CGPoint) -> CIVector { 
    return CIVector(x: point.x, y: ciImage.extent.height - point.y) 
} 
func createPoint(_ vector:CGPoint) -> CGPoint { 
    return CGPoint(x: vector.x, y: ciImage.extent.height - vector.y) 
} 

Вот фактический призыв к CIPerspectiveCorrection. Если я правильно помню, изменение в Swift 3 - это использование AnyObject.В то время как более сильно типизированные переменные работал в предыдущих версиях Swift, они вызывают отвалы в настоящее время:

func doPerspectiveCorrection(
    _ image:CIImage, 
    context:CIContext, 
    topLeft:AnyObject, 
    topRight:AnyObject, 
    bottomRight:AnyObject, 
    bottomLeft:AnyObject) 
    -> UIImage { 
     let filter = CIFilter(name: "CIPerspectiveCorrection") 
     filter?.setValue(topLeft, forKey: "inputTopLeft") 
     filter?.setValue(topRight, forKey: "inputTopRight") 
     filter?.setValue(bottomRight, forKey: "inputBottomRight") 
     filter?.setValue(bottomLeft, forKey: "inputBottomLeft") 
     filter!.setValue(image, forKey: kCIInputImageKey) 
     let cgImage = context.createCGImage((filter?.outputImage)!, from: (filter?.outputImage!.extent)!) 
     return UIImage(cgImage: cgImage!) 
} 

Теперь, когда у нас есть CIImage, мы создаем четыре CIVectors. В этом примере проекта я жестко закодированы 4 CGPoints и решили создать CIVector в viewWillLayoutSubviews, самое раннее у меня есть кадры интерфейса:

override func viewWillLayoutSubviews() { 
    let ciTL = createVector(createScaledPoint(uiTL)) 
    let ciTR = createVector(createScaledPoint(uiTR)) 
    let ciBR = createVector(createScaledPoint(uiBR)) 
    let ciBL = createVector(createScaledPoint(uiBL)) 
    imageView.image = doPerspectiveCorrection(CIImage(image: imageView.image!)!, 
               context: ctx, 
               topLeft: ciTL, 
               topRight: ciTR, 
               bottomRight: ciBR, 
               bottomLeft: ciBL) 
} 

Если поместить этот код в проект, загрузите в ваш образ в UIImageView, выясните, какие 4 CGPoints вы хотите и запускаете это, вы должны увидеть свое ограниченное изображение. Удачи!

0

Добавление к @dfd ответа. Если вы просто не хотите использовать причудливый фильтр изображения ядра, следуйте этой работе.

  • качество фотографии после того, как я обрезаю ее плохой?

    Хотя вы используете максимально возможный предварительный сеанс сеанса AVCaptureSessionPreset1920x1080, вы конвертируете буфер изображения образца в формат JPEG и затем обрезаете его. Таким образом, очевидно, что будет некоторая потеря качества. Чтобы получить качественное обрезанное изображение, попробуйте установить предварительный сеанс AVCaptureSessionPresetHigh, чтобы AVFoundation определил видео высокого качества и dngPhotoDataRepresentation(forRawSampleBuffer:previewPhotoSampleBuffer:), чтобы получить изображение в формате DNG.

  • Неверное изображение и ориентация после того, как я сделаю снимок?

didFinishProcessingPhotoSampleBuffer Делегат предоставляет буфер для образца, который всегда поворачивается на 90 градусов влево. Таким образом, вы можете повернуть на 90 градусов самостоятельно.

Запустите свой UIImage с помощью cgImage и ориентации как правого и масштабного значения 1.0.

init(cgImage: CGImage, scale: CGFloat, orientation: UIImageOrientation) 
Смежные вопросы