Python OpenCV/scikit-image

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Felix92
User
Beiträge: 124
Registriert: Mittwoch 7. November 2018, 17:57

Donnerstag 15. April 2021, 13:38

Huhu,
und zwar habe ich gerade folgendes Problem, um Informationen aus Rezepten zuverlässiger zu extrahieren müsste ich bestmöglich den kompletten Hintergrund entfernen, damit nur noch die gedruckte (schwarz/graue) Schrift über bleibt.
Das funktioniert mit dem aktuellen Code auch gut wenn die Schrift wirklich schwarz gedruckt ist, allerdings ist das eher selten der Fall meistens ist der Druck blass und hellgrau.
Somit wird dementsprechend auch die Schrift teilweise entfernt bzw. gebrochen (was mit erode und dilate auch nicht zu beheben ist).
Ein Originalbild kann ich aus Datenschutzgründen leider nicht zeigen, allerdings kann man sich den Anwendungsfall denke ganz gut vorstellen :)

Gibt es eine simple Möglichkeit den Hintergrund zu entfernen bzw. alle Pixel welche einen höheren Rotanteil als x besitzen "einfach" auf weiß 255 zu setzen ?
Oder vlt. eine ganz andere Idee / Ansatz ?

Eine weitere Idee war es einen Autoencoder dafür zu verwenden/trainieren (allerdings wäre das der letzte Schritt/Versuch) bevorzugt sind CV Lösungen.

Ein weiterer erfolgloser Versuch war: cv2.absdiff(reales_img, diese_blanko_vorlage)

Bild

bisheriger Code:

Code: Alles auswählen

img = resize_and_rotate_image(path, res_height=900, res_width=1200)
value = check_signed(img)
result_dict['recipe']['isSigned']['value'] = value
if value:
      print('have detect signature in prescription')
else: print('no signature found')

img = cv2.GaussianBlur(img,(3,3),2)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
morph_open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

thresh = cv2.threshold(morph_open,210,255,cv2.THRESH_BINARY)[1]   

mask = cv2.inRange(thresh, 0, 120)
        
kernel = np.array([[-1,-1,-1],
                                [-1, 9,-1],
                                [-1,-1,-1]])
sharpened = cv2.filter2D(mask, -1, kernel)
        

morph_close = cv2.morphologyEx(sharpened, cv2.MORPH_CLOSE, kernel)
img = cv2.bitwise_not(morph_close)
Anhang:
Zur Verdeutlichung 2 schlechte Ausschnitte und 1 gutes:
Bild
Bild

Bild

Danke euch :)
LG Felix
__deets__
User
Beiträge: 9823
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 15. April 2021, 13:54

Direktes subtrahieren funktioniert eigentlich nie. Ein Weg könnte der Wandel in HSV sein, und dann ein ausfiltern aller Pixel mit rotanteil. Wichtig: dabei auch auf ausreichend S und V achten, weil in weiß oder schwarz auch rote Pixel dominant sein können.
Benutzeravatar
Felix92
User
Beiträge: 124
Registriert: Mittwoch 7. November 2018, 17:57

Donnerstag 15. April 2021, 15:24

Huhu __deets__, danke für deine Antwort.
Habe ich gerade mal ausprobiert das Ergebnis sieht leider nicht viel besser aus als bisher.
Vlt. noch weitere Ideen ?
__deets__
User
Beiträge: 9823
Registriert: Mittwoch 14. Oktober 2015, 14:29

Freitag 16. April 2021, 08:48

@Felixi92: verzeih, meine Antwort von gestern war falsch - ich hatte dich mit jemand anderem, der auch eine CV frage hatte, verwechselt. Habe die Antwort also gelöscht.

Hast du Code & Ergebnisbilder?
Benutzeravatar
Felix92
User
Beiträge: 124
Registriert: Mittwoch 7. November 2018, 17:57

Montag 19. April 2021, 15:27

@__deets__:
zum testen habe ich Folgendes verwendet:

Code: Alles auswählen

import cv2
import sys
import numpy as np

def nothing(x):
    pass

# Load in image
image = cv2.imread('/home/felix/Desktop/Rezepte/Rezepte-03.jpg')

# Create a window
cv2.namedWindow('image')

# create trackbars for color change
cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
cv2.createTrackbar('SMin','image',0,255,nothing)
cv2.createTrackbar('VMin','image',0,255,nothing)
cv2.createTrackbar('HMax','image',0,179,nothing)
cv2.createTrackbar('SMax','image',0,255,nothing)
cv2.createTrackbar('VMax','image',0,255,nothing)

# Set default value for MAX HSV trackbars.
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize to check if HSV min/max value changes
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

output = image
wait_time = 33

while(1):

    # get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin','image')
    sMin = cv2.getTrackbarPos('SMin','image')
    vMin = cv2.getTrackbarPos('VMin','image')

    hMax = cv2.getTrackbarPos('HMax','image')
    sMax = cv2.getTrackbarPos('SMax','image')
    vMax = cv2.getTrackbarPos('VMax','image')

    # Set minimum and max HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Create HSV Image and threshold into a range.
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    output = cv2.bitwise_and(image,image, mask= mask)

    # Print if there is a change in HSV value
    if( (phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display output image
    cv2.imshow('image',output)

    # Wait longer to prevent freeze for videos.
    if cv2.waitKey(wait_time) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
Das größte Problem ist, dass manche Rezepte so "schwach" gedruckt sind, dass es vermutlich keine optimale Lösung mit CV gibt, zumindest nicht in einem automatisierten Ablauf.
Einen guten Mittelwert habe ich denke gefunden (so das ~90% der Fälle abgedeckt sind), der Rest wird halt vor dem weiteren Prozess rausgefiltert.
Vlt. hast du ja trotzdem noch eine andere Idee :)

Hier nochmal 2 Beispiele (Ausgangsformat):

Bild

Bild

Die Qualität der anderen Drucke liegt inetwa zwischen diesen beiden Beispielen (mal die Schriftart, Position, etc. außen vorgelassen)

Ansonsten hat sich am Code zum Preprocessing nicht viel geändert, bis auf:

Code: Alles auswählen

img[np.where((img <= [110,110,110]).all(axis=2))] = [0,0,0] 

vorm Blur
und das ich

Code: Alles auswählen

#morph_close = cv2.morphologyEx(sharpened, cv2.MORPH_CLOSE, kernel)
am Ende entfernt habe, da dadurch die ROI wo die Medikamente stehen unbrauchbar bzw. wesentlich schlechter lesbar wurden.

LG Felix
Antworten