In diesem Artikel werden wir die folgende Analyse unter Verwendung eines zweidimensionalen Kolloidkristallbildes durchführen.
Ich habe die folgenden kolloidalen Bilder verwendet: yum:
Autor Zephyris [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0) oder GFDL (http://www.gnu.org/copyleft/fdl.html)], [Wikimedia Von Commons (Link)
Es ist wie folgt.
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy import ndimage as ndi
from sklearn.neighbors import NearestNeighbors
Ein Maximalfilter wird verwendet, um die kolloidale Position zu erfassen. Diese Methode funktioniert ähnlich wie ImageJs Find Maxima (https://imagej.nih.gov/ij/docs/menus/process.html#find-maxima).
Laden Sie zunächst das Bild wie unten gezeigt und konvertieren Sie es in Graustufen. Holen Sie sich auch die Bildgröße.
#Bild wird geladen
img_raw = cv2.imread('ColloidCrystal_10xBrightField_GlassInWater.jpg', 1)
#Graustufen
img = cv2.cvtColor(img_raw, cv2.COLOR_BGR2GRAY)
#Bildhöhe,Breite bekommen
h, w = img.shape[:2]
Wie der Name schon sagt, ist der Maximalwertfilter ein Filter, der sich auf die maximale Helligkeit innerhalb eines bestimmten Bereichs um das interessierende Pixel bezieht. Auf diese Weise ist es möglich, den lokalen Maximalwert des Bildes zu erfassen, dh die Position der kolloidalen Partikel.
Wenden wir den Filter mit der Größe des Aufmerksamkeitsbereichs (Kernel) auf 9x9 an. (Da Geräusche durch Glätten vor dem Auftragen entfernt werden)
#Verwischen(Glätten)Geräuschentfernung durch
img = cv2.blur(img,(3,3))
#Maximalfilter anwenden
img_max = ndi.maximum_filter(img, size=9, mode='constant')
Hier ist ein Vergleich der Bilder vor und nach dem Anwenden des Filters.
In diesen beiden Bildern ist die Position, an der der Helligkeitswert gleich ist **, der lokale Maximalwert, dh die Position des Partikels. (Referenz) Dies kann leicht mit numpy.where ermittelt werden.
#Extraktion des lokalen Maximalwertes
pts_list = np.where(img == img_max)
pts_list = np.array(pts_list)
#Zeichnen Sie auf dem Originalbild
fig = plt.figure(dpi=150,facecolor='white')
plt.gray()
plt.imshow(img)
plt.scatter(pts_list[1],pts_list[0],s=3,c='red',alpha=0.7)
plt.xlim(0,300)
plt.ylim(0,300)
Die auf diese Weise erhaltenen Punkte werden über dem Originalbild angezeigt und unten angezeigt.
Sie können die Position der Partikel grob erfassen. Einige Partikel wurden jedoch zweimal nachgewiesen. Um dies zu beseitigen, werden wir die nahe beieinander liegenden Punkte mit ihrem Schwerpunkt als Vertreter zusammenfassen.
Verwenden Sie sklearn.neighbors.NearestNeighbors, um den Abstand zwischen Punkten zu berechnen.
nbrs = NearestNeighbors(n_neighbors=10, algorithm='ball_tree').fit(pts_list.T)
distances, indices = nbrs.kneighbors(pts_list.T)
Der nächste Nachbar gibt die Entfernung und den Index zum Näherungspunkt zurück, indem die Anzahl der Näherungen angegeben wird.
Dieses Mal werden wir berechnen, dass die innerhalb von 3 Pixeln vorhandenen Punkte von demselben Partikel abgeleitet sind.
#Näherungsschwelle
th = 3
#Berechnen Sie den Schwerpunkt mit einem Näherungspunkt unterhalb der Schwelle.
center_list = []
for d,i in zip(distances,indices):
i = i[np.where(d < 3)]
pts = pts_list.T[i]
center = np.mean(pts,axis=0)
center_list.append(center)
center_list = np.array(center_list).astype(np.int32)
#Duplikate entfernen
center_list = np.unique(center_list,axis=0)
center_list = center_list.T
Die auf diese Weise erhaltenen Punkte werden nachstehend auf die gleiche Weise gezeigt. Die Punkte, die sich innerhalb eines Partikels überlappten, sind zusammengefasst. Damit ist die Partikelerkennung abgeschlossen: thumbsup :: thumbsup:
Als nächstes werden wir die Radial Distribution Function (RDF) ableiten. RDF gibt die Wahrscheinlichkeit an, dass ein anderes Teilchen in Bezug auf den Abstand von einem Teilchen existiert, und wird häufig verwendet, um die periodische Struktur eines Kristalls zu beschreiben.
Siehe unten für die Ableitung von RDF und seiner Berechnungsmethode. Berechnung der radialen Verteilungsfunktion --Koishis Seite
Verwenden Sie sklearn.neighbors.NearestNeighbors, um die Näherungsatome zu berechnen.
#Berechnen Sie die Position und Entfernung benachbarter Atome bis zu 40
nbrs = NearestNeighbors(n_neighbors=40, algorithm='ball_tree').fit(center_list.T)
distances, indices = nbrs.kneighbors(center_list.T)
#Berechnen Sie den Abstand zu anderen Partikeln innerhalb von 50 Pixeln und erstellen Sie ein Histogramm
dist_list = []
for d,i in zip(distances,indices):
d = d[np.where(d < 50)][1:]
dist_list.extend(d)
dist_list = np.array(dist_list)
dist_hist = np.histogram(dist_list,range=(0,50),bins=50)
#RDF-Berechnung
rdf = dist_hist[0]/(4*np.pi*np.power(dist_hist[1][1:],2))
Das ist alles in Ordnung. Diesmal habe ich den RDF im Bereich von bis zu 50 Pixel berechnet. (Streng anders, da es nicht durch die Dichte am Ende geteilt wird, aber diesmal ist es in Ordnung, wenn der Spitzenwert bekannt ist)
Das Ergebnis ist unten dargestellt.
Sie können die Gipfel bis zur 1., 2. und 3. Nähe sehen. Die kolloidalen Kristalle sind diesmal dicht gepackt, aber aufgrund einiger Defekte sind die Peaks gespalten oder breit.
Derzeit stellt sich heraus, dass der Abstand zum ersten Näherungspartikel etwa 10 bis 18 Pixel beträgt.
Zählen wir nun die Anzahl dieser ersten Näherungspartikel.
Wenn das kugelförmige Kolloid in zwei Dimensionen dicht gepackt ist, beträgt die Anzahl der Koordinationen mit dem ersten Näherungspartikel ** 6 **. In dem Bereich darunter sind die Kolloide nicht ordentlich angeordnet. Mit anderen Worten kann das Auftragen der Anzahl von Partikeln der ersten Nähe Defekte in kolloidalen Kristallen veranschaulichen.
Lass es uns tun: v :: v: Ich benutze auch sklearn.neighbors.NearestNeighbors. Die Schwelle für die Betrachtung als erstes Proximity-Atom beträgt 16 px.
#Das erste Näherungsatom zählen
co_list = []
for d,i in zip(distances,indices):
d = d[np.where(d < 16)][1:]
co_list.append(d.shape[0])
Zusätzlich zeigt die folgende Abbildung die Anzahl der Partikel der ersten Nähe in einem Histogramm.
Die Anzahl der nächsten Partikel ist im Allgemeinen zwischen 3 und 7 verteilt. Lassen Sie uns zunächst im Bereich von (3,6) zeichnen.
fig = plt.figure(dpi=150,facecolor='white')
plt.imshow(img)
plt.scatter(center_list[1],center_list[0],s=3,c=co_list,cmap='rainbow',alpha=0.7)
plt.colorbar()
plt.clim(3,6)
plt.xlim(0,1000)
plt.ylim(0,1000)
Das Originalbild wird links gezeigt, und die Darstellung jedes durch Koordination farbcodierten Partikels wird rechts gezeigt. Ungeordneter Teil = Der Ort des Defekts kann dargestellt werden: heart_eyes :: heart_eyes:
Schließlich ist hier eine Darstellung über das gesamte Originalbild: point_down:
Lassen Sie uns abschließend die Polykristallkörner kolloidaler Kristalle visualisieren. Insbesondere wird eine zweidimensionale Abbildung von Kristallkörnern (siehe die folgende Abbildung), wie sie durch EBSD (Elektronenstrahl-Rückstreuungsbeugung) erhalten wird, auch für kolloidale Kristalle durchgeführt.
(Quelle: https://www.ube-ind.co.jp/usal/documents/m1303_550.htm)
Eine solche Analyse wird auch in einem Papier über kolloidale Kristalle durchgeführt. Beispielsweise wird in Fig. 1 des folgenden Papiers der durch das interessierende Teilchen gebildete Vektor ⇒ das erste Teilchen in der Nähe gemäß dem von der X-Achse gebildeten Winkel klassifiziert und das Kristallkorn analysiert. Wir machen Visualisierung.
Referenz: [Ramananarivo, S., Ducrot, E. & Palacci, J. Aktivitätsgesteuertes Tempern kolloidaler Monoschichten. Nat Commun 10, 3380 (2019).](Https://doi.org/10.1038/s41467-019- 11362-y)
Lassen Sie es uns auf die gleiche Weise visualisieren!
theta_list = []
for d,i in zip(distances,indices):
#Extrahieren Sie Näherungspartikel ohne sich selbst
idx = i[np.where(d < 16)][1:]
cnts = center_list.T[idx]
#Ermitteln Sie die Position des Partikels mit dem größten X-Wert
top = cnts[np.argmin(cnts[:,1])]
#Ermitteln Sie die Position des interessierenden Partikels
center = center_list.T[i[0]]
#Berechnen Sie den Winkel mit der X-Achse
axis = np.array([0,center[1]])
u = top - center
v = axis - center
c = np.inner(u, v) / (np.linalg.norm(u) * np.linalg.norm(v) + 1e-99)
a = np.rad2deg(np.arccos(np.clip(c, -1.0, 1.0))) - 90
theta_list.append(a)
Das auf diese Weise erhaltene Winkelhistogramm ist unten gezeigt.
Der Winkel scheint im Bereich von ± 30 Grad zu liegen. Lassen Sie uns planen!
Das Originalbild ist links dargestellt, und der Winkel des ersten Näherungsatoms ist rechts aufgetragen. Lassen Sie uns zum Schluss diese Farbcodierung für das gesamte Bild durchführen! Sie können das Korn des kolloidalen Kristalls deutlich sehen: yum :: yum: Es scheint laut zu sein im Vergleich zu der Zuordnung der Papiere, auf die ich mich bezog, aber es sollte für einen Niederlagenjob ausreichen.
Appelliere an Rivalen mit bunten Figuren!
Kürzlich erhielt ich eine Anfrage zur Bildanalyse von einer Person, die kolloidbezogene Forschung betreibt, und ich führte verschiedene Analysen durch, während ich zu Hause blieb. Zur Zeit habe ich gerade einen Absatz fertiggestellt, daher habe ich mein Know-how auf der Grundlage der Bilder kolloidaler Kristalle, die im Netz rollten, zusammengefasst.
Tatsächlich sind die in Experimenten erhaltenen Bilder oft verrauscht und erfordern möglicherweise eine ordnungsgemäße Filterung und Entrauschung. In dieser Hinsicht ist es im Grunde ein Spiel, das herauskommt, oder ein Teil, der Versuch und Irrtum erfordert. Ich möchte bald nützliche Methoden zusammenfassen. Es wird ein chaotischer Artikel.
Na dann ~.
Recommended Posts