Eine Geschichte über die Bildverarbeitung nur durch Matrixberechnung, ohne sich auf die Bildverarbeitungsbibliothek zu verlassen. Auch mit Pythonista möglich
Zwischenausgaben Zeichnung ・ Graustufen ・ [Faltungsfilterung](http: // qiita.com/secang0/items/f3a3ff629988dc660d87) ・ Affin-Konvertierung
Anstatt mich auf Open CV oder Pillow zu verlassen, werde ich tatsächlich verschiedene Bildverarbeitungen mit numpy und matplotlib schreiben. Diese Kombination kann auch mit der iOS-App Pythonista verwendet werden.
Verwenden Sie zusätzlich zu den Standardbibliotheken numpy und matplotlib. Ich benutze keine Pandas oder Scipy. Diese Kombination scheint eine Grammatik zu sein, die für Matlab-Benutzer einfach zu verwenden ist.
Python 3 unter Windows 10.5.2|Anaconda 4.2.0 numpy 1.12.1|matplotlib 2.0.0 Numpy 1.8.0 | matplotlib 1.4.0 in Pythonista3 Ich habe die Operation mit bestätigt.
import numpy as np
import matplotlib.pyplot as plt
Es setzt Kenntnisse in Python 3 und Kenntnisse in Numpy und Matplotlib voraus. (Der Rest ist mit Numpy verbunden, z. B. Kenntnis der Matrizen)
Verwenden Sie matplotlib.pyplot, um Bilder zu laden, anzuzeigen und zu speichern. Außerdem wird das gelesene Bild in numpy.ndarray gespeichert. Diesmal lesen und schreiben wir labyrinth.jpeg im selben Verzeichnis.
#Bilder laden
#Dreidimensionales np in img.Das Array von Array wird gespeichert.
img = plt.imread('labyrinth.jpeg')
type(img) #=> numpy.ndarray
img.size #=> (1367, 1345, 3)
#Bildschirm
plt.imshow(img)
plt.show() #Wenn das verwendete Bild klein ist, sieht es verschwommen aus, aber machen Sie sich jetzt keine Sorgen
#Bild speichern
plt.imsave('labyrinth-1.jpeg', img) #Erweiterung.Selbst wenn Sie es in png ändern, wird es ordnungsgemäß gespeichert.
Bitte beachten Sie, dass die horizontale Skala zum Zeitpunkt der Lagerung nicht verfügbar ist.
Es ist keine Übertreibung zu sagen, dass wir jetzt über Eingabe-, Ausgabe- und Debugging-Mittel verfügen.
Einige Benutzer möchten möglicherweise ein Bild erstellen, indem Sie die Pixel selbst angeben. In einem solchen Fall können Sie die Pixel mit einem 2D- oder 3D-np.array angeben, aber hier ist ein kleiner Trick, deshalb werde ich ihn vorstellen.
img_gray = np.array([
[0,63,127],
[63,127,0],
[255,0,127]
], dtype = np.uint8)
#Bildschirm
plt.imshow(img_gray, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none')
plt.show()
Zunächst ein Schwarzweißbild. Es gibt ungefähr vier Orte, die ich nicht verstehe.
dtype = np.uint8
cmap = 'gray'
vmin = 0, vmax = 255
interpolation = 'none'
Ist.
Lassen Sie uns jeden erklären. (1 und 3 werden zusammen erklärt)
dtype = np.uint8, vmin = 0, vmax = 255 Wenn Sie einen Farbwähler verwendet haben, werden Sie feststellen, dass Farben häufig zwischen 0 und 255 dargestellt werden. Dieser Trick ist jedoch erforderlich, um dies plt zu vermitteln.
Die dtype-Spezifikation ist diesmal eigentlich nicht erforderlich. Dies ist eher eine nützliche Bezeichnung für Farbe, aber es scheint sich zu lohnen. Für Schwarzweißbilder müssen vmin und vmax angegeben werden. Wenn dies weggelassen wird, wird es ohne Erlaubnis von imshow () normalisiert.
cmap = 'gray' Angesichts der Tatsache, dass cmap für Farbkarte steht und Grau Grau bedeutet, ist dies ziemlich vorhersehbar. Mit anderen Worten, es ist eine Spezifikation, eindimensionale Daten als schwarz-grau-weiß zu interpretieren. Wenn Sie dies versuchen und in in this ändern, ändert sich die Interpretation und auch die Farbe. (Die Verwendung von YlOrBr_r ist beispielsweise wie Sepia.) Erstellen Sie Ihre eigene cmap Es ist auch möglich.
interpolation = 'none' Dadurch wird der Filter entfernt, der selbst angewendet wird. (Eher Anti-Aliasing) Ich weiß nicht, warum es von Anfang an angewendet wird, aber es ist zumindest ärgerlich, sicherzustellen, dass jedes Pixel die gewünschte Farbe hat, also werde ich es entfernen. Vielleicht hängt das von der Version ab.
img_rgb = np.array([
[[255,0,0],[0,255,0],[0,0,255]],
[[255,255,0],[0,255,255],[255,0,255]],
[[0,0,0],[127,127,127],[255,255,255]],
], dtype = np.uint8)
#Bildschirm
plt.imshow(img_rgb, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none')
# => plt.imshow(img_rgb, interpolation = 'none')Gleich wie
plt.show()
Der Code ist fast der gleiche wie zuvor. (Auch wenn Sie cmap, vmax, vmin angeben, wird dies ignoriert.)
img_rgba = np.array([
[[255,0,0,0],[0,255,0,0],[0,0,255,0]],
[[255,0,0,127],[0,255,0,127],[0,0,255,127]],
[[255,0,0,255],[0,255,0,255],[0,0,255,255]],
], dtype = np.uint8)
#Bildschirm
plt.imshow(img_rgba, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none')
# => plt.imshow(img_rgba, interpolation = 'none')Gleich wie
plt.show()
Ebenso ist der Code fast der gleiche wie zuvor.
Zur Erinnerung: A in RGBA ist ein Alpha-A, das Transparenz darstellt. Es ist schwer zu sagen, ob dies transparent ist, selbst wenn Sie das Bild oben betrachten, aber wenn Sie Gimp usw. betrachten, können Sie sehen, dass es transparent ist.
(Bild überlagert das Schachbrettmuster)
Erstellen Sie vorerst eine Funktion, die diese zusammenfasst.
def img_show(img : np.ndarray, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none') -> None:
'''np.Zeigen Sie ein Bild mit Array als Argument an.'''
#Setzen Sie dtype auf uint8
#Überlauf- und Unterlaufbehandlung
img = np.clip(img,vmin,vmax).astype(np.uint8)
#Bild anzeigen
plt.imshow(img, cmap = cmap, vmin = vmin, vmax = vmax, interpolation = interpolation)
plt.show()
plt.close()
Jetzt können Sie Ihr eigenes Punktbild erstellen.
Die hier behandelte Erweiterung ist ein ganzzahliges Vielfaches und eine Erweiterung ohne Interpolation. Verwenden Sie wiederholen.
#5 in vertikaler Richtung und 3 mal in horizontaler Richtung
#Bilder laden
img = plt.imread('labyrinth.jpeg')
#Bild vergrößern
img_expand = img.repeat(5, axis = 0).repeat(3, axis = 1)
img_show(img_expand)
Auf den ersten Blick schrumpft es in horizontaler Richtung, aber wenn Sie sich die Skala ansehen, wird es vergrößert. (Sie können mit img_expand.size überprüfen)
Dies ist eine Erweiterung, die nur selten verwendet wird. Die tatsächlich verwendete Erweiterung wird später beschrieben. (Pläne)
Versuchen Sie, dieselben Bilder horizontal oder vertikal anzuordnen. Verketten ist bequem.
img = plt.imread('labyrinth.jpeg')
img_verticle = np.concatenate((img, img), axis = 0) #Vertikal
img_horizontal = np.concatenate((img,)*3, axis = 1) #Seite
#Bildschirm
img_show(img_verticle)
img_show(img_horizontal)
Im horizontalen Bild wird die Anzahl der Wiederholungen durch Multiplizieren des Tapples angegeben.
Das Trimmen kann einfach durch Indexoperation erfolgen.
img = plt.imread('labyrinth.jpeg')
#1000 vertikal:1500, 0 daneben:500 ausschneiden
img_show(img[1000:1500,0:500])
def decomposition(img : np.ndarray, channel : list = [1.,1.,1.]) -> np.ndarray:
'''Betonen Sie für jeden Kanal die Intensität, die dem Kanal zugewiesen wurde'''
float_img = img * channel
return np.array(float_img,dtype = np.uint8)
img = plt.imread('labyrinth.jpeg')
img_show(decomposition(img, [1.,0.,0.]), cmap = 'Reds')
img_show(decomposition(img, [0.,1.,0.]), cmap = 'Greens')
img_show(decomposition(img, [0.,0.,1.]), cmap = 'Blues')
Der obige Code definiert eine Funktion namens Zerlegung (Kanalzerlegung scheint auf Englisch als Farbzerlegung bezeichnet zu werden). Dies funktioniert im Grunde genommen als "img * [0,0,1]", aber da der Typ etwas kompliziert ist, habe ich eine Funktion definiert.
Ich habe es für alle Fälle mit Gimp überprüft, aber es sah genauso aus.
Das Konvertieren eines Pixels mit einem dreidimensionalen Wert von RGB in ein Pixel mit nur einem eindimensionalen Wert von Y wird als Grauskalierung bezeichnet. Kurz gesagt, es ist eine Methode zum Erstellen eines Schwarzweißbildes. Es gibt verschiedene Graustufenmethoden, aber hier beschäftigen wir uns nur mit der Zwischenwertmethode und der G-Kanal-Methode.
Die Zwischenwertmethode verwendet den Durchschnitt aus dem Maximalwert in RGB und dem Minimalwert in RGB als Y. Mit anderen Worten wird eine Berechnung wie "(max (R, G, B) + min (R, G, B)) / 2" durchgeführt.
img = plt.imread('labyrinth.jpeg')
img_mid_v = np.max(img, axis = 2)/2 +np.min(img, axis = 2)/2
img_show(img_mid_v)
Hier ein Punkt. Über die Berechnungsformel von img_mid_v Sie fragen sich vielleicht, ob "img_mid_v = (np.max (img, Achse = 2) + np.min (img, Achse = 2)) / 2" nicht gut ist. Die Antwort ist nein." Der Grund dafür ist, dass uint8 überläuft, wenn Sie zuerst die Maximal- und Minimalwerte hinzufügen. Nachdem der Typ float geworden ist, kehrt er mit img_show zu uint8 zurück.
Übrigens ändert sich "np.max (img, Achse = 2) // 2 + np.min (img, Achse = 2) // 2" nicht viel, aber die Minimal- und Maximalwerte werden abgeschnitten. Ich möchte vorsichtig sein.
Es scheint, dass Menschen G unter RGB am stärksten erkennen. Die G-Kanal-Methode hat dies berücksichtigt. Bei der G-Kanal-Methode wird der Wert von G als der Wert von Y angesehen. Kurz gesagt, es ist eine sehr grobe Methode, aber sie ist so effektiv, dass Menschen seltsam sind. (Es ist noch seltsamer, dass sich in R und G auf der Netzhaut so viele Pyramidenzellen befinden sollten)
Der Code ist einfach. ... heißt Ellipse Dies ist ein praktisches Symbol.
img = plt.imread('labyrinth.jpeg')
img_g_channel = img[...,1]
img_show(img_g_channel)
Die Idee ist dieselbe wie bei der vorherigen RGB-Zerlegung. Es ist jedoch bedauerlich, dass es nicht lange dauern wird, bis diese einfache Methode angewendet wird.
Andere Methoden werden in Zukunft behandelt.
Nachdem wir nun ein Schwarzweißbild haben, versuchen wir es mit der Binärisierung, wobei der Wert von Y "1 für Pixel über dem Schwellenwert und 0 für Pixel unter dem Schwellenwert" ist. Verwenden Sie für Schwarzweißbilder das mit der G-Kanal-Methode erstellte.
img = plt.imread('labyrinth.jpeg')
img_g_channel = img[...,1]
#Schwellenwert einstellen
threshold = 75
img_binary = img_g_channel >= threshold
img_binary = np.uint8(img_binary * 255)
img_show(img_binary)
Irgendwie habe ich das Gefühl, dass das Labyrinth auftaucht.
Am Ende der Grundlagen werde ich vorstellen, wie man einen Filter durch Falten macht. Räumliche Filterung ist für den Filter durch Faltung leicht zu verstehen.
Der diesmal verwendete Filter verwendet die folgenden zwei Matrixfaltungen.
\frac{1}{256}\left(
\begin{matrix}
21 & 31 & 21 \\
31 & 48 & 31 \\
21 & 31 & 21
\end{matrix}
\right)
Dies ist ein Unschärfefilter, der oft als Gaußsche Unschärfe bezeichnet wird. Dies ist ein Filter, der häufig zur Rauschunterdrückung vor der Konturextraktion verwendet wird.
\left(
\begin{matrix}
0 & -1 & 0 \\
-1 & 4 & -1 \\
0 & -1 & 0
\end{matrix}
\right)
Dies ist ein Laplace-Filter und wird häufig zur Konturextraktion verwendet. Kann eine Person, die den Ausdruck, dass die Idee mit der bipolaren Zelle in der Mitte identisch ist, leicht verstehen kann, diesen Punkt erreicht haben?
Erstellen Sie zunächst eine Funktion zum Falten eines zweidimensionalen Arrays (Sie müssen es nicht selbst mit scipy oder PIL erstellen, aber leider müssen Sie es selbst unter den Bindungsbedingungen von Numpy und matplotlib erstellen.
def convolve2d(img, kernel):
#Berechnen Sie die Größe der Submatrix
sub_shape = tuple(np.subtract(img.shape, kernel.shape) + 1)
#Da der Funktionsname lang ist, wird er einmal weggelassen
strd = np.lib.stride_tricks.as_strided
#Erstellen Sie eine Submatrix-Matrix
submatrices = strd(img,kernel.shape + sub_shape,img.strides * 2)
#Berechnen Sie die Einstein-Summe aus Submatrix und Kernel
convolved_matrix = np.einsum('ij,ijkl->kl', kernel, submatrices)
return convolved_matrix
Der obige Code wird unter Verwendung der Matrix der Submatrix von img gefaltet. Weitere Informationen finden Sie unter stackoverflow-Lehrer.
#Erstellen eines Filterkerns
gaussian = np.array([[21,31,21],
[31, 48,31],
[21,31,21]])/256
laplacian = np.array([[ 0,-1, 0],
[-1, 4,-1],
[ 0,-1, 0]])
#Bilder laden
img = plt.imread('labyrinth.jpeg')
img = img[...,1] #Dieses Mal wird nur der G-Kanal als Ziel ausgewählt.
#Wenden Sie die Gaußsche Unschärfe 20 Mal an
for _ in range(20):
img = convolve2d(img, gaussian)
An diesem Punkt mag es wie eine abgeschnittene Änderung erscheinen, aber wenn Sie es in bmp speichern und vergrößern, werden Sie feststellen, dass es überraschend anders ist.
#Wenden Sie den Laplace-Filter an
img = convolve2d(img, laplacian)
plt.imshow(b,cmap = 'gray_r', vmax = img.max()*0.5)
#Der Maximalwert beträgt nicht immer 255.
#Auch wenn auf den Maximalwert eingestellt, wurden andere Werte zerkleinert, so*0.Korrigiert um 5.
plt.show()
plt.close()
Es fehlt ein wenig an Wirkung, also lassen Sie uns die Grundlagen zusammenfassen.
img = np.array([
[[ 0, 0, 0],[ 0, 63,127],[255, 0, 0]],
[[ 63, 63, 63],[ 0, 0,255],[ 0, 0, 0]],
[[255,255,255],[ 0, 0, 0],[ 63,127, 0]]
], dtype = np.uint8)
img = img.repeat(100,axis = 1).repeat(100,axis = 0)#Erweiterung
img = np.concatenate((img,)*2, axis = 1) #Horizontal kopieren
img = np.concatenate((img,)*2, axis = 0) #Vertikal kopieren
print('RGB-Bild')
img_show(img)
#Generieren Sie ein Schwarzweißbild mit der Zwischenwertmethode
img = np.array(np.max(img, axis = 2)/2 +np.min(img, axis = 2)/2, dtype = np.uint8)
print('Schwarzweiss-Bild')
img_show(img)
#Gaußsche Unschärfe
img = convolve2d(img, gaussian)
#Konturextraktion
img = convolve2d(img, laplacian)
print('Konturextraktion')
plt.imshow(img,cmap = 'gray_r', vmax = img.max())
plt.show()
plt.close()
RGB-Bild Schwarzweiss-Bild Konturextraktion
In der Basisausgabe haben wir auch die G-Kanal-Methode und die Binarisierung gesehen.
** * Wir werden es nach und nach hinzufügen. Wenn Sie interessiert sind, halten Sie es bitte auf Lager. ** ** ** Es ist schon zu lang, also habe ich es nur skizziert und aufgelistet. Für weitere Informationen folgen Sie bitte dem Link. Außerdem ändern sich die verwendeten Bilder gegenüber der Zwischenausgabe. Warum habe ich ein Bild ohne Rot verwendet ...
Um eine Figur zu zeichnen, verwenden Sie msgid, um die Koordinaten auf dem Bild zu erhalten.
x, y = np.mgrid[:100,:100]
Beachten Sie, dass die positive Richtung von $ x $ nach unten und die positive Richtung von $ y $ richtig ist.
** Für diejenigen, die mehr erfahren möchten **
Die Grauskalierung ist eine Methode zur Berechnung des Schwarz-Weiß-Werts Y aus den jedem Pixel zugewiesenen RGB-Werten. Hier Verschiedene Graustufenmethoden, die in [Basic] nicht behandelt wurden (http://qiita.com/secang0/items/1229212a37d8c9922901) ) Probiere auch. Eine ausführliche Erklärung finden Sie unter dem Link. Sie werden in derselben Reihenfolge behandelt.
** Für diejenigen, die mehr erfahren möchten **
Behandelt Tiefpassfilter, Hochpassfilter und Differenzfilter.
** Für diejenigen, die mehr erfahren möchten **
Es gibt viele Möglichkeiten, ein Bild zu verzerren. Die Affintransformation ist eine Transformation, die lineare Transformation (Vergrößerung / Verkleinerung / Drehung / Scherung) und parallele Bewegung kombiniert. ** Für diejenigen, die mehr erfahren möchten **
Recommended Posts