Question

redimensionnement d'une UIImage caméra retournée par la UIImagePickerController prend un temps ridiculement longtemps si vous le faites de la manière habituelle comme dans cette post.

Mise à jour [: dernier appel pour des idées créatives ici! ma prochaine option est d'aller demander à Apple, je suppose.]

Oui, il y a beaucoup de pixels, mais le matériel graphique sur l'iPhone est parfaitement capable de tirer beaucoup de 1024x1024 quadriceps texture sur l'écran en 1 / 60e de seconde, donc il devrait y avoir un moyen de redimensionner un 2048x1536 image vers le bas à 640x480 dans beaucoup moins de 1,5 seconde.

Alors, pourquoi est-il si lent? Les données sont d'image sous-jacente aux rendements OS du sélecteur en quelque sorte pas prêt à tirer, de sorte qu'il doit être swizzled d'une certaine façon que le GPU ne peut pas aider?

Ma meilleure estimation est qu'il doit être converti de RGBA à ABGR ou quelque chose comme ça; quelqu'un peut-il penser d'une façon qu'il pourrait être possible de convaincre le système de me donner les données rapidement, même si elle est dans le mauvais format, et je vais traiter moi-même plus tard?

Pour autant que je sache, l'iPhone n'a pas de mémoire « graphique » dédié, donc il ne devrait pas être une question de déplacer les données d'image d'un endroit à l'autre.

Alors, la question suivante: est-il une méthode de dessin alternatif en plus juste en utilisant CGBitmapContextCreate et CGContextDrawImage qui prend plus d'avantage du GPU

?

Quelque chose à enquêter sur: si je commence avec un UIImage de la même taille qui n'est pas du sélecteur d'image, est-il aussi lent? Apparemment pas ...

Mise à jour: Matt Long a constaté qu'il ne prend que 30ms pour redimensionner l'image que vous revenez du sélecteur à [info objectForKey:@"UIImagePickerControllerEditedImage"], si vous avez activé le recadrage avec les commandes manuelles de la caméra. Ce n'est pas utile pour le cas où je me soucie de j'utilise takePicture pour prendre des photos par programmation. Je vois que ce que l'image modifiée est kCGImageAlphaPremultipliedFirst mais l'image originale est kCGImageAlphaNoneSkipFirst.

nouvelle mise à jour: Jason Crawford a suggéré CGContextSetInterpolationQuality(context, kCGInterpolationLow), qui a en fait réduit le temps d'environ 1,5 sec à 1,3 sec, à un coût de la qualité d'image - mais qui est encore loin de la vitesse du GPU doit être capable de

Dernière mise à jour avant la semaine s'écoule : refulgentis utilisateur a fait un certain profil qui semble indiquer que les 1,5 secondes est passé à écrire l'image de la caméra capturée sur le disque au format JPEG, puis en les lisant dans . Si cela est vrai, très bizarre.

Était-ce utile?

La solution

Utilisez Shark, profil il, comprendre ce qui prend tant de temps.

Je dois travailler beaucoup avec MediaPlayer.framework et quand vous obtenez des propriétés pour des chansons sur l'iPod, la première demande de propriété est incroyablement lent par rapport aux demandes ultérieures, parce que dans les premiers paquets MobileMediaPlayer de demande de propriété un dictionnaire avec tous les propriétés et il passe à mon application.

Je serais prêt à parier qu'il ya une situation similaire se produit ici.

EDIT:. J'ai pu faire un profil de temps en requin de la situation des deux UIImagePickerControllerEditedImage Matt Long et la situation UIImagePickerControllerOriginalImage générique

Dans les deux cas, la majorité du temps est repris par CGContextDrawImage. Dans le cas de Matt Long, le UIImagePickerController prend soin de ce entre l'utilisateur de capturer l'image et l'image d'entrer en mode « edit ».

Mise à l'échelle le pourcentage du temps nécessaire pour CGContextDrawImage = 100%, CGContextDelegateDrawImage prend alors 100%, puis ripc_DrawImage (de libRIP.A.dylib) prend 100%, puis ripc_AcquireImage (ce qui ressemble à décompresse le JPEG, et prend la majeure partie de son temps à _cg_jpeg_idct_islow, vec_ycc_bgrx_convert, decompress_onepass, sep_upsample) prend 93% du temps. Seulement 7% du temps est effectivement consacré à ripc_RenderImage, que je suppose est le dessin réel.

Autres conseils

On dirait que vous avez fait plusieurs hypothèses ici qui peuvent ou peuvent ne pas être vrai. Mon expérience est différente de la vôtre. Cette méthode semble ne prendre que 20-30ms sur mon 3Gs lors du redimensionnement d'un photo cassé de la caméra à 0,31 de la taille originale avec un appel à:

CGImageRef scaled = CreateScaledCGImageFromCGImage([image CGImage], 0.31);

(je reçois 0,31 en prenant l'échelle de largeur, 640,0 / 2048,0, par la voie)

J'ai vérifié pour vous assurer que l'image est la même taille que vous travaillez avec. Voici ma sortie NSLog:

2009-12-07 16:32:12.941 ImagePickerThing[8709:207] Info: {
    UIImagePickerControllerCropRect = NSRect: {{0, 0}, {2048, 1536}};
    UIImagePickerControllerEditedImage = <UIImage: 0x16c1e0>;
    UIImagePickerControllerMediaType = "public.image";
    UIImagePickerControllerOriginalImage = <UIImage: 0x184ca0>;
}

Je ne sais pas pourquoi la différence et je ne peux pas répondre à votre question en ce qui concerne le GPU, mais je considérerais 1,5 secondes et 30ms une différence très significative. Peut-être comparer le code à ce poste de blog à ce que vous utilisez?

Cordialement.

J'ai eu le même problème et cogné la tête contre pour longtemps. Pour autant que je peux dire, la première fois que vous accédez au UIImage retourné par le sélecteur d'image, il est juste lent. A titre d'expérience, essayez de synchronisation des deux opérations avec le UIImage -. Par exemple, votre échelle vers le bas, puis UIImageJPEGRepresentation ou quelque chose. Mettez ensuite l'ordre. Quand je l'ai fait dans le passé, la première opération obtient une pénalité de temps. Ma meilleure hypothèse est que la mémoire est toujours sur le CCD en quelque sorte, et de le transférer dans la mémoire principale à quelque chose avec elle est lente.

Lorsque vous définissez allowsImageEditing = OUI, l'image que vous obtenez en retour est redimensionnée et recadrée à environ 320x320. Cela le rend plus rapide, mais il est probablement pas ce que vous voulez.

Le meilleur que j'ai trouvé speedup est:

CGContextSetInterpolationQuality(context, kCGInterpolationLow)

le contexte que vous revenez de CGBitmapContextCreate, avant de faire CGContextDrawImage.

Le problème est que vos images réduites pourraient ne pas être aussi bon. Toutefois, si vous êtes mise à l'échelle par un facteur entier -. Par exemple, 1600x1200 à 800x600 -. Il semble OK

Voici un projet git que je l'ai utilisé et il semble bien fonctionner. L'utilisation est assez propre aussi bien -. Une ligne de code

https://github.com/AliSoftware/UIImage-Resize

NE PAS UTILISER CGBitmapImageContextCreate dans ce cas! J'ai passé près d'une semaine dans la même situation que vous êtes. La performance sera absolument terrible et il mange de la mémoire comme un fou. Utilisez UIGraphicsBeginImageContext à la place:

// create a new CGImage of the desired size
UIGraphicsBeginImageContext(desiredImageSize);
CGContextRef c = UIGraphicsGetCurrentContext();

// clear the new image
CGContextClearRect(c, CGRectMake(0,0,desiredImageSize.width, desiredImageSize.height));

// draw in the image
CGContextDrawImage(c, rect, [image CGImage]);

// return the result to our parent controller
UIImage * result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Dans l'exemple ci-dessus (à partir de mon propre code de redimensionnement d'image), « rect » est nettement plus petite que l'image. Le code passe au-dessus très rapide et devrait faire exactement ce dont vous avez besoin.

Je ne suis pas tout à fait sûr pourquoi UIGraphicsBeginImageContext est tellement plus rapide, mais je crois qu'il a quelque chose à voir avec l'allocation de mémoire. J'ai remarqué que cette approche nécessite beaucoup moins de mémoire, ce qui implique que le système d'exploitation a déjà l'espace alloué à un contexte d'image quelque part.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top