Heim  >  Artikel  >  Backend-Entwicklung  >  Verwendung von VGG zur Gesichts- und Geschlechtserkennung

Verwendung von VGG zur Gesichts- und Geschlechtserkennung

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-11-06 10:45:03988Durchsuche

Using VGGfor face and gender recognition

So erstellen Sie ein Python-Projekt zur Gesichts- und Geschlechtserkennung mithilfe von Deep Learning und VGG16.

Was ist Deep Learning?

Deep Learning ist eine Unterkategorie des maschinellen Lernens, ein neuronales Netzwerk mit drei oder mehr Schichten. Diese neuronalen Netze versuchen, das Verhalten des menschlichen Gehirns zu simulieren, indem sie aus großen Datenmengen lernen. Während ein neuronales Netzwerk mit einer einzelnen Schicht immer noch ungefähre Vorhersagen treffen kann, können zusätzliche verborgene Schichten zur Optimierung und Verfeinerung der Genauigkeit beitragen.

Deep Learning verbessert die Automatisierung, indem Aufgaben ohne menschliches Eingreifen ausgeführt werden. Deep Learning findet sich in digitalen Assistenten, sprachgesteuerten TV-Fernbedienungen, der Erkennung von Kreditkartenbetrug und selbstfahrenden Autos.

Erstellen des Python-Projekts

** Schauen Sie sich den vollständigen Code auf GitHub an: https://github.com/alexiacismaru/face-recognision

Laden Sie den VGG16-Gesichtsdatensatz und die Haar Cascade XML-Datei herunter, die für die Gesichtserkennung verwendet werden und für die Vorverarbeitung in der Gesichtserkennungsaufgabe verwendet werden.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())

Laden und verarbeiten Sie selektiv eine bestimmte Anzahl von Bildern für eine Reihe vordefinierter Motive aus dem VGG-Gesichtsdatensatz.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40

Durchsuchen Sie die Datei jedes Betreffs, indem Sie eine mit dem Betreff verknüpfte Textdatei öffnen und den Inhalt lesen. Jede Zeile in diesen Dateien enthält eine URL zu einem Bild. Für jede URL (die auf ein Bild verweist) versucht der Code, das Bild mit urllib zu laden und in ein NumPy-Array zu konvertieren.

images = []

for subject in all_subjects[:nb_subjects]:
  with open(os.path.join(base_path, "vgg_face_dataset", "files", subject), 'r') as f:
    lines = f.readlines()

  images_ = []
  for line in lines:
    url = line[line.find("http://"): line.find(".jpg") + 4]

    try:
      res = request.urlopen(url)
      img = np.asarray(bytearray(res.read()), dtype="uint8")
      # convert the image data into a format suitable for OpenCV
      # images are colored 
      img = cv2.imdecode(img, cv2.IMREAD_COLOR)
      h, w = img.shape[:2]
      images_.append(img)
      cv2_imshow(cv2.resize(img, (w // 5, h // 5)))

    except:
      pass

    # check if the required number of images has been reached
    if len(images_) == nb_images_per_subject:
      # add the list of images to the main images list and move to the next subject
      images.append(images_)
      break

Gesichtserkennung eingerichtet

Using VGGfor face and gender recognition

  1. Suchen Sie ein oder mehrere Gesichter im Bild und fügen Sie es in ein Feld ein.
  2. Stellen Sie sicher, dass das Gesicht mit der Datenbank übereinstimmt, z. B. in Bezug auf Geometrie und Fotometrie.
  3. Extrahieren Sie Merkmale aus dem Gesicht, die für die Erkennungsaufgabe verwendet werden können.
  4. Ordnen Sie das Gesicht einem oder mehreren bekannten Gesichtern in einer vorbereiteten Datenbank zu.
# create arrays for all 4 celebrities
jesse_images = []
michael_images = []
mila_images = []
sarah_images = []

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontalface_default.xml"))

# iterate over the subjects
for subject, images_ in zip(all_subjects, images):

  # create a grayscale copy to simplify the image and reduce computation
  for img in images_:
    img_ = img.copy()
    img_gray = cv2.cvtColor(img_, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        img_gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(30, 30),
        flags=cv2.CASCADE_SCALE_IMAGE
    )
    print("Found {} face(s)!".format(len(faces)))

    for (x, y, w, h) in faces:
        cv2.rectangle(img_, (x, y), (x+w, y+h), (0, 255, 0), 10)

    h, w = img_.shape[:2]
    resized_img = cv2.resize(img_, (224, 224))
    cv2_imshow(resized_img)

    if "Jesse_Eisenberg" in subject:
        jesse_images.append(resized_img)
    elif "Michael_Cera" in subject:
        michael_images.append(resized_img)
    elif "Mila_Kunis" in subject:
        mila_images.append(resized_img)
    elif "Sarah_Hyland" in subject:
        sarah_images.append(resized_img)

Die Methode detectMultiScale erkennt Gesichter im Bild. Anschließend werden die Koordinaten der Rechtecke zurückgegeben, in denen sich seiner Meinung nach Flächen befinden. Um jedes Gesicht herum wird im Bild ein Rechteck gezeichnet, das die Position des Gesichts angibt. Die Größe jedes Bildes wird auf 224 x 224 Pixel geändert.

Teilen Sie den Datensatz in einen Trainings- und Validierungssatz auf:

  • Das Trainingsset wird zum Trainieren des maschinellen Lernmodells verwendet. Es wird verwendet, um die Muster, Merkmale und Beziehungen innerhalb der Daten zu lernen. Das Modell passt seine Parameter an, um Fehler bei Vorhersagen oder Klassifizierungen anhand der Trainingsdaten zu minimieren.
  • Der Validierungssatz bewertet die Leistung des Modells anhand eines neuen Datensatzes. Dies hilft bei der Überprüfung, wie gut sich das Modell auf unsichtbare Daten verallgemeinern lässt. Der Validierungssatz sollte ein unabhängiger Satz sein, der nicht während des Trainings der Modelle verwendet wird. Das Mischen/Verwenden von Informationen aus dem Validierungssatz während des Trainings kann zu verzerrten Ergebnissen führen.
faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())

Datenerweiterung

Die Genauigkeit von Deep-Learning-Modellen hängt von der Qualität, Quantität und kontextuellen Bedeutung der Trainingsdaten ab. Dies ist eine der häufigsten Herausforderungen beim Aufbau von Deep-Learning-Modellen und kann kostspielig und zeitaufwändig sein. Unternehmen nutzen Datenerweiterung, um die Abhängigkeit von Trainingsbeispielen zu verringern und schnell hochpräzise Modelle zu erstellen.

Datenerweiterung bedeutet, die Datenmenge künstlich zu vergrößern, indem aus vorhandenen Daten neue Datenpunkte generiert werden. Dazu gehört das Hinzufügen geringfügiger Änderungen an Daten oder die Verwendung von Modellen des maschinellen Lernens, um neue Datenpunkte im latenten Raum der Originaldaten zu generieren und den Datensatz zu erweitern.

Synthetics stellen künstlich generierte Daten ohne Verwendung realer Bilder dar und werden von Generative Adversarial Networks produziert.

Erweitert wird von Originalbildern mit geringfügigen geometrischen Transformationen (wie Spiegeln, Translation, Rotation oder Hinzufügen von Rauschen) abgeleitet, um die Vielfalt des Trainingssatzes zu erhöhen.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40

Datenerweiterung verbessert die Leistung von ML-Modellen durch vielfältigere Datensätze und senkt die Betriebskosten im Zusammenhang mit der Datenerfassung:

  • Links-rechts spiegeln: Bilder werden zufällig horizontal mit einer Wahrscheinlichkeit von 0,7 gespiegelt. Dies simuliert die Variation aufgrund unterschiedlicher Ausrichtungen von Motiven in Bildern.
  • Rotation: Die Bilder werden mit einer Wahrscheinlichkeit von 0,7 leicht gedreht (bis zu 10 Grad in beide Richtungen). Dies erhöht die Variabilität des Datensatzes durch die Simulation verschiedener Kopfhaltungen.
  • Graustufenkonvertierung: Mit einer Wahrscheinlichkeit von 0,1 werden die Bilder in Graustufen konvertiert. Dadurch wird sichergestellt, dass das Modell Bilder unabhängig von ihren Farbinformationen verarbeiten und daraus lernen kann.
  • Sampling: Die Methode sample(50) generiert 50 erweiterte Bilder aus dem Originalsatz. Dadurch wird der Datensatz erweitert und mehr Daten bereitgestellt, aus denen das Modell lernen kann.

Implementierung des VGG16-Modells

VGG16 ist ein Faltungs-Neuronales Netzwerk, das häufig zur Bilderkennung verwendet wird. Sie gilt als eine der besten Computer-Vision-Modellarchitekturen. Es besteht aus 16 Schichten künstlicher Neuronen, die das Bild schrittweise verarbeiten, um die Genauigkeit zu verbessern. In VGG16 bezieht sich „VGG“ auf die Visual Geometry Group der University of Oxford, während sich „16“ auf die 16 gewichteten Schichten des Netzwerks bezieht.

VGG16 wird zur Bilderkennung und Klassifizierung neuer Bilder verwendet. Die vorab trainierte Version des VGG16-Netzwerks wird anhand von über einer Million Bildern aus der visuellen ImageNet-Datenbank trainiert. VGG16 kann angewendet werden, um festzustellen, ob ein Bild bestimmte Gegenstände, Tiere, Pflanzen und mehr enthält.

VGG16-Architektur

Using VGGfor face and gender recognition

Es gibt 13 Faltungsschichten, fünf Max-Pooling-Schichten und drei dichte Schichten. Daraus ergeben sich 21 Schichten mit 16 Gewichtungen, also 16 lernbare Parameterschichten. VGG16 nimmt die Größe des Eingabetensors als 224 x 244 an. Das Modell konzentriert sich auf Faltungsschichten eines 3x3-Filters mit Schritt 1. Es verwendet immer die gleiche Polsterung mit einer Maxpool-Schicht eines 2x2-Filters mit Schritt 2.

Conv-1 Layer hat 64 Filter, Conv-2 hat 128 Filter, Conv-3 hat 256 Filter, Conv 4 und Conv 5 haben 512 Filter und drei vollständig verbundene Layer, wobei die ersten beiden jeweils 4096 Kanäle haben, der dritte führt eine 1000-Wege-ILSVRC-Klassifizierung durch und enthält 1000 Kanäle (einen für jede Klasse). Die letzte Schicht ist die Soft-Max-Schicht.

Beginnen Sie mit der Vorbereitung des Basismodells.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())

Um sicherzustellen, dass das Modell die Bilder korrekt klassifiziert, müssen wir das Modell um zusätzliche Ebenen erweitern.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40

Die Global Average Pooling 2D-Ebene verdichtet die aus VGG16 erhaltenen Feature-Maps zu einem einzigen 1D-Vektor pro Karte. Es vereinfacht die Ausgabe und reduziert die Gesamtzahl der Parameter, was dazu beiträgt, eine Überanpassung zu verhindern.

Die Dichte Schichten sind eine Folge vollständig verbundener (dichter) Schichten, die hinzugefügt werden. Jede Schicht enthält eine bestimmte Anzahl von Einheiten (1024, 512 und 256), die auf der Grundlage gängiger Praktiken und Experimente ausgewählt werden. Diese Ebenen verarbeiten die von VGG16 extrahierten Features weiter.

Die letzte dichte Ebene (die Ausgabeebene) verwendet eine Sigmoidaktivierung, die für die binäre Klassifizierung geeignet ist (unsere beiden Klassen sind „weiblich“ und „männlich“).

Adam-Optimierung

Der Adam-Optimierungsalgorithmus ist eine Erweiterung des stochastischen Gradientenabstiegsverfahrens, um Netzwerkgewichte iterativ auf der Grundlage von Trainingsdaten zu aktualisieren. Die Methode ist effizient, wenn große Probleme mit vielen Daten oder Parametern bearbeitet werden. Es benötigt weniger Speicher und ist effizient.

Dieser Algorithmus kombiniert zwei Gradientenabstiegsmethoden: Impuls und Root Mean Square Propagation (RMSP).

Momentum ist ein Algorithmus, der dazu dient, den Gradientenabstiegsalgorithmus mithilfe des exponentiell gewichteten Durchschnitts der Gradienten zu beschleunigen.

Using VGGfor face and gender recognition

Root Mean Square Prop ist ein adaptiver Lernalgorithmus, der versucht, den AdaGrad zu verbessern, indem er den „exponentiellen gleitenden Durchschnitt“ verwendet.

Using VGGfor face and gender recognition

Da mt und vt beide als 0 initialisiert wurden (basierend auf den oben genannten Methoden), ist zu beobachten, dass sie tendenziell „gegen 0 tendieren“, da sowohl β1 als auch β2 ≈ 1. Dieser Optimierer behebt dieses Problem durch Berechnung 'Bias-korrigierter' mt und vt. Dies geschieht auch, um die Gewichte beim Erreichen des globalen Minimums zu kontrollieren und starke Schwankungen in dessen Nähe zu verhindern. Die verwendeten Formeln sind:

Using VGGfor face and gender recognition

Intuitiv passen wir uns nach jeder Iteration an den Gradientenabfall an, sodass er während des gesamten Prozesses kontrolliert und unvoreingenommen bleibt, daher der Name Adam.

Anstelle unserer normalen Gewichtsparameter mt und vt nehmen wir nun die voreingenommenen Gewichtsparameter (m_hat)t und (v_hat)t. Setzen wir sie in unsere allgemeine Gleichung ein, erhalten wir:

Using VGGfor face and gender recognition

Quelle: Geeksforgeeks, https://www.geeksforgeeks.org/adam-optimizer/

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())

Richten Sie die Vorverarbeitung, Erweiterung und das Modelltraining von Bilddaten in einem Deep-Learning-Kontext ein.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
  • Epochen: Die Anzahl der Epochen gibt an, wie weit der gesamte Trainingsdatensatz vorwärts und rückwärts durch das neuronale Netzwerk geleitet wird. Das Modell durchläuft die Trainingsdaten zehnmal. Eine Epoche ist eine vollständige Präsentation des zu erlernenden Datensatzes an eine lernende Maschine.
  • batch_size: Dieser Parameter definiert die Anzahl der Proben, die gleichzeitig durch das Netzwerk verbreitet werden. Hier verwenden wir eine Stapelgröße von 30, was bedeutet, dass das Modell 30 Bilder gleichzeitig aufnimmt, sie verarbeitet, die Gewichte aktualisiert und dann mit dem nächsten Stapel von 30 Bildern fortfährt.

Die Leistung des Modells wird bewertet, indem Vorhersagen zum Validierungssatz getroffen werden. Dies gibt einen Eindruck davon, wie gut das Modell unsichtbare Daten verarbeitet. Auf diese Vorhersagen wird ein Schwellenwert angewendet, um jedes Bild in eine von zwei Klassen („männlich“ oder „weiblich“) zu klassifizieren.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40

Erstellen Sie eine Verwirrungsmatrix, um die Genauigkeit zu visualisieren.

images = []

for subject in all_subjects[:nb_subjects]:
  with open(os.path.join(base_path, "vgg_face_dataset", "files", subject), 'r') as f:
    lines = f.readlines()

  images_ = []
  for line in lines:
    url = line[line.find("http://"): line.find(".jpg") + 4]

    try:
      res = request.urlopen(url)
      img = np.asarray(bytearray(res.read()), dtype="uint8")
      # convert the image data into a format suitable for OpenCV
      # images are colored 
      img = cv2.imdecode(img, cv2.IMREAD_COLOR)
      h, w = img.shape[:2]
      images_.append(img)
      cv2_imshow(cv2.resize(img, (w // 5, h // 5)))

    except:
      pass

    # check if the required number of images has been reached
    if len(images_) == nb_images_per_subject:
      # add the list of images to the main images list and move to the next subject
      images.append(images_)
      break

Für die binäre Klassifizierung sind die ROC-Kurve (Receiver Operating Characteristic) und die AUC (Area Under Curve) hilfreich, um die Kompromisse zwischen der Rate richtig positiver und der Rate falsch positiver Ergebnisse zu verstehen.

# create arrays for all 4 celebrities
jesse_images = []
michael_images = []
mila_images = []
sarah_images = []

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontalface_default.xml"))

# iterate over the subjects
for subject, images_ in zip(all_subjects, images):

  # create a grayscale copy to simplify the image and reduce computation
  for img in images_:
    img_ = img.copy()
    img_gray = cv2.cvtColor(img_, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        img_gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(30, 30),
        flags=cv2.CASCADE_SCALE_IMAGE
    )
    print("Found {} face(s)!".format(len(faces)))

    for (x, y, w, h) in faces:
        cv2.rectangle(img_, (x, y), (x+w, y+h), (0, 255, 0), 10)

    h, w = img_.shape[:2]
    resized_img = cv2.resize(img_, (224, 224))
    cv2_imshow(resized_img)

    if "Jesse_Eisenberg" in subject:
        jesse_images.append(resized_img)
    elif "Michael_Cera" in subject:
        michael_images.append(resized_img)
    elif "Mila_Kunis" in subject:
        mila_images.append(resized_img)
    elif "Sarah_Hyland" in subject:
        sarah_images.append(resized_img)

Abschluss

Zusammenfassend lässt sich sagen, dass Sie durch die Verwendung von Deep-Learning- und Bildverarbeitungsalgorithmen ein Python-Projekt erstellen können, das menschliche Gesichter erkennt und sie entweder als männlich oder weiblich kategorisieren kann.

Das obige ist der detaillierte Inhalt vonVerwendung von VGG zur Gesichts- und Geschlechtserkennung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn