Pergunta

Eu estou trabalhando com projeto Java que requer manipulações muito avançados de imagens. Na verdade, eu estou fazendo a maior parte da manipulação usando OpenCV, e eu estou usando JNI para envolver as funções OpenCV que eu preciso. Estou extremamente satisfeito com o desempenho OpenCV dá, as pessoas que escreveram o código OpenCV merecem grande grande crédito para o código. Em nítido contraste com o que eu experimento com o código devs Java escreveu.

Eu comecei otimista sobre a escolha da minha linguagem de programação, a minha primeira iteração de trabalho do projeto funciona bem, mas seu desempenho não está nem perto de tempo real (recebendo cerca de 1 quadro por 2 segundos.) Eu fiz algumas otimizações de Meu código e sua ajudou muito. Eu tenho sido capaz de empurrar a taxa de quadros de até cerca de 10-20 frames por segundo, o que é ótimo, mas o que eu estou achando é que para fazer quaisquer outras otimizações eu tenho que reescrever o código Java para fazer a mesma coisa, mas 10 -20x mais eficiente.

Estou chocado com a forma como os desenvolvedores do pay Java muito pouca atenção ao desempenho, especialmente quando se escreve as aulas para classes relacionadas Media. Eu fiz o download OpenJDK e eu estou explorando as funções que estou usando. Por exemplo, existe uma função sob a classe Raster chamados getPixels (...) e torna-se os pixels da imagem. Eu estava esperando esta função para ser uma função altamente otimizado no código fonte, com várias chamadas para System.arraycopy para ainda mais a optimizar o desempenho. Em vez disso o que eu encontrei foi extremamente código "elegante", onde eles estão chamando 5-6 classes diferentes e 10-20 métodos diferentes apenas para realizar o que eu posso fazer em uma linha:

for (int i =0; i < n; i++) {
  long p = rawFrame[i];
  p = (p << 32) >>> 32;
  byte red = (byte) ((p >> 16) & 0xff);
  byte green = (byte) ((p >> 8) & 0xff);
  byte blue = (byte) ((p) & 0xff);
  byte val = (byte)(0.212671f * red + 0.715160f * green + 0.072169f * blue);
  data[i] = val;
  grayFrameData[i] = (val & 0x80) + (val & (0x7f)); 
}

O código acima transforma uma imagem em tons de cinza e recebe os dados de pixel flutuador, em cerca de 1-10ms. Se eu quisesse fazer o mesmo com Java construído em funções, a conversão em escala de cinza em si leva 200-300ms e, em seguida, pegar os pixels flutuador leva cerca 50-100ms. Isto é inaceitável para desempenho em tempo real. Nota para obter um aumento de velocidade, faço uso pesado de operadores bit a bit, que devs Java evitam.

Eu entendo que eles precisam para lidar com o caso geral, mas mesmo assim, eles não podem em opções menos dar para otimizações ou pelo menos um aviso como retardar esse código pode executar.

A minha pergunta é, neste ponto final no desenvolvimento (já tenho a minha primeira iteração, não estou trabalhando em um segundo que executa mais em tempo real) eu deveria morder a bala e passar para C / C ++, onde I pode ajustar as coisas muito mais, ou devo ficar com Java e espero que as coisas se tornarão mais em tempo real amigável para que eu não vou ter que reescrever o código Java já implementadas para obter um aumento de velocidade.

Estou realmente começando a se tornar enojado com a forma como "elegante" e lento Java realmente é. A quantidade de aulas há parece um exagero.

Foi útil?

Solução

Tenho trabalho visão de computador feito com Java, e eu pode ficar downvoted por dizer isso, mas é perfeitamente utilizável para a visão de computador e outras coisas em tempo real, você apenas tem que saber como usá-lo.

Optimizations potenciais:

Se precisar de ajuda otimizar seu código, eu ficaria feliz em ajudar - por exemplo, eu posso te dizer que você provavelmente vai ter um aumento de desempenho, fazendo um método

`public static final int getGrayScale(final int pixelRGB){
    return (0.212671f * ((pixelRGB >> 16) & 0xff) + 0.715160f * ((pixelRGB >> 8) & 0xff) + 0.072169f * ((pixelRGB) & 0xff));
}`

e usar isso em seu para {pixels} loop. Ao usar uma chamada de método, a JVM pode muito mais fortemente otimizar esta operação, e, provavelmente, pode otimizar o loop for mais também.

Se você tem RAM para queimar, você pode criar um estático, tabela de pesquisa final da escala de cinza saída de bytes para todas as cores pixel pixel de 24 bits possíveis. Este será ~ 16 MB de RAM, mas então você não tem de fazer cálculos de ponto flutuante, apenas um único acesso à matriz. Este pode ser mais rápido, dependendo de qual JVM você está usando, e se é ou não possível otimizar a limites de matriz de controlo.

Places para encontrar mais rapidamente um código semelhante, processamento de imagem:

Gostaria de sugerir que você dê uma olhada no código para o aplicativo ImageJ processamento de imagem (não é possível vincular graças a StackOverflow sendo retardado) e suas bibliotecas, especificamente ij.process.TypeConverter. Assim como o seu código, ele depende fortemente de operações de matriz diretos com bit-twiddling e mínimo de criação conjunto adicional . As bibliotecas Java2D (parte do JRE padrão) e a biblioteca Java Advanced Imaging (JAI) (não pode ligar graças a StackOverflow sendo retardado) fornecer outras maneiras de fazer processamento de imagem diretamente sobre os dados de imagem rapidamente sem ter que rolar o seu próprio funcionamento todos os Tempo. Para Java2D, você apenas tem que ter cuidado quais as funções que você usa.

Por que as bibliotecas Java2D são tão indireta:

A maior parte da "classe-iness" é devido ao suporte a vários modelos de cores e formatos de armazenamento (ou seja, imagens HSB, modelos de cores baseados em flutuador, modelos de cores indexadas). existe o engano por uma razão, e, por vezes, na verdade, o desempenho aumenta - a classe BufferedImage (por exemplo) conecta diretamente na memória de gráficos em recente VMs para fazer algumas operações muito mais rápido. Indireção permite que mascarar isso a partir do utilizador uma grande parte do tempo.

Outras dicas

A minha pergunta é, neste ponto final no desenvolvimento (já tenho a minha primeira iteração, não estou trabalhando em um segundo que executa mais em tempo real) eu deveria morder a bala e passar para C / C ++, onde I pode ajustar as coisas muito mais, ou devo ficar com Java e espero que as coisas se tornarão mais em tempo real amigável para que eu não vou ter que reescrever o código Java já implementadas para obter um aumento de velocidade.

Você está pedindo que eu deveria

  1. Mudar para uma linguagem onde eu possa satisfazer os meus requisitos de desempenho.
  2. Stick com Java e espero que as coisas melhorem.

Pode haver outras opções .... mas a opção 2 não parece realista, você pode não apenas "esperança" que o código se torna mais rápido: p

Alguns pontos a nota:

  1. OpenJDK não nescceraly ter o mesmo desempenho que o Sun JDK, você já tentou o Sun JDK?
  2. Se as otimizações de desempenho que você precisa feito são em alguns métodos, então pode valer a pena re-escrevê-las e ficar com Java ...

A minha sugestão seria que depende de quão importante é a manipulação de imagens é comparado com o projeto como um todo, e em relação a quaisquer vantagens java traz. É claro que você pode escrever código rápido em java (como demonstrado) se você precisa. No entanto, se 80% do seu projeto vai consistir de tal otimização, eu certamente repensar Java como a opção de idioma aqui.

Por outro lado, se isso representa 20% da aplicação, com os outros 80% sendo a funcionalidade do usuário em torno de fornecer esta conversão, então talvez ter que fazer o trabalho de obter a manipulação feito é um comércio que vale a pena fora para não tem que lidar com seu próprio gerenciamento de memória, e para ter o que outras APIs Java está lhe dando a interacção do utilizador (web, swing, SWT, o que você está usando).

Java não é conhecido por suas habilidades em tempo real devido ao coletor de lixo. Isso pode vir a morder-lhe bem, então tome cuidado com isso.

Eu não sei quanto de um aumento de desempenho que você vai conseguir, mas se você tiver um processo de longa duração fazendo coisas repetitivas você deve tentar executar o Servidor Hotspot VM usando java -server. Ele executa muito melhor do que o cliente VM que é o padrão no Windows, que é otimizada para o tempo de inicialização rápida.

Não é claro que você está realmente perguntando sobre em tempo real. Há uma diferença entre o tempo real e rápido real. Para rápido real, é suficiente para considerar o comportamento médio caso. Throughput é a principal preocupação. meios em tempo real capaz de terminar alguma tarefa dentro de um determinado período de tempo cada vez. Ou é claro, existem aplicações que necessitam de ambos.

Em uma implementação Java convencional, como o OpenJDK, o coletor de lixo é o maior problema para alcançar o comportamento em tempo real. Isso ocorre porque o coletor de lixo pode interromper o programa a qualquer momento para fazer o seu trabalho. Minha empresa, aicas, tem implementação de Java que não requer um segmento separado para coleta de lixo. Em vez disso, um pouco de trabalho GC é feito no momento da alocação. Efetivamente, a alocação é pago para por marcação ou varrendo a poucos quarteirões para cada bloco liberado. Isso tem exigido um reimplemenation total da máquina virtual.

Compilation é outro ponto em realtime difere Java de implementações de Java convencionais. tecnologia Realtime Java tende a usar estático ou Ahead-of-Time (AOT) compilação em vez de compilação JIT. EIC pode ser aprovado para a sua aplicação, como você pode ser capaz de tolerar a "aquecer" o tempo exigido por uma VM convencional para compilar as classes mais utilizadas. Se isto é assim, do que você provavelmente não tem requisitos de tempo real, apenas o rendimento queridos.

Se você está interessado em garantir que a descodificação quadro não é interrompido pela coleta de lixo, então não faria sentido usar uma implementação em tempo real de Java e compilação talvez AoT também. O Real-Time Specification for Java (RTSJ) também fornece outros apoios para em tempo real e incorporado de programação como RelatimeThread, AsyncEventHandler e RawMemoryAccess.

É claro, a obtenção de um bom desempenho, seja em tempo real ou real rápido, requer atenção aos detalhes. O uso ao longo do objeto temporário não é útil. Alocação sempre implica um custo extra, por isso, deve ser minimizada. Este é um grande desafio para as linguagens funcionais, que não permitem alterar o estado de objeto. No entanto, deve-se tomar cuidado para entender os caminhos críticos do código que está sendo escrita para evitar otimizações desnecessários. Profiling é essencial para a compreensão de que o esforço de otimização é melhor gasto.

A optimização prematura é a raiz de todo o mal.

Ao invés de reclamar, escrever um conjunto otimizado de bibliotecas e liberá-los, mas que seria apenas errado para criar uma "referência" aplicação java que foi pré-otimizado para algum alvo inexistente.

O ponto principal de uma implementação de referência é para tornar o código compreensível, sustentável - tem que ser. Eu acho que sempre havia uma expectativa de que onde os vendedores necessários iria analisar esta versão compreensível e re-implementar partes de velocidade.

Além do que já foi dito, você pode contribuir com otimizações para o JDK. Se você puder fornecer uma otimização poderosa que não sacrifique generalidade ou legibilidade, eu espero que você vai ser capaz de obter a sua correção incluída em uma futura versão JDK.

Assim, você não tem que esperança do JDK pode se tornar melhor. Você pode ajudar a fazer isso acontecer.

Pelo que entendi, as mais recentes versões de Java (ou talvez fosse JavaFX) têm métodos que permitem o acesso a funcionalidade avançada no hardware de vídeo do seu sistema. Me desculpe, eu estou sendo tão geral, eu acredito que eu ouvi sobre isso em Java Posse e desde que eu estou preso em Java 1.3 terra eu nunca tive a oportunidade de verificá-la - mas eu me lembro de algo assim auditiva.

Aqui está algo sobre isso: Mas parece que ele será apenas em Java 7: (

Também parece que só suporta a reprodução de um fluxo e manipulação de fluxo rudimentar no início -. Mas talvez a "esperar e Java vai melhorar" abordagem pode realmente trabalho

O que é que você parar de escrever uma versão otimizada dos métodos que você deseja usar em vez de usar os métodos built-in? Se isso não for possível, por que não escrever seus objetos em uma linguagem mais nativa e de importação que em sua aplicação existente?

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