Przeglądarka: CCBot/2.0 (http://commoncrawl.org/faq/).
Strona dobrze działa w przeglądarkach:
IE 5.0, Mozilla 0.9.5, Netscape 6,
Opera 6, Konqueror 3.1 lub nowszych.
Strona może być błędnie wyświetlana!
Login: 
Hasło: 
 
# HTML #
Gość
Wyszukaj na tej stronie:
 

PHPocr

Czy pisząc w języku PHP skrypt automatycznie wykonujący pewne operacje na danej stronie WWW, da się obejść jakże dziś popularne zabezpieczenie polegające na konieczności wpisania przez użytkownika w formularzu tekstu widocznego na obrazku? Okazuje się że tak. Ten artykuł nie jest kompletnym źródłem informacji na temat łamania tego typu zabezpieczeń. Pokazuję tu jedynie w jaki sposób można odczytać tekst o znanej nam czcionce, na jednolitym tle.

Liczy się sama idea. Dynamicznie umieszczać tekst w obrazku z poziomu PHP z rozszerzeniem GD jest banalnie łatwo. Odwrotna operacja jest znacznie trudniejsza. O tym czy nasz skrypt będzie działał względnie szybko i dokładnie zadecyduje algorytm który zostanie użyty do rozpoznawania tekstu. Ja użyłem wydaje mi się najprostszego, chciało by się rzec łopatologicznego. Algorytm moim zdaniem nie jest najlepszy, gdyż czas jego wykonywania w znacznym stopniu zależy od wielkości skanowanego obrazka, rozmiarów użytej znanej nam w tym przypadku jednej ze standardowych czcionek PHP, ilości znaków w szablonach z którymi porównywane są kolejne wycinki obrazka i tła które musi być jednolite. Sporo tych ograniczeń ale jeśli opanujemy odczyt tekstu w znanej nam czcionce, widocznego na jednolitym tle, to później będziemy w stanie rozważyć kolejne utrudnienia których w tym artykule niestety nie obejmę. I w tym momencie wspomnę tylko że jeśli macie pomysł na lepszy algorytm, a uważam że da się stworzyć lepszy, dokładniejszy i bardziej wydajny, to mail me.

A teraz konkretnie. Odczytujemy obrazek.

<?php

$procent=98; //tolerancja

// Skanowanie obrazka
$image=ImageCreateFromPng("test4.png");

ImageGammaCorrect($image, 0.0001, 1000.0);
ImageTrueColorToPalette($image, true, 2);
$text_index=ImageColorClosest($image,0,0,0);
ImageColorSet($image,$text_index,0,0,0);
$bg_index=ImageColorClosest($image,255,255,255);
ImageColorSet($image,$bg_index,255,255,255);

$szerokosc=ImageSX($image);
$wysokosc=ImageSY($image);

$image2=ImageCreate($szerokosc,$wysokosc);
$background_color = ImageColorAllocate($image2,255,255,255);
$text_color = ImageColorAllocate($image2,0,0,0);
ImageTrueColorToPalette($image2, true, 2);
ImageCopy($image2, $image, 0, 0, 0, 0, $szerokosc, $wysokosc);
$image=$image2;
ImageDestroy($image2);

for($j=0;$j<$wysokosc;$j++)
{
   for($i=0;$i<$szerokosc;$i++)
   {

     $indeks[$i][$j]=ImageColorAt($image,$i,$j);

   }
}

ImageDestroy($image);

...
?>


- Jak widać na podstawie obrazka w formacie PNG tworzymy nowy obiekt o nazwie "$image". Tworzymy go za pomocą funkcji ImageCreateFromPNG(). Oczywiście dla plików graficznych w innych formatach należy stosować inne odpowiedniki tej funkcji.
- Następnie obrabiamy odpowiednio nasz obrazek za pomocą funkcji ImageGammaCorrect(), uzyskując skrajnie kontrastowy czarno-biały obraz.
- Po tej operacji redukujemy głębię obrazu do 2 kolorów.
- W tym momencie potrzebny jest człowiek. Musimy poinformować parser PHP czy tekst jest jaśniejszy niż tło, czy też jest odwrotnie. Wykorzystując funkcję ImageColorClosest() definiujemy indeksy kolorów najbliższych kolorowi białemu i czarnemu we właśnie utworzonej palecie kolorów. Następnie poprzez funkcję ImageColorSet() "na sztywno" określamy kolor dla indeksu palety najbliższemu kolorowi białemu i to samo robimy dla koloru czarnego. Po konwersji obrazka otrzymaliśmy 2-kolorową paletę, więc nie powinno być z tym problemu.
- Wykorzystując funkcje ImageSX() i ImageSY() pobieramy szerokość i wysokość obrazka.
- Tworzymy nowy obrazek w palecie 256 kolorów poprzez funkcję ImageCreate().
- I tu ważny moment. Alokujemy w nim kolor tła do pierwszego indeksu oraz kolor tekstu do drugiego.
- Redukujemy głębię kolorów tego obrazka do dwóch kolorów.
- Kopiujemy pierwotny obrobiony obraz do naszego nowo przygotowanego obrazka ze zdefiniowanymi przez nas indeksami kolorów tekstu i tła. To bardzo ważne. Gdybyśmy tego nie zrobili, operacje porównania indeksów kolorów odpowiednich pikseli z wycinków obrazka i szablonów znaków zwracały by błędne wyniki.
- Z tak przygotowanego obrazka za pomocą funkcji ImageColorAt() wyodrębniamy indeksy kolorów poszczególnych pikseli i umieszczamy je w 2-wymiarowej tablicy "$index[][]".
- Następnie uwalniamy pamięć z niepotrzebnych obrazów, gdyż od tej pory operujemy na tablicy indeksów obrazu pierwotnego.

Tworzymy szablony znaków, z którymi będą porównywane wycinki naszego obrazka.

<?php
...
$znaki='AˇBCĆDEĘFGHIJKLŁMNŃOÓPQRSśTUVWXYZ¬Żaąbcćdeęfg
hijklłmnńoópqrsśtuvwxyzźż0123456789';

// Generowanie szablonow liter
$k=10; $l=20;

$s=5;

if ($s==1) {$k=4; $l=8;}
else if ($s==2) {$k=5; $l=13;}
else if ($s==3) {$k=6; $l=13;}
else if ($s==4) {$k=7; $l=16;}
else if ($s==5) {$k=8; $l=16;}

for($c=0;$c<=strlen($znaki);$c++) //kolejny znak z tablicy $znaki
{

   $znak=$znaki[$c];

   $imszablon=ImageCreate($k,$l);
   $background_color = ImageColorAllocate($imszablon,255,255,255);
   $text_color = ImageColorAllocate($imszablon,0,0,0);
   ImageString($imszablon,$s,0,0,$znak,$text_color);
   ImageTrueColorToPalette($imszablon, true, 2);

     for($j=0;$j<$l;$j++)
     {
       for($i=0;$i<$k;$i++)
       {

         $szablon[$znak][$s][$i][$j]=ImageColorAt($imszablon,$i,$j);

       }
     }

   ImageDestroy($imszablon);

}

...
?>


- W zmiennej "$znaki" definiujemy znaki które mają być rozpoznawane przez nasz skrypt. W dalszej części skryptu zmienną "$znaki" będziemy traktować jako 1-wymiarową tablicę.
- Zależnie od wielkości czcionki "$s" określamy szerokość znaku "$k" i jego wysokość "$l".
- Z utworzonej przed chwilą tablicy "$znaki[]" pobieramy osobno każdy umieszczony w niej znak. Na jego podstawie tworzymy obraz "$imszablon".
- W tym obrazie za pomocą funkcji ImageString() osadzamy dany znak. Funkcja ImageString() przyjmuje jako 1 z argumentów rodzaj czcionki. Standardowe czcionki PHP oznaczane są cyframi 1-5.
- Obraz ten poddajemy identycznej obróbce co na początku obraz "$image".
- Z obrazu "$imszablon" wyodrębniamy indeksy kolorów poszczególnych pikseli i tak jak już to miało miejsce w przypadku obrazu "$image", umieszczamy je w tablicy, tym razem 4-wymiarowej o nazwie "$szablon[][][][]". W tej tablicy oprócz pozycji w pionie i poziomie danego piksela indeksowana jest wielkość czcionki i znak którego układ jest w danej chwili ewidencjonowany.

Porównujemy indeksy kolorów odpowiednich pikseli.

<?php
...

$zgodne=0;
$wszystkie=0;

// Porównywanie pikseli

if ($s==1) {$k=4; $l=8;}
else if ($s==2) {$k=5; $l=13;}
else if ($s==3) {$k=6; $l=13;}
else if ($s==4) {$k=7; $l=16;}
else if ($s==5) {$k=8; $l=16;}


for($y=0;$y<$wysokosc-$l;$y++)
{

   for($x=0;$x<$szerokosc-$k;$x++)
   {

     for($c=0;$c<=strlen($znaki);$c++) //kolejny znak z tablicy $znaki
     {
     $znak=$znaki[$c];

       for($j=0;$j<$l;$j++)
       {

         for($i=0;$i<$k;$i++)
         {

           $wszystkie++;
           if ($indeks[$i+$x][$j+$y]==$szablon[$znak][$s][$i][$j])
           $zgodne++;

         } //i

       } //j

       if ($zgodne/$wszystkie>=$procent/100) print $znak;
       $wszystkie=0;
       $zgodne=0;

     } //c

   } //x

} //y

?>


- Definiujemy 2 zmienne: "$wszystkie" i "$zgodne". Ich wartości przyrównujemy do zera.
- Zależnie od wielkości czcionki "$s" określamy szerokość znaku "$k" i jego wysokość "$l".
- Porównujemy ze sobą indeksy kolorów odpowiednich pikseli pochodzących z wycinków obrazka i wygenerowanych szablonów znaków.
- Dla każdej kombinacji szablonu znaku i wycinka obrazu liczymy ilość odpowiednich indeksów pikseli których wartości się zgadzają.
- Po porównaniu wszystkich wycinków obrazu w poziomie, weryfikujemy sumę zgodnych indeksów kolorów odpowiednich pikseli.
- W przypadku gdy ilość zgodnych indeksów podzielona przez ilość wszystkich indeksów jest większa bądź równa ustawionej na początku tolerancji dzielonej przez 100, w oknie przeglądarki wypisywany jest dany znak.
- Następnie zmienne "$wszystkie" i "zgodne" są zerowane, aby kolejna pętla mogła się prawidłowo wykonać.

Tolerancja jest wartością która określa akceptowalne odchylenie liczby zgodnych pikseli. Im jest ona wyższa, z tym większa dokładnością badane są obrazy. W praktyce skrypt najlepiej działaja przy wartości zmiennej "$tolerancja" ustawionej pomiędzy 98-100.

Możemy stosować do szablonów inne czcionki niż te standardowe w PHP. W funkcji ImageString() wystarczy zamiast cyfry identyfikującej rodzaj standardowej czcionki użyć funkcji ImageLoadFont(), która jako argument przyjmuje ścieżkę do pliku GDF będącego plikiem czcionek dla rozszerzenia PHP_GD.

Przedstawiony skrypt pisałem zakładając że tekst w skanowanym obrazie jest ciemniejszy niż jego tło. W sytuacji odwrotnej należy zamienić ze sobą miejscami kolory RGB(255,255,255) i RGB(0,0,0). Skrypt nie jest idealny. Można go z pewnością udoskonalić, ale powinien on dać solidne podstawy do stworzenia prawdziwego skryptu typu PHPocr :-)







Generated in: 0.066 s
Copyright © 2002-2017 Sigillum Diaboli

1686 IP banned