Segmentace obrazu - text a jeho čtení

Cvičení je zaměřené na správné využití osvětlení při nasvícení objektu a následné využití metod pro segmentaci obrazu. Segmentovaný snímek je převeden na text pomocí OCR (optical character recognition).

No description has been provided for this image

Ke čtení je využita knihovna Tesseract OCR.

Import knihoven a konfigurace

%run ./library.ipynb

Pomocné funkce

Z následujících funkcí je potřeba vybírat ty vhodné pro splnění úkolu. Parametry a implementaci funkcí si můžete zobrazit pomocí příkazu help(function_name) nebo na https://gitlab.fit.cvut.cz/bi-svz/improutils_package/tree/master/improutils.

Seznam funkcí pro přehlednost:


Úkoly

  1. Změřte velikost placky s nápisem FIT v pixelech - výška, šířka.

  2. Zvolte vhodné funkce pro segmentaci obrazu a přečtěte text z obrázku snímaném kamerou. Po vyladění algoritmu, využijte předzpracovaný obrázek a nechte ho přečíst OCR. V případě, že výsledek bude po porovnání True, úkol jste splnili.

Pro každý z úkolů je nutné zvolit vhodný typ osvětlení a následně placku nasnímat monochromatickou kamerou. Na každý úkol bude v ideálním případě potřeba jiný snímek. Volba vhodného nasvícení usnadní algoritmickou část úkolu. Při špatné volbě osvětlení nebude úkol uznán!

Pro volbu vhodné iluminační techniky a vhodného osvětlení můžete konzultovat přehledový dokument Volba vhodného osvětlení v kombinaci s kamerou, nebo přednášku Kamerový systém a zpracování obrazu.

1) Nasnímejte placky s nápisem FIT a zobrazte.

Snímky uložte do jedné složky. Použijte vhodné osvětlení!

POZOR: Přestože pracujeme s monochromatickou kamerou, nemusí mít snímky z kamery jeden kanál ve stupních šedi, jak bychom očekávali. Typicky může mít snímek 3 kanály (RGB). Závisí to na nastavení parametru PIXEL_FORMAT kamery. Před prací se snímky si ověřte, že pracujete se správným typem snímku. Snímky si můžete do vhodného formátu převést/nastavit vhodně parametr PIXEL_FORMAT kamery.

path = "data2/" ### nezapomeňte cestu zakončit '/'
files = os.listdir(path)

images = []

for f in files:
    image = load_image(path + f) ### načtěte obrázek
    images.append(image)
        
print('Celkem nalezených obrázků: ' + str(len(images)))
plot_images(*images) #zobrazte snímky
Celkem nalezených obrázků: 1
No description has been provided for this image

2) Změřte rozměry placky v pixelech

Úkolem je ze snímku segmentovat placku a změřit její rozměry - výška, šířka v pixelech.

Rozměry jsou vykresleny do původního snímku viz. obrázek. Pro pozicování textu a obrysu placky využijte znalost kontury, ze které byly hodnoty vypočítány. Pokud jsou vaše rozměry zobrazeny na opačné straně oproti referenčnímu obrázku, je to také správně.

No description has been provided for this image
def measurement_algorithm(img):
    
    ### algoritmus segmentace a měření placky
    
    sizes_drawn = img.copy()
    
    mask = segmentation_two_thresholds(to_gray(images[0]), 183, 255)
    contour_drawn, contours_count, contours = find_contours(mask, min_area=1000, external=False)
    
    rect = cv2.minAreaRect( contours[0] ) ### doplňte správně vstup
    height, width = rect[ 1 ] ### vyberte index, obsahující informaci o výšce a šířce 
    points = cv2.boxPoints( rect ) 
    points = np.int0(points) ### přetypujte na správný datový typ pro vykreslení

    cv2.line(sizes_drawn, points[0], points[1], color=(255, 0, 0), thickness=15)
    cv2.putText(sizes_drawn, "{:.2f} px".format(width), points[0], 0, 1.5, (0, 0, 255), 2)
    
    cv2.line(sizes_drawn, points[1], points[2], color=(255, 0, 0), thickness=15)
    cv2.putText(sizes_drawn, "{:.2f} px".format(height), points[2], 0, 1.5, (0, 0, 255), 2)

    return mask, sizes_drawn
img_measures = images[0]  ### doplňte index
mask, sizes_drawn = measurement_algorithm(img_measures)
plot_images(mask, sizes_drawn)
No description has been provided for this image

3) Doplňte algoritmus pro segmentaci textu z nasnímaných placek.

Výstupem algoritmu by měl být binární obraz, kde pozadí má černou barvu a objekty (popředí) bílou. Binární obrázek zobrazte.

HINT: Může (ale nemusí) se vám hodit funkce find_holes(...) pro segmentaci textu (funkce není součástí Improutils).

img = load_image("data3/0.jpg")
img = to_gray(img)
img = crop(img, 900, 600, 1650, 1100)
plot_images(img)
No description has been provided for this image
@interact(value=create_slider(min=0, max=255, description='Value'))
def _(value):
    mask = segmentation_two_thresholds(img, value[0], value[1]) ###
#     mask = segmentation_auto_threshold(img)
    plot_images(mask, img, titles=['Segmentation', 'Original'])
interactive(children=(IntRangeSlider(value=(0, 255), continuous_update=False, description='Value\xa0\xa0\xa0\x…
def segmentation_algorithm(img):
    ### algoritmus segmentace textu 
#     img = crop(...)
    
    mask = segmentation_two_thresholds(img, 166, 255)
    mask = fill_holes(mask)
    kernel = np.ones((30,30),np.uint8)

    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
    return mask
img_text = img ### doplňte index
img_bin = segmentation_algorithm(img_text)

plot_images(img_bin)
No description has been provided for this image

4) Využijte funkční algoritmus na snímky.

POZOR: Dokud nebude vstupní obraz vypadat následovně, NEPOUŠTĚJTE se do další části.

No description has been provided for this image

5) Využijte OCR na výsledný binární obrázek a zkontrolujte správnost.

HINT: Pokud se požadovaný výstup OCR neshoduje s referenčním textem, zařiďte aby nebyl text na obrázku nijak rotován a kolem textu byl alespoň 20px rámeček. Důvodem je použití Tesseract OCR, jenž je na dané věci velice náchylný.

text = ocr(img_bin) ###
ref_text = 'FIT'

print('Přečtený text je: ' + "'" + text.strip() + "'\n")
if text.strip() == ref_text:
    print('-> Úkol jste splnili!\n')
else:
    print('-> Úkol je třeba dál ladit ...')    
print('')
Přečtený text je: 'FIT'

-> Úkol jste splnili!


6) Bonusová část - změřte rozměry kostičky v milimetrech

Změřte a zobrazte rozměry placky v milimetrech, když víte že výška písmena I je 18 mm.

img = load_image("data3/0.jpg")
img = to_gray(img)
img = crop(img, 600, 400, 1850, 1350)
plot_images(img)
No description has been provided for this image
@interact(value=create_slider(min=0, max=255, description='Value'))
def _(value):
    mask = segmentation_two_thresholds(img, value[0], value[1]) ###
    plot_images(mask, img, titles=['Segmentation', 'Original'])
    
interactive(children=(IntRangeSlider(value=(0, 255), continuous_update=False, description='Value\xa0\xa0\xa0\x…
def measurement_algorithm(img):
    
    ### algoritmus segmentace a měření placky
    
    sizes_drawn = img.copy()
    
    mask = segmentation_two_thresholds(to_gray(img), 0, 247)
    contour_drawn, contours_count, contours = find_contours(mask, min_area=1000, external=False)
    
    rect = cv2.minAreaRect( contours[0] ) ### doplňte správně vstup
    height, width = rect[ 1 ] ### vyberte index, obsahující informaci o výšce a šířce 
    points = cv2.boxPoints( rect ) 
    points = np.int0(points) ### přetypujte na správný datový typ pro vykreslení

    cv2.line(sizes_drawn, points[0], points[1], color=(255, 0, 0), thickness=15)
    cv2.putText(sizes_drawn, "{:.2f} px".format(width), points[0], 0, 1.5, (0, 0, 255), 2)
    
    cv2.line(sizes_drawn, points[1], points[2], color=(255, 0, 0), thickness=15)
    cv2.putText(sizes_drawn, "{:.2f} px".format(height), points[2], 0, 1.5, (0, 0, 255), 2)

    return mask, sizes_drawn, width, height
img_measures = img  ### doplňte index
mask, sizes_drawn, width, height = measurement_algorithm(img_measures)
plot_images(mask, sizes_drawn)
No description has been provided for this image
contour_drawn, contours_count, contours = find_contours(img_bin, 50, 20000, external=False)

rect = cv2.minAreaRect( contours[0] ) ### doplňte správně vstup
heighti, widthi = rect[ 1 ]
ratio = 18 / (heighti)
print(heighti, height)
print(height/ratio, width/ratio)
plot_images(contour_drawn)
46.59762191772461 809.3329467773438
2095.1661477493662 2115.618969511512
No description has been provided for this image