Was bedeuten diese Zeilen?

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
JanaSophie
User
Beiträge: 14
Registriert: Dienstag 7. Januar 2020, 17:08

Liebe alle hier,

Nachdem ich nun openCV installiert habe, arbeite ich daran, ein Beispiel mit Film/Bildbearbeitung durchzuarbeiten, was mit gut passt, siehe hier:

https://medium.com/@janhettenkofer/find ... 5b564db044

Da geht es darum, dass ein Bild eingelesen und der hellste / durchschnittliche Punkt (Farbe) errechnet wird

base = cv2.imread(args.base, cv2.IMREAD_UNCHANGED)
base = np.float32(base) / np.iinfo(base.dtype).max
base = cv2.mean(base)

Die erste Zeile verstehe ich, da wird das Bild geladen und das Ergebnis "base" müsste vom Typ "Mat"? sein (ich hab bei "imread in der doku gelesen, weil man ja immer auf den Typ achten soll :-) )

Aber was ist das Ergebnis von np-float32(base) in der nächsten Zeile? Also eine Variable vom Typ "Mat" (wie sieht das aus) wird umgewandelt in eine Zahl??
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

`imread` liefert üblicherweise Daten vom Typ byte, also ganze Zahlen zwischen 0 und 255. `float32` wandelt dann das Array in ein Array mit dem Datentyp 32bit Fließkommazahl um, die dann durch die größte Zahl geteilt wird, die ein byte annehmen kann; letztlich hast Du also ein Array mit Zahlen von 0.0 bis 1.0.
JanaSophie
User
Beiträge: 14
Registriert: Dienstag 7. Januar 2020, 17:08

Also ich hab hier nachgelesen: https://docs.opencv.org/3.4/d4/da8/grou ... odecs.html
Gibt es eine andere Stelle, wo ich für Python besser nachlesen kann? Wie soll man denn von "Mat" auf ein Byte-array kommen??

Aber gut, also "base = np.float32(base)" Macht aus einem Array mit lauter Bytes ein gleich großes Array mit lauter Gleitkommazahlen, richtig?

Was liefert dann "np.iinfo(base.dtype).max" Eine Zahl? Und wie kann ich ein Array durch eine Zahl teilen und es kommt 0..1 raus? Seltsam, also Python soll doch so einfach lesbar sein . aber das kann ich so noch nicht unterschreiben (ich kenne nur Java sonst)
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Theoretisch kann der Rückgabewert von imread irgendeinen Zahlentyp haben, meist sind das aber Bytes. Und eine Matrix mit einem Skalar zu multiplizieren ist in der Mathematik definiert und ist bei NumPy auch nicht anders. Wenn man also einen mathematischen Hintergrund hat, dann ist das sehr gut lesbar.
Benutzeravatar
__blackjack__
User
Beiträge: 14051
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@JanaSophie: `Mat` ist ein C++-Datentyp von OpenCV — auf Python-Seite kommt das als Numpy-Array an. Welche Dimansionen das Array hat und welchen Typ die Elemente des Arrays haben, kann man nicht so genau sagen weil beim Lesen angegeben wurde, dass die Daten unverändert geladen werden sollen.

Neben der OpenCV-Dokumentation muss man sich also auch mit Numpy beschäftigen, also beispielsweise mal das Tutorial in dessen Dokumentation durcharbeiten. Wie dort Slicing und Rechenoperationen mit Arrays definiert sind, macht den ganzen Charme dieser Arrays aus.

Das man die skalaren Numpy-Datentypen zum Umwandeln eines Arrays verwenden kann war mir übrigens auch neu. Ich hätte dafür die `astype()`-Methode verwendet: ``base = base.astype(np.float32) / np.iinfo(base.dtype).max``

Was an dem Code aus dem Blogbeitrag dann etwas doof ist, ist das der den Namen `base` für das Array und dann für den Mittelwert der Arraywerte verwendet. Das man Namen in Python nacheinnder verschiedene/beliebige Typen zuweisen kann ist nett und IMHO auch sinnvoll solange der ”duck type” gleich ist. Also zum Beispiel ”Array das Bild repräsentiert” ohne das man sich dabei auf einen konkreten Datentyp für die Elemente von diesen Arrays festlegen muss, aber mal ein Bild und mal einen Mittelwert im gleichen Namensraum an den gleichen Namen zu binden ist keine gute Idee.

Die interaktive Shell ist in Python ein gutes Werkzeug, sowohl zum lernen als auch zum kennenlernen und erforschen von Bibliotheken. Da kann man mit Code live experimentieren, sieht die Werte, kann die Typen abfragen, und die Hilfstexte die bei vielen Bibliotheken direkt an den Objekten hinterlegt sind. Wirf mal einen Blick auf IPython und/oder JupyterLab.

Code: Alles auswählen

In [24]: img = cv2.imread("test.jpg", cv2.IMREAD_UNCHANGED)                     

In [25]: img                                                                    
Out[25]: 
array([[[ 97, 122, 148],
        [ 97, 122, 148],
        [ 96, 121, 147],
        ...,
        [ 38,  39,  37],
        [ 38,  39,  37],
        [ 38,  39,  35]],

       [[ 96, 122, 146],
        [ 96, 121, 147],
        [ 95, 120, 146],
        ...,
        [ 38,  39,  37],
        [ 38,  39,  37],
        [ 38,  39,  35]],

       [[ 93, 119, 143],
        [ 92, 118, 142],
        [ 92, 117, 143],
        ...,
        [ 38,  39,  37],
        [ 38,  39,  37],
        [ 38,  39,  35]],

       ...,

       [[ 26,  30,  48],
        [ 26,  30,  48],
        [ 26,  30,  48],
        ...,
        [  6,  13,  30],
        [  6,  13,  30],
        [  6,  13,  30]],

       [[ 26,  30,  48],
        [ 26,  30,  48],
        [ 26,  30,  48],
        ...,
        [  5,  12,  29],
        [  5,  12,  29],
        [  5,  12,  29]],

       [[ 25,  29,  47],
        [ 25,  29,  47],
        [ 25,  29,  47],
        ...,
        [  4,  11,  28],
        [  4,  11,  28],
        [  4,  11,  28]]], dtype=uint8)

In [26]: np.float32(img)                                                        
Out[26]: 
array([[[ 97., 122., 148.],
        [ 97., 122., 148.],
        [ 96., 121., 147.],
        ...,
        [ 38.,  39.,  37.],
        [ 38.,  39.,  37.],
        [ 38.,  39.,  35.]],

       [[ 96., 122., 146.],
        [ 96., 121., 147.],
        [ 95., 120., 146.],
        ...,
        [ 38.,  39.,  37.],
        [ 38.,  39.,  37.],
        [ 38.,  39.,  35.]],

       [[ 93., 119., 143.],
        [ 92., 118., 142.],
        [ 92., 117., 143.],
        ...,
        [ 38.,  39.,  37.],
        [ 38.,  39.,  37.],
        [ 38.,  39.,  35.]],

       ...,

       [[ 26.,  30.,  48.],
        [ 26.,  30.,  48.],
        [ 26.,  30.,  48.],
        ...,
        [  6.,  13.,  30.],
        [  6.,  13.,  30.],
        [  6.,  13.,  30.]],

       [[ 26.,  30.,  48.],
        [ 26.,  30.,  48.],
        [ 26.,  30.,  48.],
        ...,
        [  5.,  12.,  29.],
        [  5.,  12.,  29.],
        [  5.,  12.,  29.]],

       [[ 25.,  29.,  47.],
        [ 25.,  29.,  47.],
        [ 25.,  29.,  47.],
        ...,
        [  4.,  11.,  28.],
        [  4.,  11.,  28.],
        [  4.,  11.,  28.]]], dtype=float32)

In [27]: img.dtype                                                              
Out[27]: dtype('uint8')

In [28]: np.iinfo(img.dtype)                                                    
Out[28]: iinfo(min=0, max=255, dtype=uint8)

In [29]: np.iinfo(img.dtype).max                                                
Out[29]: 255

In [30]: np.float32(img) / np.iinfo(img.dtype).max                              
Out[30]: 
array([[[0.38039216, 0.47843137, 0.5803922 ],
        [0.38039216, 0.47843137, 0.5803922 ],
        [0.3764706 , 0.4745098 , 0.5764706 ],
        ...,
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.13725491]],

       [[0.3764706 , 0.47843137, 0.57254905],
        [0.3764706 , 0.4745098 , 0.5764706 ],
        [0.37254903, 0.47058824, 0.57254905],
        ...,
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.13725491]],

       [[0.3647059 , 0.46666667, 0.56078434],
        [0.36078432, 0.4627451 , 0.5568628 ],
        [0.36078432, 0.45882353, 0.56078434],
        ...,
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.14509805],
        [0.14901961, 0.15294118, 0.13725491]],

       ...,

       [[0.10196079, 0.11764706, 0.1882353 ],
        [0.10196079, 0.11764706, 0.1882353 ],
        [0.10196079, 0.11764706, 0.1882353 ],
        ...,
        [0.02352941, 0.05098039, 0.11764706],
        [0.02352941, 0.05098039, 0.11764706],
        [0.02352941, 0.05098039, 0.11764706]],

       [[0.10196079, 0.11764706, 0.1882353 ],
        [0.10196079, 0.11764706, 0.1882353 ],
        [0.10196079, 0.11764706, 0.1882353 ],
        ...,
        [0.01960784, 0.04705882, 0.11372549],
        [0.01960784, 0.04705882, 0.11372549],
        [0.01960784, 0.04705882, 0.11372549]],

       [[0.09803922, 0.11372549, 0.18431373],
        [0.09803922, 0.11372549, 0.18431373],
        [0.09803922, 0.11372549, 0.18431373],
        ...,
        [0.01568628, 0.04313726, 0.10980392],
        [0.01568628, 0.04313726, 0.10980392],
        [0.01568628, 0.04313726, 0.10980392]]], dtype=float32)

In [31]: (np.float32(img) / np.iinfo(img.dtype).max).mean()                     
Out[31]: 0.25126287
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
JanaSophie
User
Beiträge: 14
Registriert: Dienstag 7. Januar 2020, 17:08

Na ich sehe schon, ich war zu ungeduldig, jetzt habe jetzt auch die Zeile verstanden, glaube ich. :-)

Diese detaillierte Ausgabe mit [in] und [out] - wie kriegt man die hin, also dass man das so sieht?

Dass man Namen (Variablen) in Python nacheinander verschiedene/beliebige Typen zuweisen kann, ist für mich total irritierend, gerade in dem Beispiel, aber ich muss das ja nicht machen.
Benutzeravatar
__blackjack__
User
Beiträge: 14051
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@JanaSophie: Das mit den In/Out ist IPython oder JupyterLab.

Die ersten beiden Zuweisungen an `base` sind IMHO okay, auch wenn das einmal ein Array mit in den meisten Fällen Bytewerten ist und dann eines mit 32-Bit-Gleitkommazahlen. Beide male repräsentiert der Wert ja das gleiche: die Pixelwerte des gelesenen Bildes.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten