Skip to content
Snippets Groups Projects

Vylepšení skenování - prázdné stránky, otáčení, vylepšení UI

Merged Jiří Setnička requested to merge jirka/scans into devel
1 file
+ 31
3
Compare changes
  • Side-by-side
  • Inline
  • Navazujeme na vyprahovaný černobílý obrázek, který používá detekce QR
    kódů. Pokud žádný QR kód nenajdeme, tak provádíme:
    
    * ořez 10 pixelů z každé strany pro odstranění divných hran ze skeneru
    * jeden krok eroze maticí 3x3 pro odstranění šumu a smetí na skeneru
      (pro každý pixel vezmeme maximum z jeho 3x3 okolí = eroze černých oblastí)
    * spočítáme entropii obrázku (skrze metodu PIL.Image.entropy())
    
    Pokud spočítaná entropie překročí threshold 0.005, tak stránku
    odhadneme za plnou, jinak ji odhadneme za prázdnou.
    
    Testování thresholdu na Xerox scanneru, seřazené podle entropie:
    * prázdná úplně bílá stránka (uměle vyrobená): 0.0
    * prázdná nezmačkaná stránka: 0.0000054647
    * prázdná zmačkaná a natržená stránka: 0.0000314348
    * vygenerované PDF s hlavičkou protokolu (neprošlo skenem, čisté PDF): 0.0166886208
    * sken ručních zápisků na kostičkovaný papír (popsaná 1/4 stránky): 0.0764304045
    * vybledlá pomačkaná faktura vytisklá s docházejícím tonerem: 0.0833685388
    * sken ručních zápisků na kostičkovaný papír (popsána 1/2 stránky): 0.1503896076
    * nějaký vyplněný formulář (tisk + propiska, nezmačkaný): 0.2290705466
    * sken ručních zápisků na kostičkovaný papír (popsána celá stránka, hodně škrtání): 0.2393648031
    
    Zatím není informace využitá, použije se v dalších commitech.
+ 31
3
# Implementace jobů na práci s protokoly
from PIL import Image
from PIL import Image, ImageFilter
from dataclasses import dataclass, field
import multiprocessing
import os
@@ -21,6 +21,11 @@ from mo.util import logger, part_path, tex_arg
import mo.util_format
SCAN_BW_THRESHOLD = 180 # 0-255, pixel nad toto číslo = bílý pixel
# Parametry pro detekci prázdných stránek:
EMPTY_PAGE_CROP = 10 # kolik px z každé strany uříznout
EMPTY_PAGE_ERODE_SIZE = 3 # jak velkou maticí K×K erodovat
EMPTY_PAGE_ERODE_COUNT = 1 # kolikrát erodovat
EMPTY_PAGE_ENTROPY_THRESHOLD = 0.005 # Image.entropy() menší než X → prázdná stránka
#
# Job create_protocols: Vygeneruje formuláře protokolů
@@ -211,6 +216,7 @@ class ScanJobArgs:
@dataclass
class ScanJobPage:
code: Optional[str]
empty: bool
@dataclass
@@ -369,14 +375,36 @@ def _process_scan_file(args: ScanJobArgs) -> ScanJobResult:
qr = code.data.decode('US-ASCII')
# FIXME: Tady by se dala podle kódu otočit stránka
res.pages.append(ScanJobPage(code=qr))
# Pokud jsme našli QR kód, stránka určitě prázdná není, jinak to musíme odhadnout
empty = False
entropy = 0.0
if not qr:
# uříznutí okrajů (nepřesné okraje od skeneru)
c = EMPTY_PAGE_CROP
test_img = test_img.crop((c, c, full_width-c, full_height-c))
# konverze na černobílý obrázek
# test_img = test_img.convert('L').point(lambda x: 255 if x > EMPTY_PAGE_BW_THRESHOLD else 0, mode='1')
# eroze "smetí"
for _ in range(EMPTY_PAGE_ERODE_COUNT):
test_img = test_img.filter(ImageFilter.MaxFilter(EMPTY_PAGE_ERODE_SIZE))
# debug: uložení si zpracovaného obrázku
test_img.save(f'{args.out_prefix}-{page_nr:04d}-test-blank.png')
entropy = test_img.entropy()
if entropy < EMPTY_PAGE_ENTROPY_THRESHOLD:
empty = True
res.pages.append(ScanJobPage(code=qr, empty=empty))
full_img.save(f'{args.out_prefix}-{page_nr:04d}-full.png')
small_img = full_img.resize((full_width // 4, full_height // 4))
small_img.save(f'{args.out_prefix}-{page_nr:04d}-small.png')
logger.debug(f'Scan: Strana #{page_nr}: {qr}')
logger.debug(f'Scan: Strana #{page_nr}: {qr} (entropy: {entropy:.10f}, empty: {empty})')
return res
Loading