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ść?
Spis Treści
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.

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

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.

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

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:

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:

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.

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:
- Inspiracja i zainteresowanie biografią Talleyranda pod wpływem tego wpisu: (nie taki) Krótki przewodnik po tym, jak zostaje się GRACZEM
- Find and Draw Contours using OpenCV | Python
- Contours : Getting Started
- Remove background text and noise from an image using image processing with OpenCV
- Removing Unicode characters from text