Problema de lógica para sair de busca

5 respostas
esmerick

Bom dia, estou fazendo um trabalho que seria pegar o tom de cada pixel de uma imagem cinza, comparar com várias imagens menores (também escala cinza) disponibilizadas em uma pasta e fazer uma espécie de mosaico substituindo os pixels pelas imagens de tons equivalentes.

Pensando em melhorar um pouco a performace, já que são mais de 2700 imagens/ladrilhos, eu implementei a interface compareble em uma classe Ladrilho, e esta, possui propriedades como imagem (BufferedImage), tonalidadeMédia e número de vezes que repetiu (o problema estipula max. 10 vzs por ladrilho). E utilizo o Collection.sort() para organizar meus ladrilhos(que estão num ArrayList) pela média. Previamente eu peguei a tonalidade de todos os pixels da imagem base e o tomMax e min para não carregar ladrilhos desnecessários.

Para achar uma imagem/ladrilho adequada eu tenho uma variável que guarda o index da ultima imagem retornada(uma vez que esteja ordenado, imagens tendem a ter tonalidades próximas, então começar do index 0 seria mais demorado), e com essa variável eu adiciono 1 caso o pixel tenha tonalidade maior que o ladrilho do index atual, ou -1 caso o ladrilho tenha tonalidade maior que a do pixel. Caso a imagem não tenha sido utilizada mais de 10 vezes, eu a retorno, senão à removo da lista.

Meu problema está em achar um jeito de sair do while quando todas as imagens com tons adequados foram removidas(por serem utilizadas 10x). Se alguém tiver uma ideia fico agradecido :slight_smile:
Desculpem pelo texto grande xD
qualquer ideia de performace com relação ao trabalho também é bem vindo :smiley:

Aqui um codigo +/- do que seria…

public Ladrilho buscarLadrilho(int pixel, int margemErro) {
        int media = 0;
        Ladrilho lad;
        do {
            lad = BaseImagens.getLadrilho(posicaoUltimaBusca);

            if (lad.getNumVezesUtilizado() < 10) {
                media = lad.getMediaRGB();
                if (pixel > media && posicaoUltimaBusca < BaseImagens.getLadrilhos().size() - 1) {
                    posicaoUltimaBusca++;
                } else if (posicaoUltimaBusca > 0) {
                    posicaoUltimaBusca--;
                } else {
                    return null;
                }
            } else {
                BaseImagens.removeLadrilho(posicaoUltimaBusca);
            }

        } while (Math.abs(media - pixel) > margemErro);
        lad.addNumVezesUtilizado();
        return BaseImagens.getLadrilho(posicaoUltimaBusca);

    }

5 Respostas

charleston10

A lógica de você sair de uma estrutura de repetição seja qual for é usar um contador.
Como por exemplo o uso do FOR você utiliza uma variável que faz a contagem com um incrementador.

Nessa situação que você está, eu usaria a mesma lógica, criaria uma variável que faria o papel dessa contagem de quantas
vezes foi usada, e faria uma comparação dentro do Laço, que faria com que continuasse ou parasse.

Foi o que eu notei que você fez, mas para sair do laço você deve usar na comparação uma outra opção como
foi utilizado no seu IF

while ((Math.abs(media - pixel) > margemErro)[color=green]&&(lad.getNumVezesUtilizado() < 10)[/color]))

ViniGodoy

Eu faria o seguinte:

  1. Criaria na classe BaseLadrilho um map do tom para uma lista de ladrilhos daquele tom;
  2. No método BuscarLadrilho acrescentaria um contador para quantas vezes o tom foi usado;
  3. No método getLadrilho, usaria o contador para evitar pegar o mesmo tom 2 vezes.

Por exemplo:

public BufferedImage getLadrilho(int tom, int cont) { List&lt;BufferedImage&gt; ladrilhos = mapLadrilho.get(tom); return ladrilhos.get(cont % ladrilhos.size()); }

Map&lt;Integer, Integer&gt; contLadrilho = new HashMap&lt;Integer, Integer&gt;(); public Ladrilho buscarLadrilho(int pixel, int margemErro) { int tom = lad.getMediaRGB(); if (!contLadrilho.contains(tom)) contLadrilho.put(tom, 1); else contLadrilho.put(tom, contLadrilho.get(tom)+1); return BaseImagens.getLadrilho(tom, contLadrilho.get(tom)); }

Se for considerar a margem de erro (para o caso de não haver um ladrilho para um tom) eu usaria a margem no método getLadrilho, dessa forma:

public BufferedImage getLadrilho(int tom, int cont, int margem) { List&lt;BufferedImage&gt; ladrilhos = mapLadrilho.get(tom); int erro = 1; while (ladrilhos == null && erro &lt; margem) { ladrilhos = mapLadrilho.get(tom-erro); if (ladrilhos == null) { ladrilhos = mapLadrilho.get(tom+erro); } if (ladrilhos == null) return null; //Não houve nenhum ladrilho dentro da margem de erro return BaseImagens.getLadrilho(tom, contLadrilho.get(tom)); }

Ela garante que os ladrilhos serão pegados do menor para o maior erro.

Note que não seria difícil alterar o último exemplo para que ele nunca usasse dois ladrilhos iguais, bastaria remover o ladrilho usado do map (e, nesse caso, você nem precisaria do map contador).
Porém, você tem que pensar no que ocorre caso não hajam ladrilhos suficientes para um determinado tom.

Uma alternativa é ter uma cópia do map de ladrilhos e, sempre que a lista de um determinado tom esvaziar, você usaria a cópia para preenche-la novamente.

charleston10

Esse ViniGodoy é muito bom, queria ser seu aluno…
sou uma criancinha a aprender java fazendo comparação…

haha

ViniGodoy

É só vir fazer pós de desenvolvimento de jogos na PUC de Curitiba. :slight_smile:

esmerick

Muito obrigado pelas respostas, vou tentar implementar aqui… Vini com respostas geniais sempre :-o
Abraço.

Criado 31 de janeiro de 2013
Ultima resposta 31 de jan. de 2013
Respostas 5
Participantes 3