Quais são os melhores algoritmos para limiar de imagem de documento neste exemplo?

31

Estou tentando implementar vários algoritmos de binarização na imagem mostrada: insira a descrição da imagem aqui

Aqui está o código:

clc;
clear;
x=imread('n2.jpg');     %load original image

Agora redimensionamos as imagens para que o trabalho computacional se torne mais fácil posteriormente para nós.

size(x);
x=imresize(x,[500 800]);
figure;
imshow(x);
title('original image');

z=rgb2hsv(x);       %extract the value part of hsv plane
v=z(:,:,3);
v=imadjust(v);

% agora encontramos a média e o desvio padrão necessários para os algoritmos niblack e% sauvola

m = mean(v(:))
s=std(v(:))
k=-.4;
value=m+ k*s;
temp=v;

% de implementação do algoritmo de limiar niblack:

for p=1:1:500
    for q=1:1:800
        pixel=temp(p,q);
        if(pixel>value)
            temp(p,q)=1;
        else
            temp(p,q)=0;
        end
    end
end
figure;
imshow(temp);
title('result by niblack');
k=kittlerMet(g);
figure;
imshow(k);
title('result by kittlerMet');

% de implementação do algoritmo de limiar de sauvola:

val2=m*(1+.1*((s/128)-1));
t2=v;
for p=1:1:500
for q=1:1:800
    pixel=t2(p,q);
    if(pixel>value)
        t2(p,q)=1;
    else
        t2(p,q)=0;
    end
end

fim

figure;
imshow(t2);
title('result by sauvola');

Os resultados obtidos são os seguintes: insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui

Como você pode ver, as imagens resultantes são degradadas nos pontos mais escuros. Alguém poderia sugerir como otimizar meu resultado?

marca
fonte
1
Você pode usar as informações de cores para jogar fora o fundo em vez de apenas o brilho?
Endolith
Respeitado senhor / senhora. Estou fazendo um projeto sobre processamento de imagem.estou interessante conceito de binarização ... verifique e corrija a codificação ... Pego a codificação e executo o programa. Mas ocorre algum erro nessa codificação ... Função indefinida ou variável 'g'. e outro é Erro no msp (linha 31) k = kittlerMet (g); .. Como resolvê-lo ... Corrija a codificação ...
muthu 20/15

Respostas:

49

Sua imagem não possui brilho uniforme; portanto, você não deve trabalhar com um limite uniforme. Você precisa de um limite adaptável. Isso pode ser implementado pré-processando a imagem para tornar o brilho mais uniforme em toda a imagem (código escrito no Mathematica, você precisará implementar a versão do Matlab por conta própria):

Uma maneira simples de uniformizar o brilho é remover o texto real da imagem usando um filtro de fechamento:

white = Closing[src, DiskMatrix[5]]

insira a descrição da imagem aqui

O tamanho do filtro deve ser escolhido maior que a largura do traço da fonte e menor que o tamanho das manchas que você está tentando remover.

Edição: fui convidado nos comentários para explicar o que uma operação de fechamento faz. É uma dilatação morfológica seguida por uma erosão morfológica . A dilatação move essencialmente o elemento estruturador em todas as posições da imagem e seleciona o pixel mais brilhante sob a máscara, assim:

  • removendo estruturas escuras menores que o elemento estruturador
  • encolhendo estruturas escuras maiores pelo tamanho do elemento estruturador
  • ampliando estruturas brilhantes

A operação de erosão faz o oposto (ele seleciona o pixel mais escuro embaixo do elemento estruturador); portanto, se você o aplicar na imagem dilatada:

  • as estruturas escuras que foram removidas porque são menores que o elemento estruturador ainda se foram
  • as estruturas mais escuras que foram encolhidas são novamente ampliadas para o tamanho original (embora sua forma seja mais suave)
  • as estruturas brilhantes são reduzidas ao tamanho original

Portanto, a operação de fechamento remove pequenos objetos escuros com apenas pequenas alterações em objetos escuros maiores e objetos brilhantes.

Aqui está um exemplo com diferentes tamanhos de elementos de estruturação:

insira a descrição da imagem aqui

À medida que o tamanho do elemento estruturador aumenta, mais e mais caracteres são removidos. No raio = 5, todos os caracteres são removidos. Se o raio aumentar ainda mais, as manchas menores também serão removidas:

insira a descrição da imagem aqui

Agora você apenas divide a imagem original por esta "imagem em branco" para obter uma imagem de brilho (quase) uniforme:

whiteAdjusted = Image[ImageData[src]/ImageData[white]*0.85]

insira a descrição da imagem aqui

Agora, esta imagem pode ser binarizada com um limite constante:

Binarize[whiteAdjusted , 0.6]

insira a descrição da imagem aqui

Niki Estner
fonte
5
Uau! Isso é muito legal! Enorme +1!
Phonon
@nikie +1 Muito bom - o que você quer dizer com fechar o filtro deve ser "escolhido maior que o traço da fonte"? Largura ou comprimento de qualquer letra? Além disso, o que um filtro de fechamento está 'realmente' fazendo? Obrigado!
Spacey
1
@ Mohammad: Adicionei uma pequena explicação à minha resposta. E sim, essas são operações não lineares. O cabeçalho comum é o processamento de imagem morfológica.
Niki Estner 04/04
1
@nikie Não importa, o branco é o máximo, não o preto. :-)
Spacey
1
@gdelfino: Eu geralmente tento evitá-lo usando uma máscara grande o suficiente, e uso Clip[ImageData[white],{eps,Infinity}]onde eps é um número pequeno, para estar seguro.
Niki Estner
6

A resposta de Nikie parece melhor e também parece estar funcionando e produzindo resultados. Portanto, é um vencedor claro.

No entanto, apenas para a documentação, adicionando mais uma referência, que poderia ser muito rápida.

Esta técnica é chamada de limiar adaptativo, que não requer a aprender o fundo explicitamente.

Essencialmente, em vez de encontrar o limite global mais adequado - podemos particionar a imagem em uma janela local (por exemplo, 7x7 ou apropriada) e encontrar limites que mudam conforme a janela atravessa.

A referência abaixo detalha o método exato. http://homepages.inf.ed.ac.uk/rbf/HIPR2/adpthrsh.htm

Este método seria relativamente mais rápido computacionalmente.

Dipan Mehta
fonte
Essas duas coisas não são essencialmente iguais? Ou seja, estimar a média local do sinal antes do limiar?
Maurits
1
@Maurits Parece que as principais diferenças são a ordem e as estatísticas usadas. Por exemplo, nos operadores de abertura / fechamento (que são compostos de dilatação e erosão, mas em uma ordem diferente), uma janela é varrida por varredura e o máximo é obtido. (Entre outras coisas). No entanto, no limiar adaptativo, a média / mediana pode ser obtida em vez do valor máx.
Spacey
A OP também perguntou sobre o SO , o que eu respondi. Mas, em princípio, não acho que exista diferença entre as respostas, é sempre estimar as estatísticas locais. Se você fizer um limiar adaptativo, também aprenderá os antecedentes do processo.
Maurits
6

Outra maneira de usar um filtro passa-banda (no MATLAB). Brincar com a diferença de parâmetros gaussianos pode dar melhores resultados. O processo é basicamente filtrar a imagem da banda para remover os blobs de fundo de baixa frequência, normalizar para [0,1] necessário para o comando 'greythresh', imagem de limite.

Carregar imagem e converter em escala de cinza dupla:

I = imread('hw.jpg');
I = rgb2gray(I);
I = double(I);

insira a descrição da imagem aqui

Filtre usando a diferença do kernel Gaussiano e normalize:

J = imgaussian(I,1.5) - imgaussian(I,0.5);
J = J - min(J(:));
J = J / max(J(:));

insira a descrição da imagem aqui

Calcule o limite e efetue 010101:

T = J > graythresh(J);

insira a descrição da imagem aqui

geometrikal
fonte
4

Este é um bom código Matlab para limiar adaptável: http://www.mathworks.com/matlabcentral/fileexchange/8647-local-adaptive-thresholding

MyCarta
fonte
Argh! Requer a caixa de ferramentas de processamento de imagem. : - /
Spacey
De fato. Desculpe se você não o tem. Mas o DIPImage é um Image Tolbox gratuito para o Matlab. diplib.org/documentation Possui alguns métodos para limiar (seção de segmentação de verificação) e você também pode executar todas as operações morfológicas, como fechamento. O desenvolvedor também tem um blog cb.uu.se/~cris/blog/index.php/archives/tag/matlab
MyCarta
0

Vou tentar esta codificação. Mas eu não tenho uma resposta correta ...

clc;
clear;
x=imread('base2.jpg');
size(x);
x=imresize(x,[500 800]);
figure;
imshow(x);
title('original image');
z=rgb2hsv(x);       %extract the value part of hsv plane
v=z(:,:,3);
v=imadjust(v);
m = mean(v(:))
s=std(v(:))
k=-2;
value=m+ k*s;
temp=v;
for p=1:1:500
    for q=1:1:800
        pixel=temp(p,q);
        if(pixel>value)
            temp(p,q)=1;
        else
            temp(p,q)=0;
        end
    end
end
figure;
imshow(temp);
title('result by niblack');
% k=kittlerMet(g);
% figure;
% imshow(k);
% title('result by kittlerMet');

val2=m*(1+.1*((s/128)-1));
t2=v;
for p=1:1:500
for q=1:1:800
    pixel=t2(p,q);
    if(pixel>value)
        t2(p,q)=1;
    else
        t2(p,q)=0;
    end
end

end
figure;
imshow(t2);
title('result by sauvola');

insira a descrição da imagem aqui

insira a descrição da imagem aqui

muthu
fonte
2
Se isso pretende responder à pergunta, explique o que você está fazendo e por quê.
Matt L.