Jakie są najlepsze algorytmy progowania obrazu dokumentu w tym przykładzie?

31

Próbuję zaimplementować różne algorytmy binaryzacji na pokazanym obrazie: wprowadź opis zdjęcia tutaj

Oto kod:

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

% Teraz zmieniamy rozmiar obrazów, aby praca obliczeniowa stała się dla nas łatwiejsza.

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);

% teraz znajdujemy średnią i standardowe odchylenie wymagane dla algorytmów niblack i% sauvola

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

% implementujących algorytm progowania niblacka:

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');

% implementujących algorytm progowy sauvoli:

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

koniec

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

Wyniki, które uzyskałem są następujące: wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Jak widać, powstałe obrazy są degradowane w ciemniejszych miejscach. Czy ktoś mógłby zasugerować, jak zoptymalizować mój wynik?

znak
źródło
1
Czy możesz użyć informacji o kolorze, aby wyrzucić tło zamiast samej jasności?
endolith
Szanowany Pan / Pani. Robię projekt przetwarzania obrazu. Jestem ciekawą koncepcją binaryzacji .. proszę sprawdzić i poprawić kodowanie ... biorę kodowanie i uruchamiam program, ale wystąpił błąd podczas tego kodowania ... niezdefiniowana funkcja lub zmienna 'g'. a innym jest Błąd w msp (linia 31) k = kittlerMet (g); .. Jak go rozwiązać ... Proszę poprawić kodowanie ...
muthu

Odpowiedzi:

49

Twój obraz nie ma jednolitej jasności, więc nie powinieneś pracować z jednolitym progiem. Potrzebujesz progu adaptacyjnego. Można to zaimplementować poprzez wstępne przetworzenie obrazu w celu ujednolicenia jasności obrazu (kod napisany w Mathematica, musisz zaimplementować wersję Matlab dla siebie):

Prostym sposobem na wyrównanie jasności jest usunięcie faktycznego tekstu z obrazu za pomocą filtra zamykającego:

white = Closing[src, DiskMatrix[5]]

wprowadź opis zdjęcia tutaj

Rozmiar filtra należy wybrać większy niż szerokość obrysu czcionki i mniejszy niż rozmiar plam, które próbujesz usunąć.

EDYCJA: W komentarzach poproszono mnie o wyjaśnienie, co robi operacja zamknięcia. Jest to rozszerzenie morfologiczne, po którym następuje erozja morfologiczna . Dylatacja zasadniczo przesuwa element strukturyzujący w każdej pozycji obrazu i wybiera najjaśniejszy piksel pod maską, w ten sposób:

  • usuwanie ciemnych struktur mniejszych niż element strukturujący
  • zmniejszanie większych ciemnych struktur o wielkość elementu strukturyzującego
  • powiększanie jasnych struktur

Operacja erozji działa odwrotnie (wykrywa najciemniejszy piksel wewnątrz elementu strukturyzującego), więc jeśli zastosujesz go na rozszerzonym obrazie:

  • ciemne struktury, które zostały usunięte, ponieważ są mniejsze niż element strukturalny, nadal zniknęły
  • ciemniejsze struktury, które zostały zmniejszone, są ponownie powiększane do ich pierwotnego rozmiaru (chociaż ich kształt będzie gładszy)
  • jasne struktury są zredukowane do pierwotnego rozmiaru

Dlatego operacja zamykania usuwa małe ciemne obiekty z niewielkimi zmianami w większych ciemnych i jasnych obiektach.

Oto przykład z różnymi rozmiarami elementów strukturalnych:

wprowadź opis zdjęcia tutaj

Wraz ze wzrostem wielkości elementu strukturyzującego coraz więcej znaków jest usuwanych. Przy promieniu = 5 wszystkie znaki są usuwane. W przypadku dalszego zwiększenia promienia usuwane są również mniejsze plamy:

wprowadź opis zdjęcia tutaj

Teraz wystarczy podzielić oryginalny obraz przez ten „biały obraz”, aby uzyskać obraz o (prawie) jednolitej jasności:

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

wprowadź opis zdjęcia tutaj

Ten obraz można teraz poddać binaryzacji ze stałym progiem:

Binarize[whiteAdjusted , 0.6]

wprowadź opis zdjęcia tutaj

Niki Estner
źródło
5
Łał! To jest naprawdę fajne! Ogromny +1!
Phonon
@nikie +1 Bardzo fajnie - co dokładnie rozumiesz przez zamknięcie filtra, musisz wybrać „większy niż obrys czcionki”? Szerokość lub długość dowolnej litery? Ponadto, co naprawdę robi filtr zamykający? Dzięki!
Spacey
1
@Mohammad: Do mojej odpowiedzi dodałem małe wyjaśnienie. I tak, są to operacje nieliniowe. Wspólnym nagłówkiem jest morfologiczne przetwarzanie obrazu.
Niki Estner
1
@nikie Nieważne, biały to maksimum, a nie czarny. :-)
Spacey
1
@gdelfino: Zwykle staram się tego unikać, używając wystarczająco dużej maski i używam Clip[ImageData[white],{eps,Infinity}]tam, gdzie eps jest małą liczbą, aby być bezpiecznym.
Niki Estner
6

Odpowiedź Nikie wydaje się najlepsza, a także wydaje się działać i przynosić rezultaty. Jest to więc wyraźny zwycięzca.

Jednak tylko do dokumentacji dodam jeszcze jedno odniesienie, które może być bardzo szybkie.

Ta technika nazywa się Adaptacyjnym progiem, który nie wymaga wyraźnego poznania tła.

Zasadniczo, zamiast znaleźć najbardziej odpowiedni globalny próg - możemy podzielić obraz na okno lokalne (powiedzmy o 7x7 lub odpowiednio) i znaleźć progi, które zmieniają się w miarę przechodzenia okna.

Poniższe odniesienie szczegółowo opisuje dokładną metodę. http://homepages.inf.ed.ac.uk/rbf/HIPR2/adpthrsh.htm

Ta metoda byłaby względnie szybsza obliczeniowo.

Dipan Mehta
źródło
Czy te dwie rzeczy nie są zasadniczo takie same? Mianowicie szacowanie lokalnej średniej sygnału przed progowaniem?
Maurits,
1
@Maurits Wygląda na to, że głównymi różnicami są kolejność i użyte statystyki. Na przykład w operatorach otwierania / zamykania (które składają się z dylatacji i erozji, ale w innej kolejności), okno jest skanowane rastrowo i pobierane jest maksimum. (Między innymi). Jednak w progu adaptacyjnym można przyjąć średnią / medianę zamiast wartości maksymalnej.
Spacey,
OP poprosił o to również na SO , na co odpowiedziałem. Ale w zasadzie nie sądzę, żeby między odpowiedziami była jakakolwiek różnica, zawsze szacuje się lokalne statystyki. Jeśli wykonasz progowanie adaptacyjne, poznasz także tło procesu.
Maurits,
6

Innym sposobem jest użycie filtra pasmowoprzepustowego (w MATLAB). Zabawa z różnicą parametrów Gaussa może dać lepsze wyniki. Proces polega w zasadzie na filtrowaniu pasmowym obrazu w celu usunięcia plamek tła niskiej częstotliwości, normalizacji do [0,1] wymaganej dla polecenia „graythresh”, obraz progowy.

Załaduj obraz i przekonwertuj do podwójnej skali szarości:

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

wprowadź opis zdjęcia tutaj

Filtruj używając różnicy jądra Gaussa i normalizuj:

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

wprowadź opis zdjęcia tutaj

Obliczyć próg i zrobić 010101:

T = J > graythresh(J);

wprowadź opis zdjęcia tutaj

geometrikal
źródło
4

Jest to dobry kod Matlaba do adaptacyjnego progowania: http://www.mathworks.com/matlabcentral/fileexchange/8647-local-adaptive-thresholding

MyCarta
źródło
Argh! Wymaga jednak przybornika do przetwarzania obrazu. : - /
Spacey,
W rzeczy samej. Przepraszam, jeśli go nie masz. Ale DIPImage to darmowy Tolbox obrazu dla Matlaba. diplib.org/documentation Ma kilka metod progowania (sprawdź sekcję segmentacji), a także możesz wykonywać wszystkie operacje morfologiczne, takie jak zamykanie. Deweloper ma również blog cb.uu.se/~cris/blog/index.php/archives/tag/matlab
MyCarta
0

Spróbuję tego kodowania, ale nie mam poprawnej odpowiedzi ...

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');

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

muthu
źródło
2
Jeśli ma to odpowiedzieć na pytanie, wyjaśnij, co robisz i dlaczego.
Matt L.