Prototyp, Analyse von mutmaßlichen Fakes (Papierform, Basis: Videos)
import sys
import os
import cv2
import numpy as np
import tensorflow as tf
import pytesseract
from PyQt5.QtCore import QObject
from skimage.feature import graycomatrix, graycoprops
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, GlobalAveragePooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import EfficientNetB0
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLabel, QProgressBar, QMessageBox, QTextEdit
from PyQt5.QtCore import Qt, QThread, pyqtSignal
import logging
# Logging einrichten für Debugging und Fehlerverfolgung
logging.basicConfig(level=logging.INFO)
# Schritt 1: Extraktion von Frames aus einem Video
def extract_frames(video_path, frame_size=(256, 256)):
"""
Extrahiert alle Frames aus einem Video und skaliert sie auf eine vorgegebene Größe.
:param video_path: Pfad zur Videodatei
:param frame_size: Die Zielgröße der extrahierten Frames
:return: Liste von Frames (NumPy-Arrays)
"""
video = cv2.VideoCapture(video_path)
frames = []
while True:
ret, frame = video.read()
if not ret:
break
frame_resized = cv2.resize(frame, frame_size) # Bildgröße anpassen
frames.append(frame_resized)
video.release()
return frames
# Schritt 2: Extraktion von Texturmerkmalen (Papierstruktur)
def extract_texture_features(image):
"""
Extrahiert Texturmerkmale aus einem Bild, wie Kontrast, Homogenität, Energie und Korrelation,
um die Papierstruktur zu analysieren.
:param image: Eingabebild (NumPy-Array)
:return: Ein Tupel mit den berechneten Texturmerkmalen
"""
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Bild in Graustufen umwandeln
glcm = graycomatrix(gray_image, [1], [0, np.pi/4, np.pi/2, 3*np.pi/4], symmetric=True, normed=True)
contrast = greycoprops(glcm, 'contrast') # Berechnet den Kontrast
homogeneity = greycoprops(glcm, 'homogeneity') # Berechnet die Homogenität
energy = greycoprops(glcm, 'energy') # Berechnet die Energie
correlation = greycoprops(glcm, 'correlation') # Berechnet die Korrelation
return contrast.mean(), homogeneity.mean(), energy.mean(), correlation.mean()
# Schritt 3: Erstellung des Deep Learning Modells
def create_model(input_shape=(256, 256, 3)):
"""
Erstellt ein Convolutional Neural Network (CNN) Modell unter Verwendung von EfficientNetB0
als Feature-Extractor und einer einfachen dichten Schicht zur Klassifikation.
:param input_shape: Die Eingabebildgröße
:return: Das erstellte Modell
"""
base_model = EfficientNetB0(input_shape=input_shape, include_top=False, weights='imagenet') # Vortrainiertes Modell verwenden
base_model.trainable = False # Das vortrainierte Modell einfrieren
model = Sequential()
model.add(base_model) # Fügt das vortrainierte Modell hinzu
model.add(GlobalAveragePooling2D()) # Globales Pooling, um Features zu aggregieren
model.add(Dense(128, activation='relu')) # Dichte Schicht
model.add(Dropout(0.5)) # Dropout für Regularisierung
model.add(Dense(1, activation='sigmoid')) # Ausgabeschicht (binär: Echt oder Gefälscht)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # Modell kompilieren
return model
# Schritt 4: Modelltraining mit erweiterten Datenaugmentation
def train_model(model, train_images, train_labels, validation_images, validation_labels, epochs=20):
"""
Trainiert das Modell mit erweiterten Datenaugmentation, um die Robustheit zu verbessern.
:param model: Das zu trainierende Modell
:param train_images: Trainingsbilder
:param train_labels: Labels der Trainingsbilder
:param validation_images: Validierungsbilder
:param validation_labels: Labels der Validierungsbilder
:param epochs: Anzahl der Epochen für das Training
:return: Das Trainingsergebnis
"""
datagen = ImageDataGenerator(
rotation_range=40, # Drehung der Bilder
width_shift_range=0.3, # Horizontale Verschiebung
height_shift_range=0.3, # Vertikale Verschiebung
shear_range=0.3, # Scherung
zoom_range=0.3, # Zoom
horizontal_flip=True, # Zufälliges horizontales Spiegeln
fill_mode='nearest', # Auffüllen der Bildränder
brightness_range=[0.5, 1.5], # Helligkeit variiert
channel_shift_range=50.0, # Farbraumverschiebung
)
datagen.fit(train_images) # Trainierende Bilder vorbereiten
# Modelltraining mit Validierung
history = model.fit(
datagen.flow(train_images, train_labels, batch_size=32),
epochs=epochs,
validation_data=(validation_images, validation_labels)
)
return history
# Schritt 5: Analyse des Videos mit Vorhersage
def analyze_video(video_path, model, frame_size=(256, 256)):
"""
Führt eine Analyse auf jedem Frame eines Videos durch, um zu bestimmen, ob der Wahlzettel echt oder gefälscht ist.
:param video_path: Pfad zum Video
:param model: Das vortrainierte Deep Learning Modell
:param frame_size: Die Größe der Frames
:return: Eine Liste von Analyseergebnissen
"""
frames = extract_frames(video_path, frame_size)
results = []
for idx, frame in enumerate(frames):
frame_input = np.expand_dims(frame, axis=0) / 255.0 # Normalisieren
prediction = model.predict(frame_input)
result = {
'frame': idx + 1,
'prediction': 'Echt' if prediction[0] > 0.5 else 'Gefälscht', # Entscheidung basierend auf dem Vorhersagewert
'confidence': prediction[0] if prediction[0] > 0.5 else 1 - prediction[0]
}
results.append(result)
return results
# GUI Klasse zur Interaktion mit dem Benutzer
class WahlzettelApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Wahlzettel Erkennung") # Fenster-Titel
self.setGeometry(100, 100, 600, 500) # Fenstergröße und Position
self.model = None # Initialisiert das Modell als None
self.train_images = [] # Initialisiert die Liste der Trainingsbilder
self.train_labels = [] # Initialisiert die Liste der Labels
self.analysis_results = [] # Initialisiert die Liste der Analyseergebnisse
self.init_ui() # GUI initialisieren
def init_ui(self):
"""Erstellt das GUI-Layout mit verschiedenen Buttons und Anzeigen"""
layout = QVBoxLayout()
self.label = QLabel("Wählen Sie Trainingsbilder oder ein Video", self)
self.label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.label)
# Button für das Hinzufügen von Trainingsbildern
self.train_button = QPushButton("Trainingsbilder hinzufügen", self)
self.train_button.clicked.connect(self.load_train_images)
layout.addWidget(self.train_button)
# Button für das Starten des Trainings
self.train_model_button = QPushButton("Modell trainieren", self)
self.train_model_button.clicked.connect(self.train_model)
layout.addWidget(self.train_model_button)
# Button für das Speichern des Modells
self.save_model_button = QPushButton("Modell speichern", self)
self.save_model_button.clicked.connect(self.save_model)
layout.addWidget(self.save_model_button)
# Button für das Laden des Modells
self.load_model_button = QPushButton("Modell laden", self)
self.load_model_button.clicked.connect(self.load_model)
layout.addWidget(self.load_model_button)
# Button für die Videoanalyse
self.analyze_video_button = QPushButton("Video analysieren", self)
self.analyze_video_button.clicked.connect(self.analyze_video)
layout.addWidget(self.analyze_video_button)
# Textfeld für die Anzeige der Analyseergebnisse
self.results_text = QTextEdit(self)
self.results_text.setReadOnly(True)
layout.addWidget(self.results_text)
# Fortschrittsanzeige
self.progress_bar = QProgressBar(self)
layout.addWidget(self.progress_bar)
self.setLayout(layout)
def load_train_images(self):
"""Lädt Trainingsbilder und deren Labels"""
file_paths, _ = QFileDialog.getOpenFileNames(self, "Wählen Sie Trainingsbilder", "", "Bilder (*.png *.jpg *.jpeg)")
if file_paths:
for file_path in file_paths:
img = cv2.imread(file_path)
img_resized = cv2.resize(img, (256, 256)) # Bildgröße anpassen
self.train_images.append(img_resized)
label = 1 if 'echt' in file_path else 0 # Label basierend auf Dateiname (z. B. "echt" oder "gefaelscht")
self.train_labels.append(label)
self.train_images = np.array(self.train_images) / 255.0 # Normalisierung
self.train_labels = np.array(self.train_labels)
self.label.setText(f"{len(self.train_images)} Trainingsbilder geladen")
def train_model(self):
"""Startet das Modelltraining im Hintergrund"""
if not self.train_images:
QMessageBox.warning(self, "Fehler", "Keine Trainingsbilder geladen!")
return
self.progress_bar.setValue(0)
self.label.setText("Training startet...")
# Modell erstellen
self.model = create_model()
# Startet das Training in einem Hintergrund-Thread
self.thread = QThread()
self.worker = TrainWorker(self.model, self.train_images, self.train_labels)
self.worker.moveToThread(self.thread)
self.worker.finished.connect(self.on_training_finished)
self.worker.progress.connect(self.update_progress)
self.thread.started.connect(self.worker.run)
self.thread.start()
def update_progress(self, value):
"""Aktualisiert den Fortschritt der Anzeige"""
self.progress_bar.setValue(value)
def on_training_finished(self):
"""Benachrichtigt, wenn das Training abgeschlossen ist"""
self.label.setText("Training abgeschlossen!")
self.progress_bar.setValue(100)
def save_model(self):
"""Speichert das Modell auf der Festplatte"""
if self.model:
file_path, _ = QFileDialog.getSaveFileName(self, "Speichern Sie das Modell", "", "Modelle (*.h5)")
if file_path:
self.model.save(file_path)
QMessageBox.information(self, "Erfolg", "Modell erfolgreich gespeichert!")
else:
QMessageBox.warning(self, "Fehler", "Kein Modell zum Speichern vorhanden!")
def load_model(self):
"""Lädt ein Modell von der Festplatte"""
file_path, _ = QFileDialog.getOpenFileName(self, "Wählen Sie das Modell", "", "Modelle (*.h5)")
if file_path:
self.model = load_model(file_path)
QMessageBox.information(self, "Erfolg", "Modell erfolgreich geladen!")
def analyze_video(self):
"""Startet die Videoanalyse"""
if self.model is None:
QMessageBox.warning(self, "Fehler", "Das Modell muss zuerst trainiert oder geladen werden!")
return
video_path, _ = QFileDialog.getOpenFileName(self, "Wählen Sie ein Video", "", "Videos (*.mp4 *.avi)")
if video_path:
self.progress_bar.setValue(0)
self.label.setText("Videoanalyse startet...")
# Startet die Analyse im Hintergrund
self.thread = QThread()
self.worker = AnalyzeVideoWorker(self.model, video_path)
self.worker.moveToThread(self.thread)
self.worker.finished.connect(self.on_video_analysis_finished)
self.worker.progress.connect(self.update_progress)
self.thread.started.connect(self.worker.run)
self.thread.start()
def on_video_analysis_finished(self):
"""Benachrichtigt, wenn die Videoanalyse abgeschlossen ist"""
self.label.setText("Videoanalyse abgeschlossen!")
self.progress_bar.setValue(100)
self.display_video_analysis_results()
def display_video_analysis_results(self):
"""Zeigt die Ergebnisse der Videoanalyse im Textfeld an"""
if self.analysis_results:
results_text = ""
for result in self.analysis_results:
results_text += f"Frame {result['frame']}: {result['prediction']} (Confidence: {result['confidence']:.2f})\n"
self.results_text.setText(results_text)
else:
self.results_text.setText("Keine Analyseergebnisse vorhanden.")
class TrainWorker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(int)
def __init__(self, model, train_images, train_labels):
super().__init__()
self.model = model
self.train_images = train_images
self.train_labels = train_labels
def run(self):
"""Trainiert das Modell"""
history = train_model(self.model, self.train_images, self.train_labels, self.train_images, self.train_labels)
self.finished.emit()
class AnalyzeVideoWorker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(int)
def __init__(self, model, video_path):
super().__init__()
self.model = model
self.video_path = video_path
def run(self):
"""Analysiert das Video"""
self.analysis_results = analyze_video(self.video_path, self.model)
self.finished.emit()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = WahlzettelApp()
window.show()
sys.exit(app.exec_())
Kommentare
Kommentar veröffentlichen