2016-11-04 1 views
0

J'ai une superposition d'image à l'intérieur CameraViewController:rogner l'image de la caméra à Swift sans passer à une autre ViewController

description Je veux obtenir l'image de l'intérieur de ce carré rouge. Je ne veux pas passer à un autre contrôleur de vue pour installer un CropViewController, le recadrage doit être fait à l'intérieur de ce contrôleur.

Ce code derrière presque fonctionne, le problème est que l'image générée à partir de la caméra est 1080x1920 et le self.cropView.bounds est (0,0185,120) et bien sûr, il ne représente pas la même échelle utilisée pour prendre l'image

extension UIImage { 
    func crop(rect: CGRect) -> UIImage { 
     var rect = rect 
     rect.origin.x*=self.scale 
     rect.origin.y*=self.scale 
     rect.size.width*=self.scale 
     rect.size.height*=self.scale 

     let imageRef = self.cgImage!.cropping(to: rect) 
     let image = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation) 
     return image 
    } 
} 
+0

Si vous connaissez les coordonnées du CGRect que vous voulez recadrer, utilisez le filtre CIPerspectiveCorrection. Je vais jeter du code dans quelques minutes. – dfd

+0

@dfd J'essaie de voir comment fonctionne CIPerspectiveCorrection, si vous fournissez du code, cela aidera beaucoup! Merci – Marckaraujo

+0

Je viens de l'ajouter. Copier/coller d'une application qui fonctionne dans un nouveau projet et il semble que cela fonctionne - il semble que cela apparaisse à l'envers, ce qui est probablement dû à une certaine transposition CGPoint. Dites-moi, je vais lancer mon application ** très bêta ** dans un GitHub public. – dfd

Répondre

2

Vous pouvez toujours recadrer visuellement n'importe quelle image dans un quadrilatère (une forme à quatre côtés - ne doit pas nécessairement être un rectangle) à l'aide d'un filtre d'image de base appelé CIPerspectiveCorrection. Imaginons que vous ayez un cadre imageView de 414 de largeur sur 716 de hauteur, avec une image de largeur 1600 sur 900 de hauteur. (Vous utilisez un mode contenu de .aspectFit, n'est-ce pas?) Supposons que vous vouliez recadrer une forme à 4 côtés qui est des coins - dans (X, Y) coordonnées dans l'imageView - are (50,50), (75,75) (100 300) et (25 200). Notez que je liste les points en haut à gauche (TL, en haut à droite (TR), en bas à droite (BR), en bas à gauche (BL) et notez que ce n'est pas un rectangle rectiligne

(1) Convertissez le UIImage en un CIImage où le "extent" est la taille UIImage, (2) Convertissez ces coordonnées UIImageView en coordonnées CIImage, (3) passez-les et le CIImage dans le filtre CIPerspectiveCorrection pour le recadrage et (4) rendre la sortie de CIImage en UIImageView.

est un code ci-dessous que j'ai jeté ensemble. Il fonctionne. Il est aussi un peu rude sur les bords, mais nous espérons que vous obtenez le concept.

class ViewController: UIViewController { 

    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! 

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

    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) 
    } 
    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!) 
    } 

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

}

EDIT: Je mets ceci ici pour expliquer les choses. J'espère que cela ne va pas à l'encontre des règles du site. Nous deux avons échangé des projets, et il y avait un problème avec le code de l'interrogateur où un retour nul était en train de se produire. Tout d'abord, voici le code corrigé, qui devrait être dans la fonction cropImage():

let ciTL = createVector(createScaledPoint(topLeft, overlay: cameraView, image: image), image: image) 
let ciTR = createVector(createScaledPoint(topRight, overlay: cameraView, image: image), image: image) 
let ciBR = createVector(createScaledPoint(bottomRight, overlay: cameraView, image: image), image: image) 
let ciBL = createVector(createScaledPoint(bottomLeft, overlay: cameraView, image: image), image: image) 

Le problème est avec les deux dernières lignes, qui ont été transposés en passant bottomLeft où il aurait dû être bottomRight, et vice-versa . (Facile erreur à faire, je l'ai fait aussi!)

Une explication pour aider ceux qui utilisent CIPerspectiveCorrection (et d'autres filtres qui utilisent CIVectors). (1) Un CIVector peut avoir n'importe où - je pense 2 à, eh bien, une quantité presque infinie de composants. Cela dépend du filtre. Dans ce cas, il y a deux composants (X, Y). Assez simple, mais la torsion est que les 4 CIVectors décrivent 4 points dans l'extension CIImage où l'origine est en bas à gauche, pas en haut à gauche.

  • (2) Note Je n'ai pas dit une forme à 4 côtés. Vous pouvez réellement avoir une forme de "figure 8" où le point "en bas à droite" est à gauche du point "en bas à gauche"! Cela se traduirait par une forme où deux côtés se croisent.

  • (3) Tout ce qui compte est que tous les 4 points se trouvent avec l'extension CIImage.Si ce n'est pas le cas, le filtre avec le retour est nul pour son image de sortie. Une dernière note pour ceux qui n'ont pas encore travaillé avec les filtres CIImage - les filtres ne s'exécuteront pas tant que vous n'aurez pas demandé l'image de sortie. Vous pouvez en instancier un, remplir les paramètres, les chaîner, peu importe. Vous pouvez même faire une faute de frappe dans le nom du filtre (ou l'une de leurs clés). Jusqu'à ce que votre code demande le filter.outputImage, rien ne se passe.

  • +0

    vraiment merci pour le code et l'échantillon, mais je reçois toujours une image nulle dans context.createCGImage, je viens aussi de télécharger un échantillon avec le problème https://bitbucket.org/marckaraujo/how-much, je vais vraiment apprécier votre aide – Marckaraujo

    +0

    Je regarde votre code maintenant et l'ai réduit à createScaledPoint(). Fondamentalement, votre CIImage a une étendue de 1920x1080, mais la conversion de CGPoint (307.240) devient un vecteur de (2456, -1080). Je vais voir si je peux trouver pourquoi. CIVectors ici sont essentiellement coordonnées où l'origine est en bas à gauche au lieu de haut à gauche. Ma routine utilisait des variables globales et je me demandais si ce que vous transmettez pour l'UIImage ("rect" dans votre code) n'est pas le ** entier ** UIImage mais quelque chose d'autre. – dfd

    +0

    vraiment merci, pour toute votre aide. Cela fonctionne maintenant, mais seulement sans mise en page automatique. Si vous utilisez la mise en page automatique, l'image recadrée ne correspond pas à ce que vous avez sélectionné – Marckaraujo