Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities

Ich denke, ich spreche für alle, die versuchen, ein DL-Klassifikationsmodell zu trainieren und 80% ihrer Zeit mit dem Sammeln von Bildern, der Reinigung von Bildern, der Deduplizierung von Bildern, dem Sortieren von Bildern usw. und nur 20% der gesamten Projektzeit mit dem Training und der Feinabstimmung des Modells verbringen. Auch bei der Auswertung eines DL-Modells haben wir normalerweise nur die Accuracy (%) als Hauptmetrik. Was ist, wenn es eine bessere Möglichkeit gibt, diese Dinge zu tun?

Heute habe ich das Vergnügen, Ihnen eine benutzerfreundliche, auf tiefem Lernen basierende Computer Vision Anwendung mit mehreren eingebauten datenwissenschaftlich orientierten Fähigkeiten vorzustellen.

Zusammenfassung: Dieses Papier stellt eine datenwissenschaftlich orientierte Anwendung für Bildklassifizierungsaufgaben vor, die in der Lage ist, automatisch zu arbeiten: a) Bilder, die für das Training von Deep Learning (DL)-Modellen benötigt werden, mit einem eingebauten Suchmaschinen-Crawler zu sammeln; b) doppelte Bilder zu entfernen; c) Bilder mit Hilfe von eingebauten, vortrainierten DL-Modellen oder dem eigenen, trainierten DL-Modell zu sortieren; d) Datenvergrößerung anzuwenden; e) ein DL-Klassifikationsmodell zu trainieren; f) die Leistung eines DL-Modells und eines Systems mit Hilfe eines Genauigkeitsrechners sowie der Metrikrechner Accuracy Per Consumption (APC), Accuracy Per Energy Cost (APEC), Time To Closest APC (TTCAPC) und Time To Closest APEC (TTCAPEC) bewerten. Experimentelle Ergebnisse zeigen, dass die vorgeschlagene Computer Vision-Anwendung mehrere einzigartige Merkmale und Vorteile aufweist, die sich als effizient hinsichtlich der Ausführungszeit und als viel einfacher zu verwenden im Vergleich zu ähnlichen Anwendungen erweisen.

Sie können den Artikel hier lesen.

Ein Video der ersten Version der „Sorin’s Computer Vision App“ ist hier zu sehen:

Ein Video der zweiten Version der „Sorin’s Computer Vision app“, die viel mehr eingebaute Funktionen enthält, kann hier angesehen werden:

Ein Video mit der endgültigen Implementierung der „Sorin’s Computer Vision Application“ (die eine Datenerweiterungsschnittstelle in der Trainingsfunktion sowie die umweltfreundlichen Metriken APC, APEC, TTCAPC und TTCAPEC enthält) ist unten zu sehen. Aus Zeitgründen zeige ich nur diese letzten implementierten Optionen und Funktionen und nicht auch den Rest, da diese in den Videos oben zu sehen sind.

Hier habe ich alle Projektdateien (neueste Version) bezüglich unserer Tiefgehende lernbasierte Computer Vision Anwendung mit mehreren eingebauten datenwissenschaftlich orientierten Fähigkeiten veröffentlicht.

Compilation dependencies
System:
● python 3
Python libraries:
● PyQt5 – For creating the GUI
● HDF5 – To load model files
● Tensorflow – For inference
● OpenCV – For image processing
● Numpy – For data processing
● Shutil – To copy images in the system
● TQDM – For terminal progress bar
● Imagededupe – For deduplication of images
● Icrawler – For crawling for images
● Fman build system (fbs) – For creating installers

Installation requirements
● Windows 10+
● Linux (tested working on ubuntu 12+)

accuracy_calculator.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QIntValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow)
import os
from tensorflow import keras
import numpy as np
from image_sorter import ModelClassesSelection, resnet50Preprocess
import cv2

class AccuracyCalculator(ModelClassesSelection):
def __init__(self, target=None, parent=None):
super(AccuracyCalculator, self).__init__(parent)
self.target = target

self.labelComboLayout.removeWidget(self.slider)
self.slider.deleteLater()
self.slider = None
self.labelComboLayout.removeWidget(self.sliderLabel)
self.sliderLabel.deleteLater()
self.sliderLabel = None

sortedImagesFolderLabel = QLabel(„&Test images folder:“)
sortedImagesFolderButton = QPushButton(„Browse“)
sortedImagesFolderButton.clicked.connect(self.setSortedFolder)
self.sortedImagesFolderLine = QLineEdit(„Path to folder“)
sortedImagesFolderLabel.setBuddy(self.sortedImagesFolderLine)

sortedImagesLineButton = QHBoxLayout()
sortedImagesLineButton.addWidget(self.sortedImagesFolderLine)
sortedImagesLineButton.addWidget(sortedImagesFolderButton)
sortedImagesLineButton.addStretch(1)

self.topLayout.addWidget(sortedImagesFolderLabel)
self.topLayout.addLayout(sortedImagesLineButton)

sizeOfBatchesLabel = QLabel(„Size of batches“)
self.sizeOfBatchesLine = QLineEdit(„20“)
self.sizeOfBatchesLine.setValidator(QIntValidator())
sizeOfBatchesBox = QHBoxLayout()
sizeOfBatchesBox.addWidget(sizeOfBatchesLabel)
sizeOfBatchesBox.addWidget(self.sizeOfBatchesLine)

self.topLayout.addLayout(sizeOfBatchesBox)

self.calculateButton = QPushButton(„Calculate Accuracy“)
self.calculateButton.clicked.connect(self.calculateAccuracy)
self.mainLayout.addWidget(self.calculateButton)

self.setWindowTitle(„Accuracy Calculator“)

def setSortedFolder(self, btn):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.sortedImagesFolderLine.setText(folder)

def calculateAccuracy(self, btn):
selectedFolder = self.sortedImagesFolderLine.text()
if not os.path.isdir(selectedFolder):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a valid images folder.‘)
return 0
folderContents = os.listdir(selectedFolder)
for element in folderContents:
elementPath = os.path.join(selectedFolder, element)
if not os.path.isdir(elementPath):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚A valid images folder should only have sub folders.‘)
return 0
for folder in folderContents:
for element in os.listdir(os.path.join(selectedFolder, folder)):
elementPath = os.path.join(selectedFolder, folder, element)
isImage = True
try:
cv2.imread(elementPath)
except Exception:
isImage = False
if not isImage:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Some of the subfolders containts stuff other than images.‘)
return 0

if self.modelComboBox.currentText() == „Custom“:
if not os.path.isfile(self.modelFileLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a custom model file.‘)
return 0

model = keras.models.load_model(self.modelFileLine.text())
for layer in model.layers:
inputShape = layer.input_shape[1:]
break
preprocess = resnet50Preprocess
modelClassesPath = self.modelClassesLine.text()
else:
modelName = self.modelComboBox.currentText()
modelPath = self.models[modelName][‚modelPath‘]
modelClassesPath = self.models[modelName][‚modelClasses‘]
assert os.path.isfile(modelClassesPath)
assert os.path.isfile(modelPath)

inputShape = self.models[modelName][‚inputShape‘]
preprocess = self.models[modelName][‚preprocessor‘]

model = keras.models.load_model(modelPath)

classes = []
with open(modelClassesPath, ‚r‘) as f:
for line in f:
line = line.strip()
classes.append(line)

batchSize = int(self.sizeOfBatchesLine.text())

accurateResults = 0
totalResults = 0

progress = QProgressDialog(„Evaluating Model…“,
„Cancel“, 0, len(classes), self)
progress.setWindowModality(Qt.WindowModal)
progress.forceShow()

for classIndex in range(len(classes)):
progress.setValue(classIndex)

if progress.wasCanceled():
break

folderClass = classes[classIndex]
fullClassPath = os.path.join(selectedFolder, folderClass)
if os.path.isdir(fullClassPath):
xbatch = []
ybatch = []
for imageName in os.listdir(fullClassPath):
x = preprocess(os.path.join(fullClassPath, imageName), inputShape)[0]
xbatch.append(x)
ybatch.append(classIndex)
if len(xbatch) == batchSize:
xbatch = np.array(xbatch)
ybatch = np.array(ybatch)
output = np.argmax(model.predict_on_batch(xbatch), axis=-1)
accurateResults += np.sum(output == ybatch)
totalResults += len(output)
xbatch = []
ybatch = []
if len(xbatch) > 0:
xbatch = np.array(xbatch)
ybatch = np.array(ybatch)
output = np.argmax(model.predict_on_batch(xbatch), axis=-1)
accurateResults += np.sum(output == ybatch)
totalResults += len(output)

if classIndex >= len(classes) – 1:
progress.setValue(len(classes))
self.results = accurateResults/totalResults
QMessageBox.about(self, „Evaluation Completed!“,
f“Accuracy: {self.results}“)
if self.target is not None:
self.target.setText(str(self.results*100))
self.close()
self.parent().close()
return self.results
else:
QMessageBox.about(self, „Evaluation Incomplete“,
„The evaluation was aborted.“)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = AccuracyCalculator()
imgc.show()

sys.exit(app.exec_())

apc_calculator.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QDoubleValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow)
from image_sorter import ModelClassesSelection
import os
from tensorflow import keras
import numpy as np
import energyusage

class ApcCalculator(ModelClassesSelection):
def __init__(self, parent=None):
super(ApcCalculator, self).__init__(parent)

self.labelComboLayout.removeWidget(self.slider)
self.slider.deleteLater()
self.slider = None
self.labelComboLayout.removeWidget(self.sliderLabel)
self.sliderLabel.deleteLater()
self.sliderLabel = None
self.midLayout.removeWidget(self.modelClassesLabel)
self.midLayout.removeWidget(self.modelClassesLine)
self.midLayout.removeWidget(self.modelClassesButton)
self.modelClassesLabel.deleteLater()
self.modelClassesLabel = None
self.modelClassesLine.deleteLater()
self.modelClassesLine = None
self.modelClassesButton.deleteLater()
self.modelClassesButton = None

self.accuracyLabel = QLabel(„Model test accuracy (%)“)
self.accuracyLine = QLineEdit(„60“)
self.accuracyLine.setValidator(QDoubleValidator())
self.accuracyBox = QHBoxLayout()
self.accuracyBox.addWidget(self.accuracyLabel)
self.accuracyBox.addWidget(self.accuracyLine)

self.topLayout.addLayout(self.accuracyBox)

self.batchSizeLabel = QLabel(„Batch size“)
self.batchSizeLine = QLineEdit(„1“)
self.batchSizeLine.setValidator(QDoubleValidator())
self.batchSizeBox = QHBoxLayout()
self.batchSizeBox.addWidget(self.batchSizeLabel)
self.batchSizeBox.addWidget(self.batchSizeLine)

self.topLayout.addLayout(self.batchSizeBox)

self.alphaLabel = QLabel(„Alpha (0 <= a <= 0.5)“)
self.alphaLine = QLineEdit(„0.2“)
self.alphaLine.setValidator(QDoubleValidator())

self.betaLabel = QLabel(„Beta (0 < b)“)
self.betaLine = QLineEdit(„1“)
self.betaLine.setValidator(QDoubleValidator())

self.parametersBox = QHBoxLayout()
self.parametersBox.addWidget(self.alphaLabel)
self.parametersBox.addWidget(self.alphaLine)
self.parametersBox.addWidget(self.betaLabel)
self.parametersBox.addWidget(self.betaLine)

self.topLayout.addLayout(self.parametersBox)

self.calculateButton = QPushButton(„Calculate APC“)
self.calculateButton.clicked.connect(self.calculateAPC)

self.mainLayout.addWidget(self.calculateButton)

self.setWindowTitle(„Accuracy Per Consumption Calculator“)

def calculateAPC(self, btn):
accuracy = float(self.accuracyLine.text())
if accuracy < 0 or accuracy > 100:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Accuracy (%) should be between 0 and 100.‘)
return 0

batchSize = int(self.batchSizeLine.text())
if batchSize < 1:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Batch size must be greater than 0‘)
return 0

alpha = float(self.alphaLine.text())
if alpha < 0 or alpha > 0.5:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Alpha must be between 0 and 0.5‘)
return 0

beta = float(self.betaLine.text())
if beta <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Beta must be greater than 0‘)
return 0

modelName = self.modelComboBox.currentText()
if modelName == „Custom“:
if not os.path.isfile(self.modelFileLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a custom model file.‘)
return 0

model = keras.models.load_model(self.modelFileLine.text())
for layer in model.layers:
inputShape = layer.input_shape[1:]
break
else:
modelName = self.modelComboBox.currentText()
modelPath = self.models[modelName][‚modelPath‘]

inputShape = self.models[modelName][‚inputShape‘]

model = keras.models.load_model(modelPath)
batchInputShape = (batchSize, *inputShape)
energyConsumption = []
for _ in range(10):
consumption = calculateConsumption(model, batchInputShape)
energyConsumption.append(consumption)

def calculateConsumption(function):
energyOutput = energyusage.evaluate(function, energyOutput=True)[1]
return energyOutput

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = ApcCalculator()
imgc.show()

sys.exit(app.exec_())
# model = keras.models.load_model(„Models/mnist/mnist_model.h5“)
# shape = (10, 28, 28, 1)
# randomInput = np.random.uniform(-1, size=shape)

# def inference():
# output = model.predict(randomInput, max_queue_size=0)
# return output

# print(inference())

# eo = energyusage.evaluate(inference, energyOutput=True)[1]

# print(eo)

apc_calculator2.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QDoubleValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow, QTableWidgetItem, QAbstractScrollArea)
import os
import numpy as np
from metric import accuracyPerConsumption
from accuracy_calculator import AccuracyCalculator

class ApcCalculator(QDialog):
def __init__(self, parent=None):
super(ApcCalculator, self).__init__(parent)

self.topLayout = QVBoxLayout()

self.accuracyLabel = QLabel(„Model test accuracy (%)“)
self.accuracyLine = QLineEdit(„60“)
self.accuracyLine.textChanged.connect(self.recalculate)
self.accuracyLine.setValidator(QDoubleValidator())
self.calculateAccuracyButton = QPushButton(„Calculate“)
self.calculateAccuracyButton.clicked.connect(self.calculateAccuracy)
self.accuracyBox = QHBoxLayout()
self.accuracyBox.addWidget(self.accuracyLabel)
self.accuracyBox.addWidget(self.accuracyLine)
self.accuracyBox.addWidget(self.calculateAccuracyButton)

self.topLayout.addLayout(self.accuracyBox)

self.energyConsumptionLabel = QLabel(„Energy Consumption (WH)“)
self.energyConsumptionLine = QLineEdit(„1“)
self.energyConsumptionLine.textChanged.connect(self.recalculate)
self.energyConsumptionLine.setValidator(QDoubleValidator())
self.energyConsumptionBox = QHBoxLayout()
self.energyConsumptionBox.addWidget(self.energyConsumptionLabel)
self.energyConsumptionBox.addWidget(self.energyConsumptionLine)

self.topLayout.addLayout(self.energyConsumptionBox)

self.alphaLabel = QLabel(„Alpha (0 <= a <= 0.5)“)
self.alphaLine = QLineEdit(„0.1“)
self.alphaLine.textChanged.connect(self.recalculate)
self.alphaLine.setValidator(QDoubleValidator())

self.betaLabel = QLabel(„Beta (0 < b, recommended 1/average of consumptions)“)
self.betaLine = QLineEdit(„1“)
self.betaLine.textChanged.connect(self.recalculate)
self.betaLine.setValidator(QDoubleValidator())

self.parametersBox = QHBoxLayout()
self.parametersBox.addWidget(self.alphaLabel)
self.parametersBox.addWidget(self.alphaLine)
self.parametersBox.addWidget(self.betaLabel)
self.parametersBox.addWidget(self.betaLine)

self.topLayout.addLayout(self.parametersBox)

self.calculateButton = QPushButton(„Calculate APC“)
self.calculateButton.clicked.connect(self.calculateAPC)

self.mainLayout = QVBoxLayout()

self.mainLayout.addLayout(self.topLayout)

self.resultTable = QTableWidget(1, 5)
self.resultTable.setHorizontalHeaderLabels([„Accuracy“, „Energy Consumption“, „Alpha“, „Beta“, „APC“])
self.resultTable.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.resultTable.setVerticalHeaderLabels([„“])
self.resultTable.setItem(0, 0, QTableWidgetItem(„60“))
self.resultTable.setItem(0, 1, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 2, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 3, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 4, QTableWidgetItem(„-„))
self.resultTable.resizeColumnsToContents()

self.mainLayout.addWidget(self.resultTable)
self.mainLayout.addWidget(self.calculateButton)

self.setLayout(self.mainLayout)
self.setWindowTitle(„Accuracy Per Consumption Calculator“)

def recalculate(self, btn):
try:
acc = float(self.accuracyLine.text())
energy = float(self.energyConsumptionLine.text())
alpha = float(self.alphaLine.text())
beta = float(self.betaLine.text())
self.resultTable.setItem(0, 0, QTableWidgetItem(str(acc)))
self.resultTable.setItem(0, 1, QTableWidgetItem(str(energy)))
self.resultTable.setItem(0, 2, QTableWidgetItem(str(alpha)))
self.resultTable.setItem(0, 3, QTableWidgetItem(str(beta)))
apc = accuracyPerConsumption(energy, acc/100, alpha, beta)
self.resultTable.setItem(0, 4, QTableWidgetItem(str(int(10000*apc)/10000)))
self.resultTable.resizeColumnsToContents()
print(accuracyPerConsumption(energy, acc/100, alpha, beta))
except:
pass
print(„recalculating“)

def calculateAccuracy(self, btn):
self.accCalc = QDialog()
self.accCalc.setWindowModality(Qt.WindowModal)
self.accLayout = QVBoxLayout()
self.calculator = AccuracyCalculator(target=self.accuracyLine)
self.accLayout.addWidget(self.calculator)
self.accCalc.setLayout(self.accLayout)
self.accCalc.show()
# self.accuracyLine.setText(„99.9″)

def passAccuracy(self, calculator):
self.accuracyLine.setText(str(calculator.results))

def calculateAPC(self, btn):
accuracy = float(self.accuracyLine.text())
if accuracy < 0 or accuracy > 100:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Accuracy (%) should be between 0 and 100.‘)
return 0

energyConsumption = float(self.energyConsumptionLine.text())
if energyConsumption < 1:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Batch size must be greater than 0‘)
return 0

alpha = float(self.alphaLine.text())
if alpha < 0 or alpha > 0.5:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Alpha must be between 0 and 0.5‘)
return 0

beta = float(self.betaLine.text())
if beta <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Beta must be greater than 0‘)
return 0
print(f“alpha={alpha}, beta={beta}, accuracy={accuracy}, energyConsumption={energyConsumption}“)
apc = accuracyPerConsumption(energyConsumption, accuracy/100, a=alpha, b=beta)
print(f“accuracy per consumption = {apc}“)
QMessageBox.about(self,
„Accuracy per Consumption succesfully calculated!“,
f“““Alpha = {alpha}
Beta = {beta}
Energy Consumption = {energyConsumption}
Accuracy = {accuracy}%

Accuracy Per Consumption = {int(apc*10000)/100}%“““)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = ApcCalculator()
imgc.show()

sys.exit(app.exec_())

apec_calculator.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QDoubleValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow, QTableWidgetItem, QAbstractScrollArea)
import os
import numpy as np
from metric import accuracyPerConsumption
from accuracy_calculator import AccuracyCalculator

class ApecCalculator(QDialog):
def __init__(self, parent=None):
super(ApecCalculator, self).__init__(parent)

self.topLayout = QVBoxLayout()

self.accuracyLabel = QLabel(„Model test accuracy (%)“)
self.accuracyLine = QLineEdit(„60“)
self.accuracyLine.textChanged.connect(self.recalculate)
self.accuracyLine.setValidator(QDoubleValidator())
self.calculateAccuracyButton = QPushButton(„Calculate“)
self.calculateAccuracyButton.clicked.connect(self.calculateAccuracy)
self.accuracyBox = QHBoxLayout()
self.accuracyBox.addWidget(self.accuracyLabel)
self.accuracyBox.addWidget(self.accuracyLine)
self.accuracyBox.addWidget(self.calculateAccuracyButton)

self.topLayout.addLayout(self.accuracyBox)

self.energyConsumptionLabel = QLabel(„Energy Consumption (WH)“)
self.energyConsumptionLine = QLineEdit(„1“)
self.energyConsumptionLine.textChanged.connect(self.recalculate)
self.energyConsumptionLine.setValidator(QDoubleValidator())
self.energyConsumptionBox = QHBoxLayout()
self.energyConsumptionBox.addWidget(self.energyConsumptionLabel)
self.energyConsumptionBox.addWidget(self.energyConsumptionLine)

self.energyCostLabel = QLabel(„Watt-Hour Cost (cents EUR)“)
self.energyCostLine = QLineEdit(„0.00001“)
self.energyCostLine.textChanged.connect(self.recalculate)
self.energyCostLine.setValidator(QDoubleValidator())
self.energyCostBox = QHBoxLayout()
self.energyCostBox.addWidget(self.energyCostLabel)
self.energyCostBox.addWidget(self.energyCostLine)

self.topLayout.addLayout(self.energyConsumptionBox)
self.topLayout.addLayout(self.energyCostBox)

self.alphaLabel = QLabel(„Alpha (0 <= a <= 0.5)“)
self.alphaLine = QLineEdit(„0.1“)
self.alphaLine.textChanged.connect(self.recalculate)
self.alphaLine.setValidator(QDoubleValidator())

self.betaLabel = QLabel(„Beta (0 < b, recommended 1/average of costs)“)
self.betaLine = QLineEdit(„1“)
self.betaLine.textChanged.connect(self.recalculate)
self.betaLine.setValidator(QDoubleValidator())

self.parametersBox = QHBoxLayout()
self.parametersBox.addWidget(self.alphaLabel)
self.parametersBox.addWidget(self.alphaLine)
self.parametersBox.addWidget(self.betaLabel)
self.parametersBox.addWidget(self.betaLine)

self.topLayout.addLayout(self.parametersBox)

self.calculateButton = QPushButton(„Calculate APEC“)
self.calculateButton.clicked.connect(self.calculateAPEC)

self.mainLayout = QVBoxLayout()

self.mainLayout.addLayout(self.topLayout)

self.resultTable = QTableWidget(1, 6)
self.resultTable.setHorizontalHeaderLabels([„Accuracy“, „Energy Cost“, „Alpha“, „Beta“, „APEC“, „APEC Green Powered“])
self.resultTable.setVerticalHeaderLabels([„“])
self.resultTable.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.resultTable.setItem(0, 0, QTableWidgetItem(„60“))
self.resultTable.setItem(0, 1, QTableWidgetItem(„0.000010“))
self.resultTable.setItem(0, 2, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 3, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 4, QTableWidgetItem(„“))
self.resultTable.setItem(0, 5, QTableWidgetItem(„“))
self.resultTable.resizeColumnsToContents()

self.mainLayout.addWidget(self.resultTable)

self.mainLayout.addWidget(self.calculateButton)

self.setLayout(self.mainLayout)
self.setWindowTitle(„Accuracy Per Energy Cost Calculator“)

def recalculate(self, btn):
try:
acc = float(self.accuracyLine.text())
energy = float(self.energyConsumptionLine.text())
ecost = float(self.energyCostLine.text())
alpha = float(self.alphaLine.text())
beta = float(self.betaLine.text())
self.resultTable.setItem(0, 0, QTableWidgetItem(str(acc)))
self.resultTable.setItem(0, 1, QTableWidgetItem(f“{energy*ecost:.6f}“))
self.resultTable.setItem(0, 2, QTableWidgetItem(str(alpha)))
self.resultTable.setItem(0, 3, QTableWidgetItem(str(beta)))
apc = accuracyPerConsumption(ecost*energy, acc/100, alpha, beta)
self.resultTable.setItem(0, 4, QTableWidgetItem(str(int(10000*apc)/10000)))
apec = accuracyPerConsumption(0, acc/100, alpha, beta)
self.resultTable.setItem(0, 5, QTableWidgetItem(str(int(10000*apec)/10000)))
self.resultTable.resizeColumnsToContents()
print(accuracyPerConsumption(ecost*energy, acc/100, alpha, beta))
except Exception as e:
print(e)
print(„recalculating“)

def calculateAccuracy(self, btn):
self.accCalc = QDialog()
self.accCalc.setWindowModality(Qt.WindowModal)
self.accLayout = QVBoxLayout()
self.calculator = AccuracyCalculator(target=self.accuracyLine)
self.accLayout.addWidget(self.calculator)
self.accCalc.setLayout(self.accLayout)
self.accCalc.show()
# self.accuracyLine.setText(„99.9″)

def passAccuracy(self, calculator):
self.accuracyLine.setText(str(calculator.results))

def calculateAPEC(self, btn):
accuracy = float(self.accuracyLine.text())
if accuracy < 0 or accuracy > 100:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Accuracy (%) should be between 0 and 100.‘)
return 0

energyConsumption = float(self.energyConsumptionLine.text())
if energyConsumption <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Energy Consumption must be positive‘)
return 0

energyCost = float(self.energyCostLine.text())
if energyCost <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Energy Cost must be positive‘)
return 0

alpha = float(self.alphaLine.text())
if alpha < 0 or alpha > 0.5:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Alpha must be between 0 and 0.5‘)
return 0

beta = float(self.betaLine.text())
if beta <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Beta must be greater than 0‘)
return 0

energyConsumptionCost = energyCost*energyConsumption
print(f“alpha={alpha}, beta={beta}, accuracy={accuracy}, energyConsumptionCost={energyConsumptionCost}“)
apec = accuracyPerConsumption(energyConsumptionCost, accuracy/100, a=alpha, b=beta)
print(f“accuracy per energy cost = {apec}“)
QMessageBox.about(self,
„Accuracy per Energy Cost succesfully calculated!“,
f“““Alpha = {alpha}
Beta = {beta}
Energy Consumption Cost = {energyConsumptionCost:.10f}
Accuracy = {accuracy}%

Accuracy Per Energy Cost = {int(apec*10000)/100}%“““)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = ApecCalculator()
imgc.show()

sys.exit(app.exec_())

classifier_crawler.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer, QSortFilterProxyModel
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QCompleter, QProgressDialog)
from image_sorter import ModelClassesSelection, mnistPreprocess
from Crawler_extra import searchImages
import os
from tensorflow import keras
import errno
import shutil
import numpy as np
from tqdm import tqdm
import cv2

class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)

self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)

self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())

self.completer = QCompleter(self.pFilterModel, self)
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)

self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)

def on_completer_activated(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
self.activated[str].emit(self.itemText(index))

def setModel(self, model):
super(ExtendedComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)

def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(ExtendedComboBox, self).setModelColumn(column)

class ImageCrawler(ModelClassesSelection):
def __init__(self, parent=None):
super(ImageCrawler, self).__init__(parent)
self.classComboBox = ExtendedComboBox()
self.comboHLayout = QHBoxLayout()
self.comboLabel = QLabel(„Select a class of images: „)
self.comboHLayout.addWidget(self.comboLabel, 10)
self.comboHLayout.addWidget(self.classComboBox, 40)
self.amountSlider = QSlider(Qt.Horizontal)
self.amountSlider.setMinimum(1)
self.amountSlider.setMaximum(999)
self.amountSlider.setValue(20)
self.amountSlider.setTickInterval(1)
self.amountSlider.valueChanged.connect(self.amountValuechange)
self.amountLabel = QLabel(„Max amount to get: 020“)
self.comboHLayout.addWidget(self.amountLabel, 10)
self.comboHLayout.addWidget(self.amountSlider, 10)
self.mainLayout.addLayout(self.comboHLayout, 1)

destinationFolderLabel = QLabel(„&Destination folder:“)
destinationFolderButton = QPushButton(„Browse“)
destinationFolderButton.clicked.connect(self.setDestinationFolder)
self.destinationFolderLine = QLineEdit(„Path to folder“)
destinationFolderLabel.setBuddy(self.destinationFolderLine)

destinationLineButton = QHBoxLayout()
destinationLineButton.addWidget(self.destinationFolderLine)
destinationLineButton.addWidget(destinationFolderButton)
destinationLineButton.addStretch(1)

self.mainLayout.addWidget(destinationFolderLabel)
self.mainLayout.addLayout(destinationLineButton)

self.crawlButton = QPushButton(„Add Images!“)
self.crawlButton.clicked.connect(self.crawl)
self.mainLayout.addWidget(self.crawlButton)

self.modelChosen(self.classComboBox)

self.setWindowTitle(„Classifier Crawler“)

def amountValuechange(self, slider):
value = self.amountSlider.value()
if value < 10:
value = f“00{value}“
elif value < 100:
value = f“0{value}“
self.amountLabel.setText(f“Max amount to get: {value}“)

def modelChosen(self, combo):
print(„ok“)
selectedModel = self.modelComboBox.currentText()
self.modelCreditLabel.setText(self.models[selectedModel][‚credit‘])
if selectedModel != „Custom“:
classesPath = self.models[selectedModel][‚modelClasses‘]
self.classesNames = []
with open(classesPath, ‚r‘) as f:
for line in f:
line = line.strip()
self.classesNames.append(line)
self.classComboBox.clear()
self.classComboBox.addItems(self.classesNames)

def setDestinationFolder(self, button):
folder = str(QFileDialog.getExistingDirectory(self, „Select Destination Folder“))
self.destinationFolderLine.setText(folder)

def crawl(self, btn):
if not os.path.isdir((self.destinationFolderLine.text())):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a valid destination folder.‘)
else:
# unpack options
chosenModelName = self.modelComboBox.currentText()
keyword = self.classComboBox.currentText()
classIndex = self.classesNames.index(keyword)
destinationDir = self.destinationFolderLine.text()
maxImages = self.amountSlider.value()

if chosenModelName == „Custom“:
if not os.path.isfile(self.modelFileLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a custom model file.‘)
return 0
elif not os.path.isfile(self.modelClassesLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(
‚Especify a custom model classes file.‘)
return 0
else:
print(self.modelFileLine.text(), self.modelClassesLine.text())
model = keras.models.load_model(self.modelFileLine.text())
for layer in model.layers:
inputShape = layer.input_shape[1:]
break
preprocess = mnistPreprocess
modelClassesPath = self.modelClassesLine.text()
else:
modelName = chosenModelName
modelPath = self.models[modelName][‚modelPath‘]
modelClassesPath = self.models[modelName][‚modelClasses‘]
assert os.path.isfile(modelClassesPath)
assert os.path.isfile(modelPath)

inputShape = self.models[modelName][‚inputShape‘]
preprocess = self.models[modelName][‚preprocessor‘]

model = keras.models.load_model(modelPath)

# save crawled images to temporal location
tmpDir = f“.tmp_7y5h92fje_{keyword}_images“
try:
os.makedirs(tmpDir)
except OSError as e:
if e.errno != errno.EEXIST:
raise

progress = QProgressDialog(„Please wait…“, „Cancel“, 0, 100, parent=self)
progress.setWindowModality(Qt.WindowModal)
progress.forceShow()
progress.setValue(1)
progress.setValue(2)
progress.setValue(3)
progress.setValue(4)
progress.setValue(5)
progress.forceShow()
searchImages(keyword.replace(„_“, “ „), tmpDir, maxImages)
progress.setValue(0)

# predict model over each image
i = 0
progress.setMaximum(len(os.listdir(tmpDir)))
for imagePath in tqdm(os.listdir(tmpDir)):
i += 1
progress.setValue(i)

if progress.wasCanceled():
break
fullImagePath = os.path.join(tmpDir, imagePath)
img = preprocess(fullImagePath, inputShape)
output = model.predict_on_batch(img)[0]
selection = np.argmax(output)
print(output[selection])
print(self.classesNames[int(selection)], self.classesNames[int(classIndex)])
if (output[selection] > self.slider.value()/100.
and int(selection) == int(classIndex)):
shutil.copy2(fullImagePath,
os.path.join(destinationDir,
imagePath))
print(os.path.join(destinationDir, imagePath))

if i >= len(os.listdir(tmpDir)) – 1:
progress.setValue(len(os.listdir(tmpDir)))
QMessageBox.about(self,
„Complete!“,
f“The images were gotten succesfully.“)

shutil.rmtree(tmpDir, ignore_errors=True)

if __name__ == „__main__“:
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QStringListModel

app = QApplication(sys.argv)

imgc = ImageCrawler()
imgc.show()

sys.exit(app.exec_())

Crawler_extra.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from icrawler.builtin import GoogleImageCrawler

def searchImages(keyword, storageLocation, max_num):
google_crawler = GoogleImageCrawler(
parser_threads=2,
downloader_threads=4,
storage={‚root_dir‘: storageLocation}
)
google_crawler.crawl(
keyword=keyword, max_num=max_num)

# searchImages(„dog“, „cat“, 10)

createfolders.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

import os

destinationFolderPath = „folders_test“
with open(„Sorins Computer Vision Application/Models/resnet50/sortedresnet“, ‚r‘) as f:
previousLine = None
for line in f:
line = line.strip()
if line == previousLine:
print(„duplicates“)
print(line)
previousLine = line
if not os.path.isdir(os.path.join(destinationFolderPath, line)):
print(„folder not created“)
print(line)

create_covid19_folders.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

import os
import numpy as np
import shutil

imagesFolder = „Data/covid-chestxray-dataset/images“
destinationFolder = „Data/covid-chestxray-dataset/sorted-images“

with open(„Data/covid-chestxray-dataset/metadata.csv“, ‚r‘) as f:
f.readline()
for line in f:
parsed = line.split(„,“)
imageName = parsed[16]
if imageName.split(„.“)[-1] in [„jpg“, „jpeg“, „png“]:
if parsed[4] == „COVID-19“ or parsed[4] == „\“COVID-19“:
assert imageName in os.listdir(imagesFolder)
shutil.copy2(os.path.join(imagesFolder, imageName), os.path.join(destinationFolder, „positives“, imageName))
else:
assert imageName in os.listdir(imagesFolder)
shutil.copy2(os.path.join(imagesFolder, imageName), os.path.join(destinationFolder, „negatives“, imageName))

data_augmentation_options.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QIntValidator, QPixmap, QImage
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QSlider, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow)
import os
import numpy as np
import cv2
from PIL import Image

class SliderWithValue(QWidget):
def __init__(self, orientation, parent=None):
super(SliderWithValue, self).__init__(parent=parent)
self.slider = QSlider(orientation)
self.value = self.slider.value
self.label = QLabel(str(self.value()))
self.valueChanged = self.slider.valueChanged
layout = QHBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.slider)
self.setLayout(layout)
self.setMaximum = self.slider.setMaximum
self.setMinimum = self.slider.setMinimum
self.setValue = self.slider.setValue
self.valueChanged.connect(self.updateLabel)
self.updateLabel(True)

def updateLabel(self, btn):
value = self.value()
if value < 10:
self.label.setText(„00″+str(value))
elif value < 100:
self.label.setText(„0″+str(value))
else:
self.label.setText(str(value))

def transformImage(angle, shear, translation, original_image, horizontalFlip=False, verticalFlip=False):
type_border = cv2.BORDER_CONSTANT
color_border = (255, 255, 255)

rows, cols, ch = original_image.shape

translation[0] = int(translation[0]*original_image.shape[0])
translation[1] = int(translation[1]*original_image.shape[1])

if verticalFlip:
original_image = original_image[::-1,:,:]
if horizontalFlip:
original_image = original_image[:,::-1,:]

#First: Necessary space for the rotation
M = cv2.getRotationMatrix2D((cols/2 + 1, rows/2 + 1), angle, 1)
cos_part = np.abs(M[0, 0])
sin_part = np.abs(M[0, 1])
new_cols = int((rows * sin_part) + (cols * cos_part)+0.5)
new_rows = int((rows * cos_part) + (cols * sin_part)+0.5)

#Second: Necessary space for the shear
new_cols += (abs(shear)*new_cols)
new_rows += (abs(shear)*new_rows)

#Calculate the space to add with border
up_down = abs(int((new_rows-rows+1)/2))
left_right = abs(int((new_cols-cols+1)/2))

final_image = cv2.copyMakeBorder(original_image, up_down, up_down, left_right, left_right, type_border, value = color_border)
rows, cols, ch = final_image.shape

#Application of the affine transform.
M_rot = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)
translat_center_x = -(shear*cols)/2
translat_center_y = -(shear*rows)/2

M = M_rot + np.float64([[0,shear,translation[0] + translat_center_x], [shear,0,translation[1] + translat_center_y]])
midwayImage = cv2.warpAffine(final_image , M, (cols,rows), borderMode = type_border, borderValue = color_border)
return midwayImage

class DataAugmentationOptions(QWidget):
def __init__(self, parent=None):
super(DataAugmentationOptions, self).__init__(parent)
title = QLabel(„Data Augmentation Options“)
self.horizontalFlipCheck = QCheckBox(„Flip horizontally“)
self.verticalFlipCheck = QCheckBox(„Flip vertically“)
widthShiftLabel = QLabel(„Max Width Shift (%)“)
self.widthShift = SliderWithValue(Qt.Horizontal)
self.widthShift.setMaximum(100)
self.widthShift.setMinimum(0)
self.widthShift.setValue(0)
heightShiftLabel = QLabel(„Max Height Shift (%)“)
self.heightShift = SliderWithValue(Qt.Horizontal)
self.heightShift.setMaximum(100)
self.heightShift.setMinimum(0)
self.heightShift.setValue(0)
angleLabel = QLabel(„Max Angle Shift (°)“)
self.angle = SliderWithValue(Qt.Horizontal)
self.angle.setMaximum(90)
self.angle.setMinimum(0)
self.angle.setValue(0)
shearLabel = QLabel(„Max Shear Shift (%)“)
self.shear = SliderWithValue(Qt.Horizontal)
self.shear.setMaximum(100)
self.shear.setMinimum(0)
self.shear.setValue(0)
self.uploadButton = QPushButton(„Upload Own Image“)
self.uploadButton.clicked.connect(self.changeImage)

sliders = [self.widthShift, self.heightShift, self.angle, self.shear]
for slider in sliders:
slider.valueChanged.connect(self.applyDistortion)
self.horizontalFlipCheck.stateChanged.connect(self.applyDistortion)
self.verticalFlipCheck.stateChanged.connect(self.applyDistortion)
mainLayout = QHBoxLayout()
leftLayout = QVBoxLayout()
leftLayout.addWidget(title)
leftLayout.addWidget(self.horizontalFlipCheck)
leftLayout.addWidget(self.verticalFlipCheck)
leftLayout.addWidget(widthShiftLabel)
leftLayout.addWidget(self.widthShift)
leftLayout.addWidget(heightShiftLabel)
leftLayout.addWidget(self.heightShift)
leftLayout.addWidget(angleLabel)
leftLayout.addWidget(self.angle)
leftLayout.addWidget(shearLabel)
leftLayout.addWidget(self.shear)
leftLayout.addWidget(self.uploadButton)
leftWidget = QWidget()
leftWidget.setLayout(leftLayout)
leftWidget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

self.iLabel = QLabel(self)
self.changeImage()

self.applyDistortion(True)
self.updateImage(self.originalImage)

mainLayout.addWidget(leftWidget)
mainLayout.addWidget(self.iLabel)
self.setLayout(mainLayout)

def updateImage(self, cvImg):
height, width, channel = cvImg.shape
bytesPerLine = 3 * width
qImg = QImage(cvImg.tobytes(), width, height, bytesPerLine, QImage.Format_RGB888)
pixmap01 = QPixmap.fromImage(qImg).scaledToHeight(500)

self.iLabel.setPixmap(pixmap01)

def applyDistortion(self, btn):
horizontalFlip = self.horizontalFlipCheck.isChecked()
verticalFlip = self.verticalFlipCheck.isChecked()
maxWidth = self.widthShift.value()*0.01
maxHeight = self.heightShift.value()*0.01
maxshear = -self.shear.value()*0.01
maxangle = self.angle.value()
newImage = transformImage(maxangle, maxshear, [maxWidth, maxHeight], self.originalImage, horizontalFlip=horizontalFlip, verticalFlip=verticalFlip)
self.updateImage(newImage)

def changeImage(self):
caption = „Select an image“
img = False
filename, _ = QFileDialog.getOpenFileName(caption=caption)
try:
print(filename)
img = cv2.imread(filename)
assert img is not None
except Exception as e:
img = False
caption = „The selected image couldn’t be loaded, try another file“
self.changeImage()
if img is not False:
self.originalImage = img[:, :, ::-1]
self.applyDistortion(True)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = DataAugmentationOptions()
imgc.show()

sys.exit(app.exec_())

deduper.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox)
import os
import cv2
import numpy as np
import shutil
from tqdm import tqdm
from imagededup.methods import PHash, DHash, WHash, AHash
import errno
from tensorflow import keras

hasherName2Hasher = {
„Perceptual Hashing“: PHash,
„Difference Hashing“: DHash,
„Wavelet Hashing“: WHash,
„Average Hashing“: AHash
}

hasherNames = hasherName2Hasher.keys()

def removeDuplicates(targetDirectory,
destinationDirectory,
duplicatesDirectory,
hasherName,
max_distance_threshold,
parent):

hasher = hasherName2Hasher[hasherName]()

try:
os.makedirs(duplicatesDirectory)
except OSError as e:
if e.errno != errno.EEXIST:
raise
try:
os.makedirs(destinationDirectory)
except OSError as e:
if e.errno != errno.EEXIST:
raise

progress = QProgressDialog(„Deduplicating files…“, „Abort“, 0, 2, parent)
progress.setWindowModality(Qt.WindowModal)
progress.setValue(0)

# Generate encodings for all images in an image directory
encodings = hasher.encode_images(image_dir=targetDirectory)
progress.setValue(1)

# Find duplicates using the generated encodings
duplicates = hasher.find_duplicates(encoding_map=encodings)
progress.setValue(0)

tqdmProg = tqdm(range(len(duplicates)))
progress.setMaximum(len(tqdmProg))

duplicateKeys = list(duplicates.keys())

for i in tqdmProg:
image = duplicateKeys[i]
countedFor = False
for dup in duplicateKeys[:i]:
if image in duplicates[dup]:
countedFor = True
break

progress.setValue(i)

if progress.wasCanceled():
break
i += 1
if not countedFor:
try:
os.makedirs(os.path.join(duplicatesDirectory, image))
except OSError as e:
if e.errno != errno.EEXIST:
raise
shutil.copy(os.path.join(targetDirectory, image),
os.path.join(destinationDirectory, image))
imageDuplicates = duplicates[image]
for dup in tqdm(imageDuplicates):
shutil.copy(os.path.join(targetDirectory, dup),
os.path.join(duplicatesDirectory, image, dup))

if i >= len(tqdmProg) – 1:
progress.setValue(len(tqdmProg))
QMessageBox.about(None,
„Complete!“,
f“The deduplication was completed successfully“)
else:
QMessageBox.about(None, „Incomplete“, „The deduplication was interrupted“)

# removeDuplicates(„all“,
# „imageDestination“,
# „all_duplicates“,
# hasherNames[1],
# 5)

class DeduperGUI(QDialog):
def __init__(self, parent=None):
super(DeduperGUI, self).__init__(parent)

# target folder selector
imageFolderLabel = QLabel(„&Images folder:“)
imageFolderButton = QPushButton(„Browse“)
imageFolderButton.clicked.connect(self.setImagesFolder)
self.imageFolderLine = QLineEdit(„Path to folder“)
imageFolderLabel.setBuddy(self.imageFolderLine)
targetFolderBox = QHBoxLayout()
targetFolderBox.addWidget(imageFolderLabel)
targetFolderBox.addWidget(self.imageFolderLine)
targetFolderBox.addWidget(imageFolderButton)
# destination folder selector
destFolderLabel = QLabel(„&Destination folder:“)
destFolderButton = QPushButton(„Browse“)
destFolderButton.clicked.connect(self.setDestFolder)
self.destFolderLine = QLineEdit(„Path to folder“)
destFolderLabel.setBuddy(self.destFolderLine)
destinationBox = QHBoxLayout()
destinationBox.addWidget(destFolderLabel)
destinationBox.addWidget(self.destFolderLine)
destinationBox.addWidget(destFolderButton)
# duplicates folder selector
dupFolderLabel = QLabel(„&Duplicates folder:“)
dupFolderButton = QPushButton(„Browse“)
dupFolderButton.clicked.connect(self.setDupFolder)
self.dupFolderLine = QLineEdit(„Path to folder“)
dupFolderLabel.setBuddy(self.dupFolderLine)
duplicatesBox = QHBoxLayout()
duplicatesBox.addWidget(dupFolderLabel)
duplicatesBox.addWidget(self.dupFolderLine)
duplicatesBox.addWidget(dupFolderButton)

# advanced settings
advancedSettingsLabel = QLabel(„Advanced Settings“)

# hashing combo selector
hashingLabel = QLabel(„Select a hashing method“)
self.hashingSelector = QComboBox()
self.hashingSelector.addItems(hasherNames)
hashingBox = QHBoxLayout()
hashingBox.addWidget(hashingLabel)
hashingBox.addWidget(self.hashingSelector)
# max_distance_threshold slider
self.thresholdLabel = QLabel(„Max Distance Threshold: 10“)
self.slider = QSlider(Qt.Horizontal)
self.slider.setMinimum(1)
self.slider.setMaximum(64)
self.slider.setValue(10)
self.slider.setTickInterval(1)
self.slider.valueChanged.connect(self.sliderValuechange)
thresholdBox = QHBoxLayout()
thresholdBox.addWidget(self.thresholdLabel)
thresholdBox.addWidget(self.slider)

deduplicateButton = QPushButton(„Deduplicate!“)
deduplicateButton.clicked.connect(self.deduplicate)

mainLayout = QVBoxLayout()
mainLayout.addLayout(targetFolderBox)
mainLayout.addLayout(destinationBox)
mainLayout.addLayout(duplicatesBox)
mainLayout.addWidget(advancedSettingsLabel)
mainLayout.addLayout(hashingBox)
mainLayout.addLayout(thresholdBox)
mainLayout.addWidget(deduplicateButton)
self.setLayout(mainLayout)

def deduplicate(self, btn):
hasherName = self.hashingSelector.currentText()
max_threshold_distance = self.slider.value()
targetFolder = self.imageFolderLine.text()
destinationFolder = self.destFolderLine.text()
duplicatesFolder = self.dupFolderLine.text()
removeDuplicates(targetFolder,
destinationFolder,
duplicatesFolder,
hasherName,
max_threshold_distance,
self)

def setImagesFolder(self, btn):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.imageFolderLine.setText(folder)

def setDestFolder(self, btn):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.destFolderLine.setText(folder)

def setDupFolder(self, btn):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.dupFolderLine.setText(folder)

def sliderValuechange(self, slider):
value = self.slider.value()
if value < 10:
value = f“0{value}“
self.thresholdLabel.setText(f“Max Distance Threshold: {value}“)

if __name__ == „__main__“:
import sys

app = QApplication(sys.argv)
setup = DeduperGUI()
setup.show()
sys.exit(app.exec_())

deep_learning_app.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow)
import os
import numpy as np
import deduper
import image_sorter
import classifier_crawler
import model_trainer
import apc_calculator2
import apec_calculator
import accuracy_calculator
import ttcapc_calculator
import ttcapec_calculator

class App(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle(‚Sorin\’s Computer Vision Application‘)

self.table_widget = MyTableWidget(self)
self.mainLayout = QVBoxLayout()
self.mainLayout.addWidget(self.table_widget)
appCredits = QLabel(„Application made by Sorin Liviu Jurj“)
appCredits.setStyleSheet(„font: 10pt Comic Sans MS“)
appCredits.setAlignment(Qt.AlignRight)
self.mainLayout.addWidget(appCredits)
self.setLayout(self.mainLayout)

self.show()

class MyTableWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)

self.tabs = QTabWidget()
self.tab1 = image_sorter.ImageSorter()
self.tab2 = deduper.DeduperGUI()
self.tab3 = classifier_crawler.ImageCrawler()
self.tab4 = model_trainer.ModelTrainer()
self.tab5 = apc_calculator2.ApcCalculator()
self.tab6 = accuracy_calculator.AccuracyCalculator()
self.tab7 = apec_calculator.ApecCalculator()
self.tab8 = ttcapc_calculator.TtcapcCalculator()
self.tab9 = ttcapec_calculator.TtcapecCalculator()

self.tabs.addTab(self.tab3, „Image Crawler“)
self.tabs.addTab(self.tab2, „Deduplication“)
self.tabs.addTab(self.tab1, „Images Sorter“)
self.tabs.addTab(self.tab4, „Model Trainer“)
self.tabs.addTab(self.tab6, „Accuracy Calculator“)
self.tabs.addTab(self.tab5, „APC Calculator“)
self.tabs.addTab(self.tab7, „APEC Calculator“)
self.tabs.addTab(self.tab8, „TTCAPC Calculator“)
self.tabs.addTab(self.tab9, „TTCAPEC Calculator“)

self.layout.addWidget(self.tabs)
self.layout.addStretch(1)
self.setLayout(self.layout)

if __name__ == ‚__main__‘:
import sys

app = QApplication(sys.argv)
setup = App()
sys.exit(app.exec_())

image_sorter.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox)
import os
from tensorflow import keras
import cv2
import numpy as np
import shutil
from tqdm import tqdm
from tensorflow.keras.applications.resnet50 import preprocess_input as resnet50_preprocess_input
from tensorflow.keras.preprocessing import image
from data_augmentation_options import transformImage

def mnistPreprocess(imagePath, shape,
maxWidth=0,
maxHeight=0,
maxangle=0,
maxshear=0,
verticalFlip=False,
horizontalFlip=False):
image = cv2.imread(imagePath)
angle = np.random.uniform(-maxangle, maxangle)
shear = np.random.uniform(-maxshear, maxshear)
widthS = np.random.uniform(-maxWidth, maxWidth)
heightS = np.random.uniform(-maxHeight, maxHeight)
verticalFlip = verticalFlip and np.random.uniform() > 0.5
horizontalFlip = horizontalFlip and np.random.uniform() > 0.5
image = transformImage(angle, shear, [widthS, heightS], image, horizontalFlip, verticalFlip)
assert image is not None
if image.shape[2] == shape[2]:
return np.expand_dims(cv2.resize(image, shape[:2]), 0)/255.
elif image.shape[2] == 3 and shape[2] == 1:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return np.expand_dims(np.expand_dims(cv2.resize(gray, shape[:2]), -1), 0)/255.
elif image.shape[2] == 4 and shape[2] == 1:
gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
return np.expand_dims(np.expand_dims(cv2.resize(gray, shape[:2]), -1), 0)/255.

def resnet50Preprocess(imagePath, shape,
maxWidth=0,
maxHeight=0,
maxangle=0,
maxshear=0,
verticalFlip=False,
horizontalFlip=False):
img = cv2.imread(imagePath)
if img.shape[-1] == 1:
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
elif img.shape[-1] == 4:
img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
elif img.shape[-1] == 3:
pass
else:
raise Exception(f“Channels of image {imagePath} = {img.shape[-1]}“)
augment = maxWidth>0 or maxHeight>0 or maxangle>0 or maxshear>0 or verticalFlip or horizontalFlip
if augment:
angle = np.random.uniform(-maxangle, maxangle)
shear = np.random.uniform(-maxshear, maxshear)
widthS = np.random.uniform(-maxWidth, maxWidth)
heightS = np.random.uniform(-maxHeight, maxHeight)
verticalFlip = verticalFlip and np.random.uniform() > 0.5
horizontalFlip = horizontalFlip and np.random.uniform() > 0.5

img = transformImage(angle, shear, [widthS, heightS], img, horizontalFlip, verticalFlip)
img = cv2.resize(img, shape[:2])
img = image.img_to_array(img)
img = np.expand_dims(img, axis=0)
img = resnet50_preprocess_input(img)
assert 3 == img.shape[-1], img.shape
return img

class ModelClassesSelection(QWidget):
def __init__(self, parent=None):
super(ModelClassesSelection, self).__init__(parent)
self.models = {
‚mnist‘: {
‚modelPath‘: ‚Models/mnist/mnist_model.h5‘,
‚modelClasses‘: ‚Models/mnist/mnist_classes‘,
‚inputShape‘: (28, 28, 1),
‚preprocessor‘: mnistPreprocess,
‚credit‘: ‚The mnist model was trained by Sorin Liviu Jurj‘
},
‚Custom‘: {
‚modelPath‘: “,
‚modelClasses‘: “,
‚inputShape‘: (1, 1, 1),
‚preprocessor‘: mnistPreprocess,
‚credit‘: ‚Custom model‘
},
‚Other‘: {
‚modelPath‘: “,
‚modelClasses‘: “,
‚inputShape‘: (1, 1, 1),
‚preprocessor‘: mnistPreprocess,
‚credit‘: ‚Custom model‘
},
‚resnet50‘: {
‚modelPath‘: ‚Models/resnet50/resnet50_model.h5‘,
‚modelClasses‘: ‚Models/resnet50/resnet50_classes‘,
‚inputShape‘: (224, 224, 3),
‚preprocessor‘: resnet50Preprocess,
‚credit‘: ‚Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun for architecture design \nImage-net.org DataSet for training‘
}
}

self.modelComboBox = QComboBox()
options = [‚mnist‘, ‚Other‘, ‚Custom‘, ‚resnet50‘]
self.modelComboBox.addItems(options)
self.modelComboBox.activated.connect(self.modelChosen)

self.sliderLabel = QLabel(„Confidence required: 50“)
self.slider = QSlider(Qt.Horizontal)
self.slider.setMinimum(0)
self.slider.setMaximum(99)
self.slider.setValue(50)
self.slider.setTickInterval(1)
self.slider.valueChanged.connect(self.sliderValuechange)

modelLabel = QLabel(„&Model:“)
modelLabel.setAlignment(Qt.AlignLeft)
modelLabel.setBuddy(self.modelComboBox)

self.labelComboLayout = QHBoxLayout()
self.labelComboLayout.addWidget(modelLabel)
self.labelComboLayout.addWidget(self.modelComboBox)
self.labelComboLayout.addWidget(self.sliderLabel)
self.labelComboLayout.addWidget(self.slider)
self.labelComboLayout.addStretch(1)
self.modelCreditLabel = QLabel(self.models[self.modelComboBox.currentText()][‚credit‘])
self.modelCreditLabel.setStyleSheet(„font: 10pt Comic Sans MS“)

self.topLayout = QVBoxLayout()
self.topLayout.addLayout(self.labelComboLayout)
self.topLayout.addWidget(self.modelCreditLabel)
self.topLayout.addStretch(1)

customLabel = QLabel(„Custom Model Configuration“)
modelFileLabel = QLabel(„Model &File:“)
modelFileButton = QPushButton(„Browse“)
modelFileButton.clicked.connect(self.setModelFile)
self.modelFileLine = QLineEdit(„Path to file“)
modelFileLabel.setBuddy(self.modelFileLine)

self.modelClassesLabel = QLabel(„Model &Classes:“)
self.modelClassesButton = QPushButton(„Browse“)
self.modelClassesButton.clicked.connect(self.setClassesFile)
self.modelClassesLine = QLineEdit(„Path to file“)
self.modelClassesLabel.setBuddy(self.modelClassesLine)

self.midLayout = QHBoxLayout()
self.midLayout.addWidget(modelFileLabel)
self.midLayout.addWidget(self.modelFileLine)
self.midLayout.addWidget(modelFileButton)
self.midLayout.addWidget(self.modelClassesLabel)
self.midLayout.addWidget(self.modelClassesLine)
self.midLayout.addWidget(self.modelClassesButton)
self.midLayout.addStretch(1)

self.mainLayout = QVBoxLayout()
self.mainLayout.addLayout(self.topLayout)
self.mainLayout.addWidget(customLabel)
self.mainLayout.addLayout(self.midLayout)

self.setLayout(self.mainLayout)

def modelChosen(self, combo):
self.modelCreditLabel.setText(self.models[self.modelComboBox.currentText()][‚credit‘])

def sliderValuechange(self, slider):
value = self.slider.value()
if value < 10:
value = f“0{value}“
self.sliderLabel.setText(f“Confidence required: {value}“)

def setModelFile(self, button):
folder = QFileDialog.getOpenFileName(self, „Select Custom Model File“)[0]
self.modelFileLine.setText(folder)

def setClassesFile(self, button):
folder = QFileDialog.getOpenFileName(self, „Select Custom Model Classes File“)[0]
self.modelClassesLine.setText(folder)

class ImageSorter(ModelClassesSelection):
def __init__(self, parent=None):
super(ImageSorter, self).__init__(parent)

imageFolderLabel = QLabel(„&Images folder:“)
imageFolderButton = QPushButton(„Browse“)
imageFolderButton.clicked.connect(self.setImagesFolder)
self.imageFolderLine = QLineEdit(„Path to folder“)
imageFolderLabel.setBuddy(self.imageFolderLine)

folderLineButton = QHBoxLayout()
folderLineButton.addWidget(self.imageFolderLine)
folderLineButton.addWidget(imageFolderButton)
folderLineButton.addStretch(1)

destinationFolderLabel = QLabel(„&Destination folder:“)
destinationFolderButton = QPushButton(„Browse“)
destinationFolderButton.clicked.connect(self.setDestinationFolder)
self.destinationFolderLine = QLineEdit(„Path to folder“)
destinationFolderLabel.setBuddy(self.destinationFolderLine)

destinationLineButton = QHBoxLayout()
destinationLineButton.addWidget(self.destinationFolderLine)
destinationLineButton.addWidget(destinationFolderButton)
destinationLineButton.addStretch(1)

self.topLayout.addWidget(imageFolderLabel)
self.topLayout.addLayout(folderLineButton)
self.topLayout.addWidget(destinationFolderLabel)
self.topLayout.addLayout(destinationLineButton)
self.topLayout.addStretch(1)

sortButton = QPushButton(„Sort!“)
sortButton.clicked.connect(self.sort)
self.mainLayout.addWidget(sortButton)

self.setWindowTitle(„Image sorting“)

def setImagesFolder(self, button):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.imageFolderLine.setText(folder)

def setDestinationFolder(self, button):
folder = str(QFileDialog.getExistingDirectory(self, „Select Destination Folder“))
self.destinationFolderLine.setText(folder)

def sort(self, button):
if not os.path.isdir((self.imageFolderLine.text())):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a valid folder with images to sort.‘)
elif not os.path.isdir((self.destinationFolderLine.text())):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a valid destination folder.‘)
elif self.modelComboBox.currentText() == „Other“:
QMessageBox.about(self, „Not implemented“, „The model is not implemented yet“)
else:
imageFolderPath = self.imageFolderLine.text()
destinationFolderPath = self.destinationFolderLine.text()
confidenceRequired = self.slider.value()/100.
if self.modelComboBox.currentText() == „Custom“:
if not os.path.isfile(self.modelFileLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a custom model file.‘)
elif not os.path.isfile(self.modelClassesLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(
‚Especify a custom model classes file.‘)
else:
print(self.modelFileLine.text(), self.modelClassesLine.text())
model = keras.models.load_model(self.modelFileLine.text())
for layer in model.layers:
inputShape = layer.input_shape[1:]
break
preprocess = resnet50Preprocess
modelClassesPath = self.modelClassesLine.text()
else:
modelName = self.modelComboBox.currentText()
modelPath = self.models[modelName][‚modelPath‘]
modelClassesPath = self.models[modelName][‚modelClasses‘]
assert os.path.isfile(modelClassesPath)
assert os.path.isfile(modelPath)

inputShape = self.models[modelName][‚inputShape‘]
preprocess = self.models[modelName][‚preprocessor‘]

model = keras.models.load_model(modelPath)
classes = []
with open(modelClassesPath, ‚r‘) as f:
for line in f:
line = line.strip()
classes.append(line)
if not os.path.isdir(os.path.join(destinationFolderPath, line)):
os.mkdir(os.path.join(destinationFolderPath, line))
if not os.path.isdir(os.path.join(destinationFolderPath, „Undetermined“)):
os.mkdir(os.path.join(destinationFolderPath, „Undetermined“))

tqdmProg = tqdm(os.listdir(imageFolderPath))
progress = QProgressDialog(„Copying files…“, „Abort Copy“, 0, len(tqdmProg), self)
progress.setWindowModality(Qt.WindowModal)
i = 0
total = 0.
undetermined = 0.
for imagePath in tqdmProg:
progress.setValue(i)

if progress.wasCanceled():
break
i += 1
fullImagePath = os.path.join(imageFolderPath, imagePath)
image = preprocess(fullImagePath, inputShape)
output = model.predict_on_batch(image)[0]
selection = np.argmax(output)
if output[selection] > confidenceRequired:
folder = str(classes[selection])
total += 1.
else:
folder = „Undetermined“
total += 1.
undetermined += 1.
shutil.copy2(fullImagePath, os.path.join(destinationFolderPath, folder, imagePath))
if i >= len(tqdmProg) – 1:
progress.setValue(len(tqdmProg))
undeterminedPorcentage = int((undetermined/total)*10000.)/100.
QMessageBox.about(self,
„Complete!“,
f“The sorting was completed successfully\n {undeterminedPorcentage}% of images undetermined“)
else:
QMessageBox.about(self, „Incomplete“, „The sorting was interrupted“)

if __name__ == ‚__main__‘:
import sys

app = QApplication(sys.argv)
setup = ImageSorter()
setup.show()
sys.exit(app.exec_())

main.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QMainWindow
from deep_learning_app import App

import sys

if __name__ == ‚__main__‘:
appctxt = ApplicationContext() # 1. Instantiate ApplicationContext
window = App()
window.show()
exit_code = appctxt.app.exec_() # 2. Invoke appctxt.app.exec_()
sys.exit(exit_code)

metric.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

import numpy as np
import matplotlib.pyplot as plt

def modifiedConsumption(consumption, accuracy, a=0.1):
„““
a is a meassure of the importance of consumption even as the
accuracy goes up
„““
return consumption*((1-a)*(1 – accuracy) + a)

def accuracyPerConsumption(consumption, accuracy, a=0.1, b=1):
„““
ranges from 0 to 1
100% accuracy and 0 consumption returns apc 1
0% accuracy returns apc 0 regardless
apc goes up with accuracy and down with consumption
consumption from innaccurate results is weighted more heavily
„““
return accuracy/(b*modifiedConsumption(consumption, accuracy, a) + 1)

def accuracyPerEnergyCost(energyCost, accuracy, a=0.1, b=1):
„““
ranges from 0 to 1
100% accuracy and 0 cost returns apec 1
0% accuracy returns apec 0 regardless
apec goes up with accuracy and down with consumption
cost from innaccurate results is weighted more heavily
„““
return accuracy/(b*modifiedConsumption(energyCost, accuracy, a) + 1)

if __name__ == „__main__“:

accuracies = [0.7, 0.8, 0.9, 0.95, 0.99, 0.995, 0.999]
consumptions = np.arange(0, 10, 0.01)
costs = np.arange(0, 5, 0.05)
betas = [5, 100, 1000]
alphas = [0, 0.25, 0.5]
apcs = []

# Default consumption

# for accuracy in accuracies:
# for consumption in consumptions:
# apc = accuracyPerConsumption(consumption, accuracy, b=1)
# apcs.append(apc)
# plt.plot(consumptions, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Consumption per inference (Watt-Hour)“)
# plt.ylabel(„APC“)
# plt.title(f“Accuracy Per Consumption“)
# plt.savefig(„apc_def.png“, dpi=800)

# Default costs

# for accuracy in accuracies:
# for consumption in costs:
# apc = accuracyPerConsumption(consumption, accuracy, b=10)
# apcs.append(apc)
# plt.plot(costs, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Cost per inference (cents EUR)“)
# plt.ylabel(„APEC“)
# plt.title(f“Accuracy Per Energy Cost“)
# plt.savefig(„apec_def.png“, dpi=800)

# alpha figures

# for alpha in alphas:
# for accuracy in accuracies:
# for consumption in consumptions:
# apc = accuracyPerConsumption(consumption, accuracy, a=alpha)
# apcs.append(apc)
# plt.plot(consumptions, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Consumption per inference (Watt-Hour)“)
# plt.ylabel(„APC“)
# plt.title(f“Accuracy Per Consumption (alpha={alpha})“)
# plt.savefig(f“apc_a{alpha}.png“, dpi=800)
# plt.clf()

# Beta figures

# for beta in betas:
# for accuracy in accuracies:
# for consumption in consumptions:
# apc = accuracyPerConsumption(consumption, accuracy, b=beta)
# apcs.append(apc)
# plt.plot(consumptions, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Consumption per inference (Watt-Hour)“)
# plt.ylabel(„APC“)
# plt.title(f“Accuracy Per Consumption (beta={beta})“)
# plt.savefig(f“apc_b{beta}.png“, dpi=800)
# plt.clf()

# Alpha figures (costs)

# for alpha in alphas:
# for accuracy in accuracies:
# for consumption in costs:
# apc = accuracyPerConsumption(consumption, accuracy, a=alpha, b=10)
# apcs.append(apc)
# plt.plot(costs, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Cost per inference (cents EUR)“)
# plt.ylabel(„APEC“)
# plt.title(f“Accuracy Per Energy Cost (alpha={alpha})“)
# plt.savefig(f“apec_a{alpha}.png“, dpi=800)
# plt.clf()

# Beta figures (costs)

# for beta in betas:
# for accuracy in accuracies:
# for consumption in costs:
# apc = accuracyPerConsumption(consumption, accuracy, b=beta)
# apcs.append(apc)
# plt.plot(costs, apcs, label=f“acc={accuracy}“)
# apcs = []
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Cost per inference (cents EUR)“)
# plt.ylabel(„APEC“)
# plt.title(f“Accuracy Per Energy Cost (beta={beta})“)
# plt.savefig(f“apec_b{beta}.png“, dpi=800)
# plt.clf()

# Default costs

consumptions = np.arange(0, 20, 0.1)
# for accuracy in accuracies:
# for consumption in consumptions:
# apc = accuracyPerConsumption(consumption, accuracy, b=0.1)
# apcs.append(apc)
# plt.plot(consumptions, apcs, label=f“acc={accuracy}“)
# apcs = []

# values = [(10.4, 0.9056), (10.6, 0.9341), (9.8, 0.9349), (8.88, 0.9454)]
# names = [„VGG-19“, „InceptionV3“, „ResNet-50“, „MobileNetV2″]
# for i, (c, acc) in enumerate(values):
# apc = accuracyPerConsumption(c, acc, b=0.1)
# plt.plot(c, apc, marker=“*“, label=names[i], linestyle=““)
# plt.legend(loc=“best“)
# plt.xlabel(„Energy Consumption per hour (WH)“)
# plt.ylabel(„APC“)
# plt.title(f“Accuracy Per Consumption“)
# plt.savefig(„apc_models.png“, dpi=800)
# plt.clf()

consumptions = np.arange(0, 0.035, 0.001)

wattPrice = 0.00305

for accuracy in accuracies:
for consumption in consumptions:
apc = accuracyPerConsumption(consumption, accuracy, b=50)
apcs.append(apc)
plt.plot(consumptions, apcs)
apcs = []

values = [(10.4, 0.9056), (10.6, 0.9341), (9.8, 0.9349), (8.88, 0.9454)]
names = [„VGG-19“, „InceptionV3“, „ResNet-50“, „MobileNetV2″]
for i, (c, acc) in enumerate(values):
apc = accuracyPerConsumption(c*wattPrice, acc, b=50)
print(apc)
plt.plot(c*wattPrice, apc, marker=“o“, label=names[i], linestyle=““)
for i, (c, acc) in enumerate(values):
c = 0
apc = accuracyPerConsumption(c*wattPrice, acc, b=50)
print(apc)
plt.plot(c*wattPrice, apc, marker=“*“, label=names[i]+“ solar powered“, linestyle=““)
plt.legend(loc=“best“)
plt.xlabel(„Energy Cost per hour (cents EUR)“)
plt.ylabel(„APEC“)
plt.title(f“Accuracy Per Energy Cost“)
plt.savefig(„apec_models.png“, dpi=800)
plt.clf()

model_trainer.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QIntValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow)
import os
import numpy as np
from image_sorter import ModelClassesSelection, resnet50Preprocess
from data_augmentation_options import transformImage, DataAugmentationOptions
import cv2
from tensorflow import keras
import time

class ModelTrainer(ModelClassesSelection):
def __init__(self, parent=None):
super(ModelTrainer, self).__init__(parent)

self.labelComboLayout.removeWidget(self.slider)
self.slider.deleteLater()
self.slider = None
self.labelComboLayout.removeWidget(self.sliderLabel)
self.sliderLabel.deleteLater()
self.sliderLabel = None

sortedImagesFolderLabel = QLabel(„&Sorted images folder:“)
sortedImagesFolderButton = QPushButton(„Browse“)
sortedImagesFolderButton.clicked.connect(self.setSortedFolder)
self.sortedImagesFolderLine = QLineEdit(„Path to folder“)
sortedImagesFolderLabel.setBuddy(self.sortedImagesFolderLine)

sortedImagesLineButton = QHBoxLayout()
sortedImagesLineButton.addWidget(self.sortedImagesFolderLine)
sortedImagesLineButton.addWidget(sortedImagesFolderButton)
sortedImagesLineButton.addStretch(1)

self.mainLayout.addWidget(sortedImagesFolderLabel)
self.mainLayout.addLayout(sortedImagesLineButton)

numberOfBatchesLabel = QLabel(„Number of training batches“)
self.numberOfBatchesLine = QLineEdit(„1“)
self.numberOfBatchesLine.setValidator(QIntValidator())
numberOfBatchesBox = QHBoxLayout()
numberOfBatchesBox.addWidget(numberOfBatchesLabel)
numberOfBatchesBox.addWidget(self.numberOfBatchesLine)

sizeOfBatchesLabel = QLabel(„Size of batches“)
self.sizeOfBatchesLine = QLineEdit(„10“)
self.sizeOfBatchesLine.setValidator(QIntValidator())
sizeOfBatchesBox = QHBoxLayout()
sizeOfBatchesBox.addWidget(sizeOfBatchesLabel)
sizeOfBatchesBox.addWidget(self.sizeOfBatchesLine)

self.mainLayout.addLayout(numberOfBatchesBox)
self.mainLayout.addLayout(sizeOfBatchesBox)

self.onlyArchitectureCheckbox = QCheckBox(„Use only architecture“, self)
self.mainLayout.addWidget(self.onlyArchitectureCheckbox)
self.trainButton = QPushButton(„Train model“)
self.trainButton.clicked.connect(self.selectAugmentation)
self.mainLayout.addWidget(self.trainButton)
self.setWindowTitle(„Model Trainer“)

def setSortedFolder(self, btn):
folder = str(QFileDialog.getExistingDirectory(self, „Select Images Folder“))
self.sortedImagesFolderLine.setText(folder)

def selectAugmentation(self, btn):
print(„select augment“)
self.dlg = QDialog()
dlgLayout = QVBoxLayout()
self.dlg.setLayout(dlgLayout)

self.augmentationOption = DataAugmentationOptions()

dlgLayout.addWidget(self.augmentationOption)
selectButton = QPushButton(„Continue“)
selectButton.clicked.connect(self.trainModel)
dlgLayout.addWidget(selectButton)
self.dlg.exec_()
print(„dlg show“)

def trainModel(self, btn):
self.dlg.close()
horizontalFlip = self.augmentationOption.horizontalFlipCheck.isChecked()
verticalFlip = self.augmentationOption.verticalFlipCheck.isChecked()
maxWidth = self.augmentationOption.widthShift.value()*0.01
maxHeight = self.augmentationOption.heightShift.value()*0.01
maxshear = self.augmentationOption.shear.value()*0.01
maxangle = self.augmentationOption.angle.value()
useOnlyArchitecture = self.onlyArchitectureCheckbox.isChecked()
print(horizontalFlip, verticalFlip, maxHeight, maxWidth, maxangle, maxshear)
selectedFolder = self.sortedImagesFolderLine.text()
if not os.path.isdir(selectedFolder):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a valid images folder.‘)
return 0
folderContents = os.listdir(selectedFolder)
for element in folderContents:
elementPath = os.path.join(selectedFolder, element)
if not os.path.isdir(elementPath):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚A valid images folder should only have sub folders.‘)
return 0
for folder in folderContents:
for element in os.listdir(os.path.join(selectedFolder, folder)):
elementPath = os.path.join(selectedFolder, folder, element)
isImage = True
try:
assert cv2.imread(elementPath) is not None, elementPath
except Exception as e:
isImage = False
print(e)
if not isImage:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Some of the subfolders containts stuff other than images.‘)
return 0

if self.modelComboBox.currentText() == „Custom“:
if not os.path.isfile(self.modelFileLine.text()):
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Especify a custom model file.‘)
return 0

model = keras.models.load_model(self.modelFileLine.text())
for layer in model.layers:
inputShape = layer.input_shape[1:]
break
preprocess = resnet50Preprocess
# modelClassesPath = self.modelClassesLine.text()
else:
modelName = self.modelComboBox.currentText()
modelPath = self.models[modelName][‚modelPath‘]
# modelClassesPath = self.models[modelName][‚modelClasses‘]
# assert os.path.isfile(modelClassesPath)
assert os.path.isfile(modelPath)

inputShape = self.models[modelName][‚inputShape‘]
preprocess = self.models[modelName][‚preprocessor‘]

model = keras.models.load_model(modelPath)

print(„dialog ended“)
if not useOnlyArchitecture:
model = swapOutputAndFreeze(model, len(os.listdir(selectedFolder)))
else:
model = swapOutput(model, len(os.listdir(selectedFolder)))

model.compile(optimizer=“adam“, loss=“categorical_crossentropy“)

numberOfBatches = int(self.numberOfBatchesLine.text())
batchSize = int(self.sizeOfBatchesLine.text())
generator = trainValGenerator(preprocess,
numberOfBatches,
batchSize,
selectedFolder,
inputShape,
maxWidth=maxWidth,
maxHeight=maxHeight,
maxangle=maxangle,
maxshear=maxshear,
verticalFlip=verticalFlip,
horizontalFlip=horizontalFlip)

progress = QProgressDialog(„Training…“, „Cancel“, 0, numberOfBatches,
parent=self)
progress.setWindowModality(Qt.WindowModal)
progress.forceShow()
progress.setValue(0)
i = 0
startTime = time.time()
for inputBatch, outputBatch in generator:
i += 1
progress.setValue(i)

if progress.wasCanceled():
break
model.fit(x=inputBatch, y=outputBatch, batch_size=batchSize,
verbose=False)

if i >= numberOfBatches – 1:
progress.setValue(numberOfBatches)
QMessageBox.about(self,
„Complete!“,
f“Model trained succesfully in {time.time() – startTime} seconds!“)
saveLocation, _ = QFileDialog.getSaveFileName(
None,
„Select location of model file“,
„model.h5“,
„H5 Model File (*.h5)“)
model.save(saveLocation)

def trainValGenerator(preprocess, numberOfBatches, batchSize, folder, shape,
maxWidth=0,
maxHeight=0,
maxangle=0,
maxshear=0,
verticalFlip=False,
horizontalFlip=False):
subfolders = list(os.listdir(folder))
for _ in range(numberOfBatches):
inputBatch = []
outputBatch = []
for __ in range(batchSize):
chosenClass = np.random.randint(0, len(subfolders))
chosenFolder = os.path.join(folder, subfolders[chosenClass])
imagesPaths = os.listdir(chosenFolder)
selectedImage = np.random.choice(imagesPaths)
x = preprocess(os.path.join(chosenFolder, selectedImage), shape,
maxWidth, maxHeight, maxangle, maxshear, verticalFlip, horizontalFlip)
inputBatch.append(x[0])
oneHotOutput = np.identity(len(subfolders))[chosenClass]
outputBatch.append(oneHotOutput)
yield np.array(inputBatch), np.array(outputBatch)

def swapOutputAndFreeze(model, outputDim):
output2 = keras.layers.Dense(outputDim, activation=“softmax“)(model.layers[-2].output)
newModel = keras.models.Model(inputs=model.input, outputs=output2)
for layer in newModel.layers[:-1]:
layer.trainable = False
return newModel

def swapOutput(model, outputDim):
output2 = keras.layers.Dense(outputDim, activation=“softmax“)(model.layers[-2].output)
newModel = keras.models.Model(inputs=model.input, outputs=output2)
return newModel

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = ModelTrainer()
imgc.show()

sys.exit(app.exec_())

ttcapc_calculator.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QDoubleValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow, QTableWidgetItem, QAbstractScrollArea)
import os
import numpy as np
from metric import accuracyPerConsumption
from accuracy_calculator import AccuracyCalculator

def rounded(delta, value):
return (int(value/delta)+0.5)*delta

class TtcapcCalculator(QDialog):
def __init__(self, parent=None):
super(TtcapcCalculator, self).__init__(parent)

self.topLayout = QVBoxLayout()

self.accuracyLabel = QLabel(„Model test accuracy (%)“)
self.accuracyLine = QLineEdit(„60“)
self.accuracyLine.textChanged.connect(self.recalculate)
self.accuracyLine.setValidator(QDoubleValidator())
self.calculateAccuracyButton = QPushButton(„Calculate“)
self.calculateAccuracyButton.clicked.connect(self.calculateAccuracy)
self.accuracyBox = QHBoxLayout()
self.accuracyBox.addWidget(self.accuracyLabel)
self.accuracyBox.addWidget(self.accuracyLine)
self.accuracyBox.addWidget(self.calculateAccuracyButton)

self.topLayout.addLayout(self.accuracyBox)

self.energyConsumptionLabel = QLabel(„Energy Consumption (WH)“)
self.energyConsumptionLine = QLineEdit(„1“)
self.energyConsumptionLine.textChanged.connect(self.recalculate)
self.energyConsumptionLine.setValidator(QDoubleValidator())
self.energyConsumptionBox = QHBoxLayout()
self.energyConsumptionBox.addWidget(self.energyConsumptionLabel)
self.energyConsumptionBox.addWidget(self.energyConsumptionLine)

self.trainingTimeLabel = QLabel(„Training Time (sec)“)
self.trainingTimeLine = QLineEdit(„10000“)
self.trainingTimeLine.textChanged.connect(self.recalculate)
self.trainingTimeLine.setValidator(QDoubleValidator())
self.trainingTimeBox = QHBoxLayout()
self.trainingTimeBox.addWidget(self.trainingTimeLabel)
self.trainingTimeBox.addWidget(self.trainingTimeLine)

self.topLayout.addLayout(self.energyConsumptionBox)
self.topLayout.addLayout(self.trainingTimeBox)

self.parametersBox = QGridLayout()

self.alphaLabel = QLabel(„Alpha (0 <= a <= 0.5)“)
self.alphaLine = QLineEdit(„0.1“)
self.alphaLine.textChanged.connect(self.recalculate)
self.alphaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.alphaLabel, 0, 0)
self.parametersBox.addWidget(self.alphaLine, 0, 1)

self.betaLabel = QLabel(„Beta (0 < b, recommended 1/average of consumptions)“)
self.betaLine = QLineEdit(„1“)
self.betaLine.textChanged.connect(self.recalculate)
self.betaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.betaLabel)
self.parametersBox.addWidget(self.betaLine)

self.accuracyDeltaLabel = QLabel(„Accuracy Delta“)
self.accuracyDeltaLine = QLineEdit(„0.1“)
self.accuracyDeltaLine.textChanged.connect(self.recalculate)
self.accuracyDeltaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.accuracyDeltaLabel)
self.parametersBox.addWidget(self.accuracyDeltaLine)

self.energyDeltaLabel = QLabel(„Energy Delta“)
self.energyDeltaLine = QLineEdit(„1“)
self.energyDeltaLine.textChanged.connect(self.recalculate)
self.energyDeltaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.energyDeltaLabel)
self.parametersBox.addWidget(self.energyDeltaLine)

self.topLayout.addLayout(self.parametersBox)

self.calculateButton = QPushButton(„Calculate TTCAPC“)
self.calculateButton.clicked.connect(self.calculateAPC)

self.mainLayout = QVBoxLayout()

self.mainLayout.addLayout(self.topLayout)

self.resultTable = QTableWidget(1, 10)
self.resultTable.setHorizontalHeaderLabels([„Accuracy“, „Energy Consumption“, „Alpha“, „Beta“, „Accuracy Delta“, „Energy Delta“, „Rounded Accuracy“, „Rounded Energy“, „Training Time“, „Closest APC“])
self.resultTable.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.resultTable.setVerticalHeaderLabels([„“])
self.resultTable.setItem(0, 0, QTableWidgetItem(„60“))
self.resultTable.setItem(0, 1, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 2, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 3, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 4, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 5, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 6, QTableWidgetItem(„60.05“))
self.resultTable.setItem(0, 7, QTableWidgetItem(„1.5“))
self.resultTable.setItem(0, 8, QTableWidgetItem(„10000“))
self.resultTable.setItem(0, 9, QTableWidgetItem(„-„))
self.resultTable.resizeColumnsToContents()

self.mainLayout.addWidget(self.resultTable)
self.mainLayout.addWidget(self.calculateButton)

self.setLayout(self.mainLayout)
self.setWindowTitle(„Time To Closest Accuracy Per Consumption Calculator“)

def recalculate(self, btn):
try:
acc = float(self.accuracyLine.text())
energy = float(self.energyConsumptionLine.text())
alpha = float(self.alphaLine.text())
beta = float(self.betaLine.text())
accDelta = float(self.accuracyDeltaLine.text())
energyDelta = float(self.energyDeltaLine.text())
rAcc = rounded(accDelta, acc)
rEnergy = rounded(energyDelta, energy)
trainingTime = float(self.trainingTimeLine.text())
self.resultTable.setItem(0, 0, QTableWidgetItem(str(acc)))
self.resultTable.setItem(0, 1, QTableWidgetItem(str(energy)))
self.resultTable.setItem(0, 2, QTableWidgetItem(str(alpha)))
self.resultTable.setItem(0, 3, QTableWidgetItem(str(beta)))
self.resultTable.setItem(0, 4, QTableWidgetItem(str(accDelta)))
self.resultTable.setItem(0, 5, QTableWidgetItem(str(energyDelta)))
self.resultTable.setItem(0, 6, QTableWidgetItem(str(rAcc)))
self.resultTable.setItem(0, 7, QTableWidgetItem(str(rEnergy)))
self.resultTable.setItem(0, 8, QTableWidgetItem(str(trainingTime)))
apc = accuracyPerConsumption(rEnergy, rAcc/100, alpha, beta)
self.resultTable.setItem(0, 9, QTableWidgetItem(str(int(10000*apc)/10000)))
self.resultTable.resizeColumnsToContents()
except:
pass

def calculateAccuracy(self, btn):
self.accCalc = QDialog()
self.accCalc.setWindowModality(Qt.WindowModal)
self.accLayout = QVBoxLayout()
self.calculator = AccuracyCalculator(target=self.accuracyLine)
self.accLayout.addWidget(self.calculator)
self.accCalc.setLayout(self.accLayout)
self.accCalc.show()
# self.accuracyLine.setText(„99.9″)

def passAccuracy(self, calculator):
self.accuracyLine.setText(str(calculator.results))

def calculateAPC(self, btn):
accuracy = float(self.accuracyLine.text())
if accuracy < 0 or accuracy > 100:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Accuracy (%) should be between 0 and 100.‘)
return 0

energyConsumption = float(self.energyConsumptionLine.text())
if energyConsumption < 1:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Batch size must be greater than 0‘)
return 0

alpha = float(self.alphaLine.text())
if alpha < 0 or alpha > 0.5:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Alpha must be between 0 and 0.5‘)
return 0

beta = float(self.betaLine.text())
if beta <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Beta must be greater than 0‘)
return 0

accDelta = float(self.accuracyDeltaLine.text())
energyDelta = float(self.energyDeltaLine.text())
rAcc = rounded(accDelta, accuracy)
rEnergy = rounded(energyDelta, energyConsumption)
trainingTime = float(self.trainingTimeLine.text())
print(f“alpha={alpha}, beta={beta}, accuracy={accuracy}, energyConsumption={energyConsumption}“)
apc = accuracyPerConsumption(rEnergy, rAcc/100, a=alpha, b=beta)
print(f“accuracy per consumption = {apc}“)
QMessageBox.about(self,
„Time To Closest Accuracy per Consumption succesfully calculated!“,
f“““Alpha = {alpha}
Beta = {beta}

Energy Consumption = {energyConsumption}
Energy Delta = {energyDelta}
Rounded Energy = {rEnergy}

Accuracy = {accuracy}%
Accuracy Delta = {accDelta}
Rounded Accuracy = {rAcc}%

Training Time = {trainingTime}
Closest Accuracy Per Consumption = {int(apc*10000)/100}%“““)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = TtcapcCalculator()
imgc.show()

sys.exit(app.exec_())

ttcapec_calculator.py

„““
Author: Sorin Liviu Jurj
This code is written in Python for our paper called „Deep Learning-Based Computer Vision Application with Multiple Built-In Data Science-Oriented Capabilities“. More details can be found here: https://www.jurj.de/deep-learning-based-computer-vision-application-with-multiple-built-in-data-science-oriented-capabilities
„““

from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5.QtGui import QDoubleValidator
from PyQt5.QtWidgets import (
QApplication, QCheckBox, QComboBox, QDateTimeEdit,
QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
QVBoxLayout, QWidget, QFileDialog, QErrorMessage, QProgressDialog,
QMessageBox, QMainWindow, QTableWidgetItem, QAbstractScrollArea)
import os
import numpy as np
from metric import accuracyPerConsumption
from accuracy_calculator import AccuracyCalculator

def rounded(delta, value):
return (int(value/delta)+0.5)*delta

class TtcapecCalculator(QDialog):
def __init__(self, parent=None):
super(TtcapecCalculator, self).__init__(parent)

self.topLayout = QVBoxLayout()

self.accuracyLabel = QLabel(„Model test accuracy (%)“)
self.accuracyLine = QLineEdit(„60“)
self.accuracyLine.textChanged.connect(self.recalculate)
self.accuracyLine.setValidator(QDoubleValidator())
self.calculateAccuracyButton = QPushButton(„Calculate“)
self.calculateAccuracyButton.clicked.connect(self.calculateAccuracy)
self.accuracyBox = QHBoxLayout()
self.accuracyBox.addWidget(self.accuracyLabel)
self.accuracyBox.addWidget(self.accuracyLine)
self.accuracyBox.addWidget(self.calculateAccuracyButton)

self.topLayout.addLayout(self.accuracyBox)

self.energyConsumptionLabel = QLabel(„Energy Consumption (WH)“)
self.energyConsumptionLine = QLineEdit(„1“)
self.energyConsumptionLine.textChanged.connect(self.recalculate)
self.energyConsumptionLine.setValidator(QDoubleValidator())
self.energyConsumptionBox = QHBoxLayout()
self.energyConsumptionBox.addWidget(self.energyConsumptionLabel)
self.energyConsumptionBox.addWidget(self.energyConsumptionLine)

self.topLayout.addLayout(self.energyConsumptionBox)

self.energyCostLabel = QLabel(„Energy Cost (EUR cents per WH)“)
self.energyCostLine = QLineEdit(„0.001“)
self.energyCostLine.textChanged.connect(self.recalculate)
self.energyCostLine.setValidator(QDoubleValidator())
self.energyCostBox = QHBoxLayout()
self.energyCostBox.addWidget(self.energyCostLabel)
self.energyCostBox.addWidget(self.energyCostLine)

self.topLayout.addLayout(self.energyCostBox)

self.trainingTimeLabel = QLabel(„Training Time (sec)“)
self.trainingTimeLine = QLineEdit(„10000“)
self.trainingTimeLine.textChanged.connect(self.recalculate)
self.trainingTimeLine.setValidator(QDoubleValidator())
self.trainingTimeBox = QHBoxLayout()
self.trainingTimeBox.addWidget(self.trainingTimeLabel)
self.trainingTimeBox.addWidget(self.trainingTimeLine)

self.topLayout.addLayout(self.trainingTimeBox)

self.parametersBox = QGridLayout()

self.alphaLabel = QLabel(„Alpha (0 <= a <= 0.5)“)
self.alphaLine = QLineEdit(„0.1“)
self.alphaLine.textChanged.connect(self.recalculate)
self.alphaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.alphaLabel, 0, 0)
self.parametersBox.addWidget(self.alphaLine, 0, 1)

self.betaLabel = QLabel(„Beta (0 < b, recommended 1/average of costs)“)
self.betaLine = QLineEdit(„50“)
self.betaLine.textChanged.connect(self.recalculate)
self.betaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.betaLabel)
self.parametersBox.addWidget(self.betaLine)

self.accuracyDeltaLabel = QLabel(„Accuracy Delta“)
self.accuracyDeltaLine = QLineEdit(„0.1“)
self.accuracyDeltaLine.textChanged.connect(self.recalculate)
self.accuracyDeltaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.accuracyDeltaLabel)
self.parametersBox.addWidget(self.accuracyDeltaLine)

self.energyDeltaLabel = QLabel(„Energy Delta“)
self.energyDeltaLine = QLineEdit(„1“)
self.energyDeltaLine.textChanged.connect(self.recalculate)
self.energyDeltaLine.setValidator(QDoubleValidator())

self.parametersBox.addWidget(self.energyDeltaLabel)
self.parametersBox.addWidget(self.energyDeltaLine)

self.topLayout.addLayout(self.parametersBox)

self.calculateButton = QPushButton(„Calculate TTCAPEC“)
self.calculateButton.clicked.connect(self.calculateAPC)

self.mainLayout = QVBoxLayout()

self.mainLayout.addLayout(self.topLayout)

self.resultTable = QTableWidget(1, 11)
self.resultTable.setHorizontalHeaderLabels([„Accuracy“, „Energy Cost“, „Alpha“, „Beta“, „Accuracy Delta“, „Energy Delta“, „Rounded Accuracy“, „Rounded Energy“, „Training Time“, „Closest APEC“, „Closest APEC Green Powered“])
self.resultTable.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.resultTable.setVerticalHeaderLabels([„“])
self.resultTable.setItem(0, 0, QTableWidgetItem(„60“))
self.resultTable.setItem(0, 1, QTableWidgetItem(„0.001“))
self.resultTable.setItem(0, 2, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 3, QTableWidgetItem(„50“))
self.resultTable.setItem(0, 4, QTableWidgetItem(„0.1“))
self.resultTable.setItem(0, 5, QTableWidgetItem(„1“))
self.resultTable.setItem(0, 6, QTableWidgetItem(„60.05“))
self.resultTable.setItem(0, 7, QTableWidgetItem(„1.5“))
self.resultTable.setItem(0, 8, QTableWidgetItem(„10000“))
self.resultTable.setItem(0, 9, QTableWidgetItem(„-„))
self.resultTable.setItem(0, 10, QTableWidgetItem(„-„))
self.resultTable.resizeColumnsToContents()

self.mainLayout.addWidget(self.resultTable)
self.mainLayout.addWidget(self.calculateButton)

self.setLayout(self.mainLayout)
self.setWindowTitle(„Time To Accuracy Per Energy Cost Calculator“)

def recalculate(self, btn):
try:
acc = float(self.accuracyLine.text())
energyCost = float(self.energyCostLine.text())
energy = float(self.energyConsumptionLine.text())*energyCost
alpha = float(self.alphaLine.text())
beta = float(self.betaLine.text())
accDelta = float(self.accuracyDeltaLine.text())
energyDelta = float(self.energyDeltaLine.text())
rAcc = rounded(accDelta, acc)
rEnergy = rounded(energyDelta, energy)
trainingTime = float(self.trainingTimeLine.text())
self.resultTable.setItem(0, 0, QTableWidgetItem(str(acc)))
self.resultTable.setItem(0, 1, QTableWidgetItem(str(energy)))
self.resultTable.setItem(0, 2, QTableWidgetItem(str(alpha)))
self.resultTable.setItem(0, 3, QTableWidgetItem(str(beta)))
self.resultTable.setItem(0, 4, QTableWidgetItem(str(accDelta)))
self.resultTable.setItem(0, 5, QTableWidgetItem(str(energyDelta)))
self.resultTable.setItem(0, 6, QTableWidgetItem(str(rAcc)))
self.resultTable.setItem(0, 7, QTableWidgetItem(str(rEnergy)))
self.resultTable.setItem(0, 8, QTableWidgetItem(str(trainingTime)))
apc = accuracyPerConsumption(rEnergy, rAcc/100, alpha, beta)
self.resultTable.setItem(0, 9, QTableWidgetItem(str(int(10000*apc)/10000)))
self.resultTable.setItem(0, 10, QTableWidgetItem(str(rAcc)))
self.resultTable.resizeColumnsToContents()
except:
pass

def calculateAccuracy(self, btn):
self.accCalc = QDialog()
self.accCalc.setWindowModality(Qt.WindowModal)
self.accLayout = QVBoxLayout()
self.calculator = AccuracyCalculator(target=self.accuracyLine)
self.accLayout.addWidget(self.calculator)
self.accCalc.setLayout(self.accLayout)
self.accCalc.show()
# self.accuracyLine.setText(„99.9″)

def passAccuracy(self, calculator):
self.accuracyLine.setText(str(calculator.results))

def calculateAPC(self, btn):
accuracy = float(self.accuracyLine.text())
if accuracy < 0 or accuracy > 100:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Accuracy (%) should be between 0 and 100.‘)
return 0

energyConsumption = float(self.energyConsumptionLine.text())
if energyConsumption < 1:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Batch size must be greater than 0‘)
return 0

alpha = float(self.alphaLine.text())
if alpha < 0 or alpha > 0.5:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Alpha must be between 0 and 0.5‘)
return 0

beta = float(self.betaLine.text())
if beta <= 0:
error_dialog = QErrorMessage(self)
error_dialog.showMessage(‚Beta must be greater than 0‘)
return 0

accDelta = float(self.accuracyDeltaLine.text())
energyCost = float(self.energyCostLine.text())
energy = energyConsumption*energyCost
energyDelta = float(self.energyDeltaLine.text())
rAcc = rounded(accDelta, accuracy)
rEnergy = rounded(energyDelta, energy)
trainingTime = float(self.trainingTimeLine.text())
print(f“alpha={alpha}, beta={beta}, accuracy={accuracy}, energyCost={energy}“)
apc = accuracyPerConsumption(rEnergy, rAcc/100, a=alpha, b=beta)
print(f“accuracy per energy cost = {apc}“)
QMessageBox.about(self,
„Time To Closest Accuracy per Energy Cost succesfully calculated!“,
f“““Alpha = {alpha}
Beta = {beta}

Energy Consumption = {energyConsumption}
Energy Cost per WH = {energyCost}
Energy Consumption Cost = {energy}
Energy Delta = {energyDelta}
Rounded Energy = {rEnergy}

Accuracy = {accuracy}%
Accuracy Delta = {accDelta}
Rounded Accuracy = {rAcc}%

Training Time = {trainingTime}
Closest Accuracy Per Energy Cost = {int(apc*10000)/100}%“““)

if __name__ == „__main__“:
import sys
app = QApplication(sys.argv)

imgc = TtcapecCalculator()
imgc.show()

sys.exit(app.exec_())

 

Leave a Comment

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahren Sie mehr darüber, wie Ihre Kommentardaten verarbeitet werden .