|
from PyQt5.QtCore import QSize, QRunnable, Qt, QThreadPool, QObject, pyqtSignal, pyqtSlot, QThread |
|
import numpy as np |
|
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QFrame, QComboBox, QLabel, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QFileDialog, QProgressBar |
|
from PyQt5.QtGui import QPixmap, QImage |
|
import cv2 |
|
import sys |
|
from Relatorio import Relatorio |
|
import json |
|
|
|
from model_manager import ModelManager |
|
from explicador import Explicador |
|
|
|
|
|
class Classify(QObject): |
|
|
|
sg_progess_bar = pyqtSignal(int, str) |
|
sg_update_image = pyqtSignal(QImage) |
|
sg_report = pyqtSignal(str, float) |
|
|
|
str_loading_model = "LOADING MODEL" |
|
str_predicting = "PREDICTING" |
|
str_doing_report = "CONFIGURING REPORT" |
|
str_explaining = "EXPLAINING" |
|
str_showing_explanation = "SHOWING EXPLANATION" |
|
str_finished = "FINISHED" |
|
|
|
def __init__(self, model_manager, model_info, explicador, image, name_explainer): |
|
super().__init__() |
|
self.MODEL_MANAGER = model_manager |
|
self.EXPLICADOR = explicador |
|
self.model_info = model_info |
|
self.image = image |
|
self.name_explainer = name_explainer |
|
|
|
|
|
def run(self): |
|
self.sg_progess_bar.emit(0, self.str_loading_model) |
|
|
|
model = self.MODEL_MANAGER.configure_model(self.model_info["name"], |
|
self.model_info["directory"], |
|
self.model_info["size"], |
|
self.model_info["type"]) |
|
|
|
|
|
self.sg_progess_bar.emit(20, self.str_predicting) |
|
predicted = self.MODEL_MANAGER.make_prediction(self.model_info["name"], self.image) |
|
|
|
|
|
self.sg_progess_bar.emit(40, self.str_doing_report) |
|
self.sg_report.emit(predicted["class_name"], predicted["score"]) |
|
|
|
self.sg_progess_bar.emit(60, self.str_explaining) |
|
if self.name_explainer == "Grad-CAM" or self.name_explainer == "Grad-CAM++": |
|
props = { |
|
"conv_layer":self.model_info["last_conv"] |
|
} |
|
elif self.name_explainer == "LIME": |
|
props = { |
|
"undo_changes":model["undo_changes"] |
|
} |
|
else: |
|
props = {} |
|
explanation = self.EXPLICADOR.get_explanation(self.image, model["model"], model["size"], self.name_explainer, model["preprocessing"], props=props) |
|
|
|
self.sg_progess_bar.emit(80, self.str_showing_explanation) |
|
|
|
explanation = np.asarray(explanation) |
|
height, width, channel = explanation.shape |
|
bytesPerLine = 3 * width |
|
explanation = QImage(explanation.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped() |
|
self.sg_progess_bar.emit(100, self.str_finished) |
|
self.sg_update_image.emit(explanation) |
|
|
|
|
|
|
|
|
|
class MainWindow(QMainWindow): |
|
select_image_str = "select image" |
|
model_str = "select model" |
|
xai_str = "select explainer" |
|
bt_image_str = "select" |
|
run_str = "RUN" |
|
|
|
str_title = "Grapevine Classification" |
|
|
|
MODEL_MANAGER = ModelManager() |
|
EXPLICADOR = Explicador() |
|
|
|
def __init__(self): |
|
super().__init__() |
|
|
|
self.setWindowTitle(self.str_title) |
|
self.setFixedSize(QSize(600, 600)) |
|
|
|
|
|
self.central_widget = QWidget() |
|
self.setCentralWidget(self.central_widget) |
|
central_layout = QHBoxLayout(self.central_widget) |
|
|
|
|
|
self.left_layout = QVBoxLayout() |
|
|
|
self.image_layout = QHBoxLayout() |
|
self.model_layout = QHBoxLayout() |
|
self.xai_layout = QHBoxLayout() |
|
|
|
self.run_layout = QGridLayout() |
|
|
|
|
|
self.select_image_button = QPushButton() |
|
self.select_image_button.setText(self.bt_image_str) |
|
|
|
self.select_model_combobox = QComboBox() |
|
self.select_xai_combobox = QComboBox() |
|
|
|
self.select_run = QPushButton() |
|
self.select_run.setText(self.run_str) |
|
self.select_run.setStyleSheet("background-color: gray; color: black;") |
|
self.select_run.setEnabled(False) |
|
|
|
self.progress_bar = QProgressBar() |
|
self.progress_bar.setAlignment(Qt.AlignCenter) |
|
|
|
|
|
self.select_image_label = QLabel() |
|
self.select_image_label.setText(self.select_image_str) |
|
|
|
self.select_model_label = QLabel() |
|
self.select_model_label.setText(self.model_str) |
|
|
|
self.select_xai_label = QLabel() |
|
self.select_xai_label.setText(self.xai_str) |
|
|
|
|
|
self.visualiza_imagem = QLabel() |
|
|
|
|
|
self.relatorio_widget = Relatorio() |
|
|
|
|
|
self.relatorio_widget.configure('', 0) |
|
|
|
|
|
self.image_layout.addWidget(self.select_image_label) |
|
self.image_layout.addWidget(self.select_image_button) |
|
|
|
self.model_layout.addWidget(self.select_model_label) |
|
self.model_layout.addWidget(self.select_model_combobox) |
|
|
|
self.xai_layout.addWidget(self.select_xai_label) |
|
self.xai_layout.addWidget(self.select_xai_combobox) |
|
|
|
self.run_layout.addWidget(self.select_run, 0, 3) |
|
|
|
self.left_layout.addLayout(self.image_layout) |
|
self.left_layout.addLayout(self.model_layout) |
|
self.left_layout.addLayout(self.xai_layout) |
|
self.left_layout.addWidget(self.progress_bar) |
|
self.left_layout.addLayout(self.run_layout) |
|
self.left_layout.addWidget(self.relatorio_widget) |
|
self.relatorio_widget.hide_labels() |
|
|
|
central_layout.addLayout(self.left_layout) |
|
central_layout.addWidget(self.visualiza_imagem) |
|
|
|
|
|
self.carrega_configuracoes() |
|
|
|
|
|
self.image = None |
|
|
|
|
|
self.define_actions() |
|
|
|
|
|
|
|
|
|
def view_image(self, img): |
|
pixmap = QPixmap(img) |
|
pixmap = pixmap.scaled(300, 300) |
|
self.visualiza_imagem.setPixmap(pixmap) |
|
|
|
def carrega_configuracoes(self): |
|
self.path_config = "config.json" |
|
if len(sys.argv) > 1: |
|
self.path_config = sys.argv[1] |
|
|
|
f = open(self.path_config) |
|
self.configs = json.load(f) |
|
f.close() |
|
models = [x["name"] for x in self.configs["models"]] |
|
self.select_model_combobox.addItems(models) |
|
|
|
self.select_xai_combobox.addItems(self.EXPLICADOR.get_explainers_name()) |
|
self.models = self.configs["models"] |
|
self.MODEL_MANAGER.configure_classes(self.configs["classes"]) |
|
|
|
|
|
def define_actions(self): |
|
self.select_image_button.clicked.connect(self.open_image) |
|
self.select_run.clicked.connect(self.execute) |
|
|
|
|
|
def open_image(self): |
|
fname = QFileDialog.getOpenFileName(self, self.select_image_str, |
|
filter="Image files (*.jpg *.tiff *.jpeg *.bmp *.png)") |
|
print(fname) |
|
self.image = fname[0] |
|
self.view_image(self.image) |
|
self.relatorio_widget.hide_labels() |
|
self.select_run.setStyleSheet("background-color: green; color: white;") |
|
self.select_run.setEnabled(True) |
|
|
|
|
|
@pyqtSlot(int, str) |
|
def update_progress(self, progress, text): |
|
self.progress_bar.setValue(progress) |
|
self.progress_bar.setFormat(text) |
|
|
|
|
|
@pyqtSlot(QImage) |
|
def receive_image(self, img): |
|
self.view_image(img) |
|
self.progress_bar.setTextVisible(False) |
|
|
|
@pyqtSlot(str, float) |
|
def update_relatorio(self, pred_class, score): |
|
self.relatorio_widget.configure(pred_class, score) |
|
|
|
|
|
def execute(self): |
|
self.progress_bar.setTextVisible(True) |
|
model = self.models[self.select_model_combobox.currentIndex()] |
|
name_explainer = str(self.select_xai_combobox.currentText()) |
|
|
|
|
|
|
|
|
|
self.thread = QThread(parent=self) |
|
|
|
self.worker = Classify(self.MODEL_MANAGER, model, self.EXPLICADOR, self.image, name_explainer) |
|
self.worker.sg_progess_bar.connect(self.update_progress) |
|
self.worker.sg_update_image.connect(self.receive_image) |
|
self.worker.sg_report.connect(self.update_relatorio) |
|
|
|
self.worker.moveToThread(self.thread) |
|
|
|
self.thread.started.connect(self.worker.run) |
|
|
|
self.thread.start() |
|
|
|
|
|
|
|
app = QApplication(sys.argv) |
|
|
|
window = MainWindow() |
|
window.show() |
|
|
|
app.exec() |