Zastanawiasz się może, kim jest tajemniczy „Król Dyplomacji” i co on robi na Google Drive. Tak naprawdę nasz bohater, a raczej jego biografia posłuży do prezentacji tego, jak wydobywać „Nowe Złoto”.

Połączymy w tym celu kilka narzędzi w tym: Computer Vision i OCR (rozpoznawanie tekstu). Oddzielimy sygnał od szumu. Zamienimy nieustrukturyzowane dane w formę przyjaźniejszą do dalszej obróbki.

Wszystko to odbędzie się pod okiem tytułowego bohatera, ikony elastyczności, opanowania i spokoju.

Kim jest zatem ów tajemniczy gość?

Król Dyplomacji

Karol Maurycy de Talleyrand-Perigord był francuskim dyplomatą, ministrem spraw zagranicznych, nawet biskupem. Służył kolejno czterem francuskim reżimom, maczał palce w obaleniu dwóch z nich, wchodził w konszachty z głowami państw wrogich, a za wszystkie przysługi kazał sobie słono płacić. Zawsze u władzy, płynący z prądem, niezmiennie skuteczny.

Niech za charakterystykę naszego bohatera posłuży kilka poniższych cytatów. Cytatami i ich wydobywaniem będziemy zajmować się w tym wpisie.

„U natur złożonych stałość wynika z giętkości.”

“Jego siłą była umiejętność abstrahowania od miłości własnej a nawet interesu, żeby zachować niczym nie zmąconą swobodę myślenia i oceniania (…)”

„Dla Talleyranda „powolność i ostrożność” są przymiotami dyplomaty.”

„Talleyrand wyczuwa na odległość zarówno niepowodzenie jak sukces: nie zwykł przeciwstawiać się prądowi unoszącemu ludzi i sprawy.”

„Koniec roku 1793 jest ponury. Talleyrand wegetuje, można by rzec, że zapada w zimowy sen. To forma owej mądrości, która płynie u niego raczej z instynktu niż z przemyślenia.(…) Obecny stan rzeczy nie będzie trwał wiecznie, bo nic nie trwa wiecznie, a już zwłaszcza to co zostało doprowadzone do przesady. Konwencja i terror zużyją się tym rychłej, im są brutalniejsze. Czas, wierny sprzymierzeniec Talleyranda jest po jego stronie.”

„Przy całej swej ambicji nasz bohater należy do rzadkiego i niebezpiecznego gatunku ludzi spokojnych i nieskończenie cierpliwych.”

„Talleyrand czyli niezrozumiany sfinks” – Jean Orieux

Jak widać postać na trudne czasy. Jako ciekawostkę dodam, że używana książka na allegro kosztowała jakiś czas temu ok. 20 zł. Dzisiaj trudno znaleźć egzemplarz tańszy niż 100 zł. Król Dyplomacji nawet po śmierci wypłynął na powierzchnię.

Zacznijmy więc podróż.

Początek i Koniec Podróży

Zaczynamy z egzemplarzem wyżej wymienionej książki, markerem (różowym, ale nie uprzedzajmy się) i kontem na Dysku Google. Tylko tyle.

Książka, marker i konto Google. Punkt Początkowy.

Przeczytamy i zaznaczymy najlepsze i najbardziej wartościowe dla nas fragmenty książki.

Pierwszy przystanek w podróży.

Końcem podróży będzie plik tekstowy, który będzie zbiorem wszystkich naszych zaznaczeń. Żaden fragment książki nie zostanie przepisany ręcznie. Całość wykona nasz program.

Skanowanie Strony

Mamy książkę z zaznaczonymi z wybranymi cytatami. Potrzebujemy teraz cyfrowego odpowiednika, czyli zdjęcia każdego zaznaczenia. Smartfon i aplikacja do skanowania dokumentów pozwoli to zrobić.

Lista aplikacji do skanowania dokumentów jest dosyć długa. Pewnie sam już korzystałeś nie raz z jakiejś. Wiele z nich ma wbudowane automaty do korekty i poprawy obrazu.

Przy wyborze odpowiedniej aplikacji istotne były dwie kwestie:

  • jakość skanów (ocena wizualna czy jest dobrze czy nie),
  • możliwość synchronizacji zdjęć z Google Drive.

Zostało trzech kandydatów:

  • Google Drive Scan – gdy mamy na smartfonie zainstalowany Google Drive, jest dostępny widżet, który pozwala nam robić zdjęcia bezpośrednio do katalogu, gdzie trzymamy skany.
  • Skaner w Evernote – świetne rozpoznawanie dokumentów tekstowych i automatyczna korekta obrazu, ale słaba opcja z synchronizacją,
  • Adobe Scan – dobre jakościowo zdjęcia, pozwala przyciąć wedle uznania dany dokument i ma możliwość wysłania zdjęcia na Dysk Google.

Ostatecznie wygrał Adobe Scan nie z powodu swoich nadnaturalnych zdolności, ale spełniał oba warunki, które wymieniłem wcześniej.

Pewna uwaga. Przy robieniu zdjęć źródło światła, ale i jego położenia znacząco zmienia jakość zdjęć. Najlepiej, gdy źródło światła nie oświetla stron bezpośrednio (ktoś, kto robi zdjęcia, na pewno już to wie). Jakość zdjęcia jest lepsza, a zaznaczenia wydają się bardziej wyraźnie. Ma to znaczenie przy wykrywaniu konturów interesujących nas fragmentów (o tym trochę dalej).

Po wyborze aplikacji pozostało zrobić zdjęcia kolejnych stron i wysłać je do naszego katalogu ze skanami książki na Google Drive.

Pod przyciskiem „Więcej” kryje się możliwość wysyłania skanów na Google Drive

A tak wygląda lista plików na Google Drive.

Pliki PDF czekające na dalszy etap podróży.

Talleyrand po raz pierwszy na Dysku Google. Jeszcze w surowej, nieobrobionej postaci. Podłączymy teraz nasz program z Dyskiem Google.

Google Drive API i PyDrive

Aby móc pobierać pliki z Dysku Google trzeba włączyć dla naszego konta obsługę API. Tutaj w 4 prostych krokach cała procedura. Bardzo dobry tutorial, dostępny jest również pod tym adresem: Simple way to access to Google Service API.

Najważniejszy krok dla dalszych prac to pobranie do katalogu z programem pliku credentials.json, który zawiera naszą konfigurację klienta Google.

Po konfiguracji API i gdy już wiemy, że działa, dalej korzystamy już z PyDrive. Biblioteka, która opakowuje Google API i upraszcza z nim pracę.

Nawiązania połączenia z poziomu naszego programu wygląda tak jak poniżej. Kod programu opatrzony jest odpowiednim komentarzem, dlatego nie będę tego powielał. Program, część skanów i plik wynikowy dostępny jest na GitHubie.

#import bibliotek
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

# nazwa folderu na Dysku Google na podstawie, której stworzymy katalog lokalny
NAZWA_KSIAZKI = 'ORIEUX_TALLEYRAND'

# połączenie z własnym Dyskiem Google i folderem ze zdjęciami kolejnych stron książki
def polaczenie_google_drive(folder):
    # ustanowienie polaczenia z dyskiem Google
    gauth = GoogleAuth()
    # Tworzymy lokalny webserver do autentykacji
    gauth.LocalWebserverAuth()
    drive = GoogleDrive(gauth)

    # szukamy katalogu z książką na Dysku Google
    ksiazka = drive.ListFile({'q': "title='{}'  and mimeType = 'application/vnd.google-apps.folder'"
                             .format(folder)}).GetList()

    # książką pobieramy na dysk lokalny wszystkie pliki pdf
    for item in ksiazka:
        file_list = drive.ListFile({'q': "'{}' in parents ".format(item['id'])}).GetList()
        for file in file_list:
            download_mimetype = 'application/pdf'
            if file['mimeType'] == download_mimetype:
                file.GetContentFile(os.path.join(folder, file['title']))

Jesteśmy na etapie, gdzie pliki pdf są na naszym dysku lokalnym. Teraz zaczyna się najciekawszy etap podróży.

Detekcja Konturów

Zanim zaczniemy odnajdywać kontury naszych zaznaczeń, musimy dokonać konwersji pdf-ów na pliki png.

Pdf2image

Skorzystamy z pdf2image. Instalujemy ją jak inne biblioteki poleceniem pip install pdf2image. Funkcja, która zamienia po kolei wszystkie pliki.

#import bibliotek
from pdf2image import convert_from_path

# zamieniamy pobrane pliki pdf na png
def zamiana_pdf_na_png(folder):
    sciezka = Path(folder)
    if sciezka.is_dir():
        # tworzymy listę plików w folderze
        lista_plikow = [x for x in sciezka.iterdir() if x.is_file()]
        for item in lista_plikow:
            # sprawdzenie czy nasz plik jest pdf-em
            if item.suffix == '.pdf':
                # zwykle jest jedna strona ale przyjmujemy
                # ostrozne zaloczenie ze w jednym pdfie moze byc kilka stron i zamiana kazdej na 'png'
                pages = convert_from_path(item, 500)
                licznik = 0
                for page in pages:
                    page.save(folder + '/' + licznik + '_' +item.stem + '.png', 'PNG')
                    licznik+=1

OpenCV

OpenCV to podstawowa biblioteka w Computer Vision i skupia się głównie na przetwarzaniu obrazu w czasie rzeczywistym. Bibliotekę opisywał (w świetnym jak zwykle stylu) Mirek Mamczur: Wykrywanie twarzy real-time w 15 liniach kodu w Python, Wykrywanie kolorów w OpenCV. Stwórz samemu „płaszcz niewidkę”!.

My wykorzystamy OpenCV, by z tego:

Przykładowa strona w formacie *.png

Za pomocą tego kodu:

#import bibliotek
import cv2

# przycinamy obraz do fragmentu z zaznaczonym kolorem
def detekcja_konturow(plik):
    # wczytujemy plik
    img = cv2.imread(plik)
    # tworzymy wersję pliku w skali szarosci, przyda sie pozniej
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # tworzymy wersję pliku w zmieniajac domyslny schmat koloru na HSV
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    # wybieramy kanal odpowiadajacy za nasycenie koloru
    nasycenie = hsv[:, :, 1]

    # ustawiamy próg dla nasycenia według ktorego wylapiemy kolorowa czesc
    ret, thresh = cv2.threshold(nasycenie, 40, 255, cv2.THRESH_BINARY)

    # odnajdujemy kontury koloru
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    c = max(contours, key=cv2.contourArea)

    # wymiary prostokąta z konturu
    x, y, w, h = cv2.boundingRect(c)

    # przyciecie obrazu w skali szarosci do kolorowego fragmentu
    out_gray = img_gray[y:y + h, x:x + w].copy()
    return out_gray

Zrobić przycięty obraz w odcieniach szarości, czyli to:

Całkiem niezłe przycięcie już bez koloru pod rozpoznawanie tekstu

Odczytamy teraz przycięty tekst.

Pytesseract

Pytesseract to narzędzie OCR (optical character recognition) dla pythona. Rozpoznaje i czyta tekst na obrazach, obsługuje co istotne język polski i polskie znaki.

Aby powyższy obraz dopieścić i pomóc w odczytaniu tekstu usuwamy jeszcze możliwe szumy i ustawiamy próg dla odcieni szarości tak, aby `pytesseract` mógł odczytać tekst jeszcze lepiej.

#import bibliotek
import pytesseract

# odczytujemy tekst z obrazu w skali szarosci
def czytanie_tekstu(obraz):

    # redukcja szumu
    img = cv2.medianBlur(obraz, 7)

    # próg dla odcieni szarosci
    ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

    # podanie ścieżki do tesseract
    # https://stackoverflow.com/questions/50951955/pytesseract-tesseractnotfound-error-tesseract-is-not-installed-or-its-not-i
    pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

    # rozpoznawanie tekstu z przygotowanego obrazu, z ustawieniem języka polskiego
    cytat = pytesseract.image_to_string(th1, 'pol')

    # zwrócenie gotowego cytatu
    return cytat

Funkcja z wskazanego obrazu zwróci cytat.

strona63.png
Lyn, CU MOZUNUYSNY Mazwat „PrZENNICZCHIAIMI . I OZa NMICIICZINYTNI wyjJą-
tkami. których nie omieszkamy zasygnalizować, kłamie tylko przez po-
minięcie. To, co stwierdza, jest prawdziwe, a ponieważ kłamstwo do-
skonałe prawie nie istnieje, posługiwanie się nim jest głupie, wulgar-
ne, a zwłaszcza nieskuteczne — co jest dokładnym przeciwieństwem
cech Talleyranda. Zadowala się więc genialnym kamuflażem. Mówi
prawdę, by ukryć rzeczy ważne i niebezpieczne, one same pozosta-
ją wszakże tajemnicą. Jego szczerość zwodzi głupców; tego właśnie
pragnął.

€
Jeśli chodzi o dzieciństwo naszeoo bohatera nrawda iect 7oodnąa

Całkiem nieźle, jak na parę linijek kodu. Przed nami już tylko…

Ostatnia Podróż

Zostało już tylko zapisać cytat w pliku tekstowym i po przejściu przez wszystkie obrazy plik zapisać na Dysku Google.

Za te dwa zadania odpowiadają dwie poniższe funkcje. Jedna to zapisywanie kolejnych cytatów do pliku tekstowego.

# zapis cytatow do pliku tekstowego
def zapisywanie_cytatow(plik, cytat):
    tryb = 'a' if os.path.exists(plik) else 'w'
    with open(plik, tryb,encoding='utf-8') as f:
        f.write(cytat + '\n')
 

Druga funkcja wysyła zbiorczy plik z naszymi zaznaczeniami na Dysk Google:

# laczymy sie z dyskiem Google i wysylamy plik zbiorczy z cytatami
def wyslanie_pliku(plik):

    gauth = GoogleAuth()
    gauth.LocalWebserverAuth()  # Creates local webserver and auto handles authentication.
    drive = GoogleDrive(gauth)

    with open(plik, 'r', encoding='utf-8') as f:
        pelny_tekst = f.read()
        plik_na_dysku = drive.CreateFile({'title': plik})
        plik_na_dysku.SetContentString(pelny_tekst,encoding='utf-8')
        plik_na_dysku.Upload()

Po tej ostatniej operacji mamy już swoje zaznaczenia w postaci pliku tekstowego. Talleyrand trafił na Dysk Google po raz drugi.

Gotowy plik z cytatami na Dysku Google

Co Dalej?

Efekt, który osiągnęliśmy, jest naprawdę dobry. Jest jeszcze sporo miejsca na ewentualne poprawki. Można lepiej przycinać tekst, usuwać zbędne znaki.

Można, zamiast jednego koloru wykorzystać inne do oznaczeń konkretnych fragmentów tekstu i za pomocą kolorów tworzyć kategorie.

Inne podejście to zastosować symbole i oznaczenia na marginesie, takie jak tutaj. Wtedy można wykorzystać Template Matching i Deep Learning do rozpoznawania symboli i znów stworzyć osobne kategorie.

Podsumowanie

Celem powyższego projektu było wykorzystanie szeroko dostępnych narzędzi, aby wydobyć dane i przetworzyć je do użyteczniejszej formy. Wykorzystana biografia to tylko przykład. Równie dobrze mogą to być obrazy i skany faktur, paragonów, umów a zaznaczeniami kwot, dat, czy istotnych zapisów.

Miejscem przeznaczenia nie musi też być zwykły plik tekstowy. W poprzednim wpisie Python i Pandas Jedzą Zupę, pokazywałem jak dane umieścić w bazie danych SQL Server.

Jeśli masz ochotę poeksperymentować ze swoimi skanami, gotowy projekt do pobrania tutaj.

Przy okazji chciałbym podziękować jednej osobie, bez której najprawdopodobniej nie byłoby tego bloga, a ten wpis by się nie ukazał. Wielkie dzięki dla Rafała Mazura (zenjaskiniowca.pl), za jego wpisy, programy, pomoc w obraniu kierunku i ruszeniu tyłka, pomimo tego, że osobiście się nie znamy.

Linki

Poniżej garść linków, źródeł i inspiracji wykorzystanych przy tym projekcie ponadto co jest zamieszczone powyżej: