...

31 respostas
R

31 Respostas

J

O problema pode ser o seu algorítimo, ou a superfície(que não usa aceleração de hardware).

Usa a opengl como superfície. Existem muitos tutoriais na internet. Tente melhorar o algoritmo também.

R

E
colorMap = findColorMap(value);

Como é este método?

R

E

Cruz credo, tudo isso para arredondar um número para 2 casas?

BigDecimal roundValue = new BigDecimal(value).setScale(2, RoundingMode.HALF_EVEN);  
    value = roundValue.doubleValue();

BigDecimal é excelente para trabalhar com moeda, mas é péssimo para fazer o que você quer.

Outra coisa bizarra é o que você está fazendo para achar uma cor a partir de um valor. Só para me dar uma idéia, poderia dizer quantos elementos contém esse ColorMapList?

J

Quando for trabalhar com gráficos e precisar de desempenho(vídeo por exemplo), você precisa desenhar suas imagens em uma superfície que esteja sendo processada por uma “gpu”. A opengl é uma biblioteca que vai te dar tudo isso.

dá uma lida nos tutoriais:

http://jogamp.org/jogl/www/
http://www.land-of-kain.de/docs/jogl/

R

No colorlistmap tem 25 elementos.

E

O que eu faria no seu lugar.

Digamos que value seja um número de 0.0 a 1.0, e que você tenha 4 cores:
Preto - 0.0 <= value < 0.23
Vermelho - 0.23 <= value < 0.57
Azul - 0.57 <= value < 0.75
Verde - 0.75 <= value <= 1.0

O que você deve fazer:
a) Crie um array com 5 posições contendo, ordenadamente, esses valores 0.0, 0.23, 0.57, 0.75, 1.0
b) Use Arrays.binarySearch. Por exemplo, digamos que value = 0.5
Arrays.binarySearch vai lhe retornar o número -3 (é um número negativo porque o valor não foi encontrado, mas isso é esperado mesmo). Leia a documentação de Arrays.binarySearch () http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#binarySearch(double[],%20double) ) e descubra que -3 indica que o “ponto de inserção” é 2, ou seja, você vai associar o valor a Vermelho (que está na segunda posição do array).

E

Na maior parte dos processadores atuais,

coluna = (int) (h / (float) this.matrix.getLarguraCelula());

é mais lento que

coluna = (int) ((double) h / this.matrix.getLarguraCelula());

Mas acho que, neste caso em particular (porque você não quer nada arredondado)

coluna = h / this.matrix.getLarguraCelula();

é suficiente.

E

Não acho que arredondar um número para duas casas seja necessário neste caso, a menos que você queira piorar o desenho de propósito.

R

Boa noite a todos , bom obrigado pelas dica mas para otimizad da melhor forma acredito que terei que usa o raster
.serpixels para adicionar um bloco inyeiro de pixel de uma vez.mas nao estou sabe usar alguem teri um exemplo ou poderia ajidar abs

E

Pode postar findNewMatrixDimension também? Tenho a impressão que isso também é lento

R

E

Nossa, outro código com procura linear. Sinceramente acho que setPixels não vai ajudar nada no seu caso.

for(MatrixDimension md : this.matrixDimensionList){  
                if(md.getColuna() == coluna && md.getLinha() == linha){  
                    contemSubMatriz = true;  
                    monitorValue =  this.matrixCalc[linha][coluna];  
                    break;  
                }  
                contemSubMatriz = false;  
            }

Qual o tamanho de matrixDimensionList?

E

Aliás, você postou o código errado - o método que você postou é void mas pelo contexto ele teria de ser boolean, não?

R

sim, deveria é que eu alterei um pouco as coisas aqui, essa lista depende do parâmetros, mas deve ter em media 800 itens

E

Aha! Você está fazendo uma busca linear em algo que tem 800 itens para cada pixel.
Pense se há uma forma de acelerar esse método - em média, ele deve estar fazendo 400 loops para cada ponto, e isso deve ser super-lento.
Você, basicamente, teria de inventar uma maneira de melhorar isso, de modo que você precisasse fazer no máximo umas 10 comparações.

E

Você percebeu como é difícil tornar uma coisa mais rápida?
A primeira coisa que lhe veio à cabeça era como você poderia pintar um pixel de forma mais rápida (setPixel).
Então o pessoal foi na sua e lhe mandou usar GPU e outras coisas mais avançadas.
Mas no seu caso, o seu problema é basicamente analisar o seu algoritmo para ver por que é que você está fazendo busca linear e outras coisas mais lentas. Pode ser que você simplesmente tenha de usar um outro algoritmo para que as coisas funcionem mais rapidamente.

A propósito, lembra-se daquela história de fazer busca binária (binarySearch) que lhe indiquei? Na verdade, acho que há uma maneira um pouco mais rápida - você sabe que de um pixel para outro, o valor do índice para o Color Map não muda muito (deve ser igual ou no máximo subir de 1 ou cair de 1). Você pode ver se o valor anterior é bom para ser reusado, e se não for, você pode aumentar 1 ou diminuir 1 até que você ache o valor da cor certa.

V

A ideia desse seu algoritmo é fazer o que?

R

Ola Vini a ideia e a seguinte tenho que cria uma imagem com base na altura e largura de uma matriz apos tenho que pintar os pixel so posso pintar os pixel com um tamanho maior do que o normal cada pixl pode ter 60x60 depois disso eu pego os bytes que representam essa imagem jog na tela

J

entanglement:
Você percebeu como é difícil tornar uma coisa mais rápida?
A primeira coisa que lhe veio à cabeça era como você poderia pintar um pixel de forma mais rápida (setPixel).
Então o pessoal foi na sua e lhe mandou usar GPU e outras coisas mais avançadas.
Mas no seu caso, o seu problema é basicamente analisar o seu algoritmo para ver por que é que você está fazendo busca linear e outras coisas mais lentas. Pode ser que você simplesmente tenha de usar um outro algoritmo para que as coisas funcionem mais rapidamente.

A propósito, lembra-se daquela história de fazer busca binária (binarySearch) que lhe indiquei? Na verdade, acho que há uma maneira um pouco mais rápida - você sabe que de um pixel para outro, o valor do índice para o Color Map não muda muito (deve ser igual ou no máximo subir de 1 ou cair de 1). Você pode ver se o valor anterior é bom para ser reusado, e se não for, você pode aumentar 1 ou diminuir 1 até que você ache o valor da cor certa.

A gpu no caso só acelera a pintura na superfície dela, ou seja na hora de mostrar a imagem que está pronta na placa de vídeo. O processamento com raster.setPixel(x,y,cor) acontece na cpu. O maior gargalo no código postado são: getPixel e setPixel. Essas funções são custosas porque fazem uma cópia dos pixels da imagem ao invés de olhar o ponteiro. Isso aliado com o que você disse da quantidade de iterações maximiza o tempo para desenhar a imagem.

Eu estava portando a aforge.net para java e já tinha quase toda a parte de processamento de imagem pronta, mas o resultando foi tão ruim que desisti do projeto. Um filtro complexo levava uns 200ms para processar uma imagem do tamanho que foi passada nesse tópico. Eu enviei uma parte dele para o vini godoy dar uma olhada.

A única solução razoável que consegui para isso foi usar o método que pega toda uma banda de cor da imagem como um vetor de int. Desse modo você consegue minimizar toda essa iteração com setPixel e getPixel.

getSamples(int x, int y, int w, int h, int b, int[] iArray) //Returns the samples for a specified band for the specified rectangle of pixels in an int array, one sample per array element.

O método acima copia toda uma área para um vetor int[], float[]… da banda b.

Com vala ou c++ consegui resultados na casa dos us(micro).

E

Eu também estava pensando nesse método setSamples - de fato, dessa maneira deve ser bem rápido mapear seu array de cores no WritableRaster. Na verdade, é possível até brincar com o tal do SampleModel e poder trabalhar de forma mais “próxima ao hardware” ainda.
Mas acho que primeiro ele tem de otimizar o tal método que agora está fazendo uma busca em uma lista de 800 itens (argh). Depois é que tem de se preocupar como pintar um pixel, ou uma coleção deles.

R

E

É o seguinte. Como você deve saber, há várias maneiras de se armazenar pixels na memória. Quando você usa setSamples ( http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/WritableRaster.html#setSamples(int,%20int,%20int,%20int,%20int,%20int[]) ) , em vez de você usar o formato “cozinhado” que é o de você ter 4 bytes por pixel - as cores R, G, B e o alpha, você deve usar o formato que é especificado pelo SampleModel ( http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/SampleModel.html ) .
Esse formato é mais próximo à representação tal como é feita pelo hardware, e pode ser usado se você precisa alterar muitos pixels de uma vez só.
Cada WritableRaster tem uma forma diferente de especificar esse SampleModel, portanto é necessário verificar exatamente como é que ele funciona.
Um exemplo de um SampleModel é um http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/MultiPixelPackedSampleModel.html - mas não sei se o WritableRaster, por exemplo, suporta esse SampleModel que lhe disse. Pode até suportar um SampleModel que não está especificado.
Eu não tenho um exemplo pronto disso. Talvez você ache um pronto na Internet.

E

Mas ainda acho que você tem de localizar, usando um profiler (o jvisualvm, que já vem com o JDK, é excelente para você medir esse tempo da execução de cada linha), qual é o método que está gastando mais tempo. Acho que apenas 10% do tempo que você gasta nessa rotina é para plotar pixels :frowning:

J

entanglement:
Mas ainda acho que você tem de localizar, usando um profiler (o jvisualvm, que já vem com o JDK, é excelente para você medir esse tempo da execução de cada linha), qual é o método que está gastando mais tempo. Acho que apenas 10% do tempo que você gasta nessa rotina é para plotar pixels :frowning:

Aposto algumas dilmas nos métodos setPixel e getPixel. :smiley:

E
long t = System.currentTimeMillis();
                    BufferedImage bi = new BufferedImage(2150, 1200, BufferedImage.TYPE_INT_ARGB);
                    WritableRaster wr = bi.getRaster();
                    int[] pixelValue = new int[4];
                    pixelValue[0] = 12;
                    pixelValue[1] = 23;
                    pixelValue[2] = 45;
                    pixelValue[3] = 100;
                    for (int w = 0; w < 2150; w++) {
                        for (int h = 0; h < 1200; h++) {
                            wr.setPixel(w, h, pixelValue);
                        }
                    }
                    JOptionPane.showMessageDialog(ExemploWritableRaster.this, String.format("%d ms",
                        (System.currentTimeMillis() - t)));
                    bi.flush();

Medi o tempo deste método. Ele leva cerca de 125 ms para executar na minha máquina. Portanto, os 2 minutos são para executar o algoritmo, não do setPixel.

E

Ou seja, setPixel leva 1% do tempo de execução do programa original, portanto ele tem de se preocupar com o algoritmo em si, não com setPixel.

J
entanglement:
Ou seja, setPixel leva 1% do tempo de execução do programa original, portanto ele tem de se preocupar com o algoritmo em si, não com setPixel.

Você não pode colocar um timer para medir a execução de um bloco do programa porque o GC influencia no resultado. Precisa parar o coletor de lixo e medir método por método.

Se você separar todas as instruções e medir setPixel vai ver que ele é o método que possui o custo mais alto do algoritmo.

Fiz uma brincadeira aqui:

um filtro que faz o complemento de uma imagem 1920x1080:

getPixel e setPixel representam aproximadamente 50% da execução do programa:

[code]/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package complemento;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

/**
*
* @author julio
*/
public class Complemento {

public void doInvert(WritableRaster wraster) {
for (int y = 0; y < wraster.getHeight(); y++) {
for (int x = 0; x < wraster.getWidth(); x++) {

int[] pixel = new int[4];
wraster.getPixel(x, y, pixel);

pixel[0] = 255 - pixel[0];
pixel[1] = 255 - pixel[1];
pixel[2] = 255 - pixel[2];
pixel[3] = 255 - pixel[3];

wraster.setPixel(x, y, pixel);
}
}

}

/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
Complemento app = new Complemento();
BufferedImage bi = ImageIO.read(new File("c:\\teste.jpg"));
WritableRaster wr = bi.getRaster();
app.doInvert(wr);

}
}

J

A solução dele é sim melhorar o algoritmo, e isso significa usar setPixel e getPixel o menor número de vezes possível. Com Qt é a mesma coisa. O método setPixel e getPixel de QImage é tão pesado que chega a ser mais lento que o do java por chamar detach() várias vezes. Detach() faz uma cópia da data dentro do arquivo. Usando c++ eu consigo contornar esse problema usando apontadores:

uchar* data = image->data();

Com java isso já não é possível.

J

repetido…pau do guj. Rsrsrsrs.

Criado 2 de outubro de 2012
Ultima resposta 4 de out. de 2012
Respostas 31
Participantes 4