Pergunta

redimensionar uma câmera UIImage retornado pelo UIImagePickerController leva um ridiculamente muito tempo se você fizer isso da maneira usual como em este post .

[actualização: última chamada para idéias criativas aqui! minha próxima opção é Vá perguntar a Apple, eu acho.]

Sim, é um monte de pixels, mas o hardware de gráficos no iPhone é perfeitamente capaz de sorteio de 1024x1024 quads texturizados na tela em 1 / 60th de um segundo, então não há realmente deve ser uma forma de redimensionar uma 2048x1536 imagem até 640x480 em muito menos do que 1,5 segundos.

Então por que é tão lento? É os dados de imagem subjacentes às OS retornos do selecionador de alguma forma não está pronto para ser extraídas, de forma que ele tem de ser swizzled de alguma forma que a GPU não pode ajudar?

Meu melhor palpite é que ele precisa ser convertido de RGBA para ABGR ou algo parecido; Alguém pode pensar em uma maneira que pode ser possível para convencer o sistema para me dar os dados rapidamente, mesmo que seja no formato errado, e eu vou lidar com isso sozinho mais tarde?

Tanto quanto eu sei, o iPhone não tem nenhum "gráficos" memória dedicada, por isso não deve ser uma questão de mover os dados de imagem de um lugar para outro.

Assim, a pergunta: existe algum método de desenho alternativo, além de apenas usando CGBitmapContextCreate e CGContextDrawImage que leva mais vantagem do GPU

Algo para investigar: se eu começar com um UIImage do mesmo tamanho que não é do seletor de imagem, é tão lento? Aparentemente não ...

Update: Matt Long descobriram que ele só tem 30ms para redimensionar a imagem que você voltar no seletor no [info objectForKey:@"UIImagePickerControllerEditedImage"], se você tiver ativado o corte com os controles manuais da câmera. Isso não é útil para o caso que me importa onde eu estou usando takePicture para tirar fotos de forma programática. Vejo que que a imagem editada é kCGImageAlphaPremultipliedFirst mas a imagem original é kCGImageAlphaNoneSkipFirst.

Além disso actualização: Jason Crawford sugeriu CGContextSetInterpolationQuality(context, kCGInterpolationLow), o que, de fato, reduzir o tempo de cerca de 1,5 segundos para 1,3 segundos, com um custo na qualidade da imagem - mas isso é ainda muito longe da velocidade do GPU deve ser capaz de

Última atualização antes que a semana se esgota : refulgentis usuário fez alguns perfis que parece indicar que os 1,5 segundos é gasto escrevendo a imagem da câmera capturado no disco como um JPEG e, em seguida, lê-lo de volta . Se for verdade, muito bizarro.

Foi útil?

Solução

Use Tubarão, perfil dela, descobrir o que está demorando tanto.

Eu tenho que trabalhar muito com MediaPlayer.framework e quando você chegar propriedades para músicas no iPod, o primeiro pedido de propriedade é incrivelmente lento em comparação com os pedidos subsequentes, porque nos primeiros Solicitar pacotes MobileMediaPlayer até um dicionário com todas as propriedades e passa para meu aplicativo.

Eu estaria disposto a apostar que há uma situação semelhante ocorrendo aqui.

EDIT:. Eu era capaz de fazer um perfil de vez em Tubarão da situação UIImagePickerControllerEditedImage de ambos Matt Long ea situação UIImagePickerControllerOriginalImage genérico

Em ambos os casos, a maioria do tempo é ocupado por CGContextDrawImage. No caso de Matt Long, o UIImagePickerController cuida disso entre o usuário capturar a imagem e o modo de imagem que entra 'editar'.

Scaling a percentagem de tempo gasto para CGContextDrawImage = 100%, CGContextDelegateDrawImage seguida, leva 100%, então ripc_DrawImage (de libRIP.A.dylib) leva 100%, e depois ripc_AcquireImage (que parece que descomprime o JPEG, e ocupa a maioria de seu tempo em _cg_jpeg_idct_islow, vec_ycc_bgrx_convert, decompress_onepass, sep_upsample) leva 93% do tempo. Apenas 7% do tempo é realmente gasto em ripc_RenderImage, que eu suponho que é o desenho real.

Outras dicas

Parece que você fez várias suposições aqui que pode ou não ser verdade. Minha experiência é diferente do seu. Este método parece ter apenas 20-30ms no meu 3Gs ao dimensionar um foto disparou da câmera para 0,31 do tamanho original com uma chamada para:

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

(I obter 0,31 tomando a escala largura, 640,0 / 2048.0, por sinal)

Eu verifiquei para certificar-se a imagem é do mesmo tamanho que você está trabalhando. Aqui está a minha saída 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>;
}

Eu não tenho certeza por a diferença e eu não posso responder à sua pergunta como ele se relaciona com a GPU, no entanto eu consideraria 1,5 segundos e 30ms uma diferença muito significativa. Talvez comparar o código nesse post com o que você está usando?

Atenciosamente.

Eu tive o mesmo problema e bateu minha cabeça contra ele por um longo tempo. Tanto quanto eu posso dizer, a primeira vez que você acessar o UIImage retornado pelo seletor de imagem, é apenas lento. Como uma experiência, tentar cronometrar quaisquer duas operações com o UIImage -. Por exemplo, a sua escala para baixo, e depois UIImageJPEGRepresentation ou algo assim. Em seguida, mudar a ordem. Quando eu fiz isso no passado, a primeira operação recebe uma penalidade de tempo. Minha melhor hipótese é que a memória ainda está no CCD de alguma forma, e transferi-lo para a memória principal de fazer qualquer coisa com ele é lento.

Quando você define allowsImageEditing = YES, a imagem que você voltar é redimensionada e cortada para cerca de 320x320. Isso faz com que seja mais rápido, mas provavelmente não é o que você quer.

A melhor aceleração que eu encontrei é:

CGContextSetInterpolationQuality(context, kCGInterpolationLow)

no contexto você voltar de CGBitmapContextCreate, antes de fazer CGContextDrawImage.

O problema é que suas imagens em escala reduzida pode não parecer tão bom. No entanto, se você está escalando para baixo por um fator inteiro -. Por exemplo, 1600x1200 para 800x600 -., Então, parece OK

Aqui está um projeto git que eu usei e parece funcionar bem. O uso é bastante limpo, bem -. Uma linha de código

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

Não use CGBitmapImageContextCreate neste caso! Passei quase uma semana na mesma situação em que está. O desempenho vai ser absolutamente terrível e ele vai comer a memória como um louco. Use UIGraphicsBeginImageContext vez:

// 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();

No exemplo acima (do meu próprio código de imagem redimensionamento), "rect" é significativamente menor do que a imagem. O código acima é executado muito rápido, e deve fazer exatamente o que você precisa.

Eu não sou inteiramente certo porque UIGraphicsBeginImageContext é muito mais rápido, mas eu acredito que tem algo a ver com a alocação de memória. Tenho notado que esta abordagem exige muito menos memória, o que implica que o sistema operacional já alocou espaço para um lugar contexto da imagem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top