[RESOLVIDO] Problema ao tratar contraste de imagem

11 respostas
N

Pessoal, tenho o código abaixo que aumenta ou diminui o contraste de uma imagem.
Ele funciona com várias imagens que eu testei, mas exclusivamente com o tipo de imagem que estou usando que são cheques scaneados com extensão .tiff não funciona.

import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.IOException;

import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;

public class SimpleContrast {
	public static void main(String[] args) throws IOException {

//		PlanarImage image = JAI.create("fileload", "C:\\foto.TIFF");//Com essa imagem funciona
		PlanarImage image = JAI.create("fileload", "C:\\scan.tiff");//Com a imagem scaneada não funciona
		
		BufferedImage input = image.getAsBufferedImage();
		BufferedImage output = new BufferedImage(input.getWidth(),
				input.getHeight(), BufferedImage.TYPE_INT_RGB);

		float scaleFactor = 1.0f;
		float offset = 1;

		RescaleOp rescale = new RescaleOp(scaleFactor, offset, null);
		rescale.filter(input, output);
	
		JFrame frame = new JFrame();
		frame.setTitle("Simple Contrast 2");
		frame.getContentPane().add(new JButton(new ImageIcon(output)));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);
	}
}
O erro que  é:

Exception in thread main java.lang.IllegalArgumentException: Rescaling cannot be performed on an indexed image

at java.awt.image.RescaleOp.filter(Unknown Source)

at SimpleContrast.main(SimpleContrast.java:25)

Alguém imagina o pq desse erro?
Fiz o teste de converter a imagem para JPEG e daí funcionou… :?:
Coloquei outros tipos de imagem da mesma extensão e tbm funcionou…

11 Respostas

E

Imagem indexada em tif, é preto e branco, e não existe escala para preto e branco, preto é preto e branco é branco, por isso não funciona. :slight_smile:

J

Imagens no formato gif, png e tiff possuem uma tabela de índice de informações de cor. Você não pode redimensionar uma imagem sem tratar essa tabela primeiro.
Provavelmente essa api do java não trata isso.

Você precisa achatar essa imagem em um formato como jpeg antes de usar um algoritmo que faz processamento pixel a pixel.


http://www.awaresystems.be/imaging/tiff.html

Melhorar imagens digitais(contraste) é conhecido como histogram stretching. Um algoritmo simples. É preferível implementá-lo a usar esses de bibliotecas de terceiros como a jai.

você pode:

pxsaida = pixent * c // onde c é o nível de contraste

Você precisa definir um limite para os valores para que não haja um estouro (exemplo o máximo do byte 256 valores, ou o mínimo que é 0).

Pode também usar um algoritmo mais complexo como o de normalização ou equalização.

http://homepages.inf.ed.ac.uk/rbf/HIPR2/stretch.htm

E

Um cheque escaneado por uma leitora de cheques está em um formato TIFF que contém várias imagens (normalmente a frente e o verso).

Dependendo de como o fulano que escaneou os cheques programou a leitora de cheques, ele pode conter imagens que são P&B (o mais comum) ou então em escala de cinza.
A resolução pode ser bem baixinha (tipo 100 pontos por polegada) ou um pouco melhor.

Normalmente o pessoal preza a velocidade de escaneamento, não a qualidade, e então o cheque é meio impossível de você conseguir ler, mesmo fazendo o processamento digital da imagem :frowning: - o pior caso é quando o cheque é escaneado em P&B, aí não dá para fazer mágica mesmo. O contraste não pode ser mexido nesse tipo de imagens.

Você realmente precisa testar o tipo da imagem antes de chamar cegamente RescaleOp.

J

entanglement:
Um cheque escaneado por uma leitora de cheques está em um formato TIFF que contém várias imagens (normalmente a frente e o verso).

Dependendo de como o fulano que escaneou os cheques programou a leitora de cheques, ele pode conter imagens que são P&B (o mais comum) ou então em escala de cinza.
A resolução pode ser bem baixinha (tipo 100 pontos por polegada) ou um pouco melhor.

Normalmente o pessoal preza a velocidade de escaneamento, não a qualidade, e então o cheque é meio impossível de você conseguir ler, mesmo fazendo o processamento digital da imagem :frowning: - o pior caso é quando o cheque é escaneado em P&B, aí não dá para fazer mágica mesmo. O contraste não pode ser mexido nesse tipo de imagens.

Você realmente precisa testar o tipo da imagem antes de chamar cegamente RescaleOp.

Até mesmo um png ou gif indexado com 256 cores. Esse algoritmo deve funcionar apenas com imagens que possuem mais de 8bits por pixel sem índice.

N

entanglement:
Um cheque escaneado por uma leitora de cheques está em um formato TIFF que contém várias imagens (normalmente a frente e o verso).

Dependendo de como o fulano que escaneou os cheques programou a leitora de cheques, ele pode conter imagens que são P&B (o mais comum) ou então em escala de cinza.
A resolução pode ser bem baixinha (tipo 100 pontos por polegada) ou um pouco melhor.

Normalmente o pessoal preza a velocidade de escaneamento, não a qualidade, e então o cheque é meio impossível de você conseguir ler, mesmo fazendo o processamento digital da imagem :frowning: - o pior caso é quando o cheque é escaneado em P&B, aí não dá para fazer mágica mesmo. O contraste não pode ser mexido nesse tipo de imagens.

Você realmente precisa testar o tipo da imagem antes de chamar cegamente RescaleOp.

Pois é, realmente as imagens são em preto e branco.
Consegui um outro algoritmo que faz o contraste (que sinceramente pra mim não melhora em nada), MAS escurece e clareia um pouquinho… rs
Daqui a pouco vou postar aqui a solução.

N

juliocbq:
Imagens no formato gif, png e tiff possuem uma tabela de índice de informações de cor. Você não pode redimensionar uma imagem sem tratar essa tabela primeiro.
Provavelmente essa api do java não trata isso.

Você precisa achatar essa imagem em um formato como jpeg antes de usar um algoritmo que faz processamento pixel a pixel.


http://www.awaresystems.be/imaging/tiff.html

Melhorar imagens digitais(contraste) é conhecido como histogram stretching. Um algoritmo simples. É preferível implementá-lo a usar esses de bibliotecas de terceiros como a jai.

você pode:

pxsaida = pixent * c // onde c é o nível de contraste

Você precisa definir um limite para os valores para que não haja um estouro (exemplo o máximo do byte 256 valores, ou o mínimo que é 0).

Pode também usar um algoritmo mais complexo como o de normalização ou equalização.

http://homepages.inf.ed.ac.uk/rbf/HIPR2/stretch.htm

Muito Obrigada Julio, muito boa a explicação! :smiley:
Vou dar uma boa pesquisada sobre o assunto que agora vou ter que explicar pro chefe… rs

N

Evandro_Contato:
Imagem indexada em tif, é preto e branco, e não existe escala para preto e branco, preto é preto e branco é branco, por isso não funciona. :slight_smile:

Agora faz todo o sentido! Até meio óbvio… rs :oops:

E

Rs, e que ja passei pelo mesmo problema que o seu ate quebrei a cuca dai que fui ver esta diferenca em alguns tiffs que estavam em preto e branco.

Espero ter ajudado,

J

Natalia Lima:
Evandro_Contato:
Imagem indexada em tif, é preto e branco, e não existe escala para preto e branco, preto é preto e branco é branco, por isso não funciona. :slight_smile:

Agora faz todo o sentido! Até meio óbvio… rs :oops:

Você pode ter uma imagem colorida indexada com 4, 16 ou 256 valores.
O fato de ser “preto” ou “branco” não tem relação(Eu poderia ter 3 bandas de cores e a imagem estar limiarizada entre preto e branco) com o problema do redimensionamento.

Para poupar espaço, os arquivos indexados usam somente as “cores usadas nos pixels”. O restante da informação que é todo o intervalo da banda é descartado.
Ex:

pixel(255,1,1) // descartados valores de 0 a 254 para o vermelho, 0,2 a 255 para o verde e o azul.

Em contrapartida eu poderia ter uma imagem em escala de cinza com 256(8 bit por pixel) valores. Esse artifício de índices é usado para imagens coloridas.


E

Legal Julio, eu pensei ser a relação por causa do preto e branco, por eu ter reparado que isso somente acontecia quando digitalizava imagens em preto e branco.

Suas informações foram esclarecedoras :slight_smile:

obrigado,

N

Aí galera, segue a solução.
Fiz com base no código postado aqui --> http://www.java.net/node/654661

Aqui stão só os métodos, no link tem uma classe completa.

/**
     * 
     * Método que faz o contraste
     * 
     * @param paramContraste
     * @return
     */
    public PlanarImage doContrast(float paramContraste) {
        
        contrast += paramContraste;
        
        BufferedImage input = getImageInViewer(frente).getAsBufferedImage();
        BufferedImage index = convertType(input, BufferedImage.TYPE_BYTE_INDEXED);
        
        float scaleFactor = contrast;
        float offset = 1;
        
        return PlanarImage.wrapRenderedImage(rescale(index, scaleFactor, offset));
        
    }
    
    /**
     * 
     * Cria um objeto IndexColorModel
     * 
     * @param indexed
     * @param scaleFactor
     * @param offset
     * @return
     */
    public static BufferedImage rescale(BufferedImage indexed, float scaleFactor, float offset) {
        IndexColorModel icm = (IndexColorModel) indexed.getColorModel();
        return new BufferedImage(rescale(icm, scaleFactor, offset), indexed.getRaster(), false, null);
    }
    
    /**
     * 
     * Separa por cores verde, vermelha e azul
     * 
     * @param icm
     * @param scaleFactor
     * @param offset
     * @return
     */
    public static IndexColorModel rescale(IndexColorModel icm, float scaleFactor, float offset) {
        int size = icm.getMapSize();
        byte[] reds=new byte[size], greens=new byte[size], blues=new byte[size], alphas=new byte[size];
        icm.getReds(reds);
        icm.getGreens(greens);
        icm.getBlues(blues);
        icm.getAlphas(alphas);
        rescale(reds, scaleFactor, offset);
        rescale(greens, scaleFactor, offset);
        rescale(blues, scaleFactor, offset);
        return new IndexColorModel(8, size, reds, greens, blues, alphas);
    }
    
    /**
     * 
     * Executa a reescala de cores
     * 
     * @param comps
     * @param scaleFactor
     * @param offset
     */
    public static void rescale(byte[] comps, float scaleFactor, float offset) {
        for(int i=0; i<comps.length; ++i) {
            int comp = 0xff & comps[i];
            int newComp = Math.round(comp*scaleFactor+offset);
            if (newComp < 0)
                newComp = 0;
            else if (newComp > 255)
                newComp = 255;
            comps[i] = (byte) newComp;
        }
    }
    
    /**
     * 
     * Converte o tipo da imagem 
     * 
     * @param image
     * @param type
     * @return
     */
    public static BufferedImage convertType(BufferedImage image, int type) {
        if (image.getType() == type)
            return image;
        BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), type);
        Graphics2D g = result.createGraphics();
        g.drawRenderedImage(image, null);
        g.dispose();
        return result;
    }
Criado 16 de maio de 2012
Ultima resposta 17 de mai. de 2012
Respostas 11
Participantes 4