刪除 demogui 原先的 folder
This commit is contained in:
parent
a8ed1ac592
commit
c12bbd29fd
File diff suppressed because it is too large
Load Diff
@ -1,142 +0,0 @@
|
||||
import os
|
||||
import kp
|
||||
import shutil
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget, QPushButton, QFileDialog, QHBoxLayout
|
||||
from utils import preprocess_image, perform_inference, post_process_inference, process_image, cosine_similarity, compare_images_cosine_similarity, cluster_images_with_dbscan, list_image_files
|
||||
|
||||
|
||||
class ConsoleWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("Demo Console")
|
||||
self.setGeometry(100, 100, 600, 400)
|
||||
|
||||
# Console area for log messages
|
||||
self.text_edit = QTextEdit(self)
|
||||
self.text_edit.setReadOnly(True)
|
||||
|
||||
# Button to start the declutter process
|
||||
self.start_button = QPushButton("Select Directories and Start")
|
||||
self.start_button.clicked.connect(self.select_directories_and_start)
|
||||
|
||||
# Layout setup
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.text_edit)
|
||||
layout.addWidget(self.start_button)
|
||||
container = QWidget()
|
||||
container.setLayout(layout)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
# Variables to store directory paths
|
||||
self.input_directory = ''
|
||||
self.to_keep_directory = ''
|
||||
self.to_delete_directory = ''
|
||||
|
||||
def print_message(self, message):
|
||||
self.text_edit.append(message)
|
||||
QApplication.processEvents() # Update the GUI immediately
|
||||
|
||||
def select_directories_and_start(self):
|
||||
# Open directory dialog to select directories
|
||||
self.input_directory = QFileDialog.getExistingDirectory(self, "Select Input Directory")
|
||||
self.to_keep_directory = QFileDialog.getExistingDirectory(self, "Select 'To Keep' Directory")
|
||||
self.to_delete_directory = QFileDialog.getExistingDirectory(self, "Select 'To Delete' Directory")
|
||||
|
||||
if self.input_directory and self.to_keep_directory and self.to_delete_directory:
|
||||
self.print_message(f"Selected directories:\nInput: {self.input_directory}\nTo Keep: {self.to_keep_directory}\nTo Delete: {self.to_delete_directory}")
|
||||
declutter_photo_album(self.input_directory, self.to_keep_directory, self.to_delete_directory, self)
|
||||
|
||||
def declutter_photo_album(input_directory, to_keep_directory, to_delete_directory, console):
|
||||
def log(message):
|
||||
console.print_message(message)
|
||||
|
||||
log("CONNECTING DEVICE")
|
||||
|
||||
DECLUTTER_MODEL_FILE_PATH = './resnet34_feature_extractor.nef'
|
||||
PHOTO_QUALITY_SCORER_PATH = './photo_scorer_520.nef'
|
||||
|
||||
# Ensure output directories exist
|
||||
os.makedirs(input_directory, exist_ok=True)
|
||||
os.makedirs(to_keep_directory, exist_ok=True)
|
||||
os.makedirs(to_delete_directory, exist_ok=True)
|
||||
|
||||
# Scan for devices
|
||||
device_descriptors = kp.core.scan_devices()
|
||||
if device_descriptors.device_descriptor_number > 0:
|
||||
usb_port_id = device_descriptors.device_descriptor_list[0].usb_port_id
|
||||
log(f"Device connected at USB port ID: {usb_port_id}")
|
||||
else:
|
||||
log('Error: no Kneron device connected.')
|
||||
return
|
||||
|
||||
# Connect to device
|
||||
device_group = kp.core.connect_devices(usb_port_ids=[22])
|
||||
kp.core.set_timeout(device_group=device_group, milliseconds=5000)
|
||||
|
||||
SCPU_FW_PATH = '../../res/firmware/KL520/fw_scpu.bin'
|
||||
NCPU_FW_PATH = '../../res/firmware/KL520/fw_ncpu.bin'
|
||||
kp.core.load_firmware_from_file(device_group=device_group,
|
||||
scpu_fw_path=SCPU_FW_PATH,
|
||||
ncpu_fw_path=NCPU_FW_PATH)
|
||||
|
||||
# Filter low-quality images
|
||||
log("FILTERING LOW QUALITY IMAGES")
|
||||
model_nef_descriptor = kp.core.load_model_from_file(device_group=device_group,
|
||||
file_path=PHOTO_QUALITY_SCORER_PATH)
|
||||
to_keep_images = []
|
||||
images = list_image_files(input_directory)
|
||||
for image_file_path in images:
|
||||
score = process_image(device_group, model_nef_descriptor, image_file_path)
|
||||
log(f"Image: {image_file_path}, Score: {score}")
|
||||
if score > 0.5:
|
||||
log(" Low quality: recommend to delete")
|
||||
shutil.copy(image_file_path, to_delete_directory)
|
||||
else:
|
||||
log(" Accepted quality image")
|
||||
to_keep_images.append(image_file_path)
|
||||
|
||||
# Compare photo similarity
|
||||
log("COMPARING PHOTO SIMILARITY")
|
||||
model_nef_descriptor = kp.core.load_model_from_file(device_group=device_group,
|
||||
file_path=DECLUTTER_MODEL_FILE_PATH)
|
||||
|
||||
images = to_keep_images
|
||||
clusters = cluster_images_with_dbscan(images, device_group, model_nef_descriptor)
|
||||
|
||||
# Organize clustered images into directories
|
||||
for cluster_index, cluster in enumerate(clusters):
|
||||
cluster_dir = os.path.join(to_delete_directory, f"cluster_{cluster_index}")
|
||||
os.makedirs(cluster_dir, exist_ok=True)
|
||||
log(f"Cluster #{cluster_index}")
|
||||
for image_file_path in cluster:
|
||||
log(image_file_path)
|
||||
shutil.copy(image_file_path, cluster_dir)
|
||||
|
||||
# Move images not in any cluster to 'to_keep' directory
|
||||
non_clustered_images = set(images) - set(img for cluster in clusters for img in cluster)
|
||||
for image_file_path in non_clustered_images:
|
||||
shutil.copy(image_file_path, to_keep_directory)
|
||||
|
||||
# Decide which photos to keep in clusters
|
||||
log("DECIDING WHICH PHOTO TO KEEP")
|
||||
for cluster_index, cluster in enumerate(clusters):
|
||||
cluster_scores = []
|
||||
for image_file_path in cluster:
|
||||
score = process_image(device_group, model_nef_descriptor, image_file_path)
|
||||
cluster_scores.append((image_file_path, score))
|
||||
|
||||
# Sort by score in descending order and keep the top 2
|
||||
cluster_scores.sort(key=lambda x: x[1], reverse=True)
|
||||
top_photos = cluster_scores[:2]
|
||||
|
||||
log(f"In cluster {cluster_index}")
|
||||
for image_file_path, _ in top_photos:
|
||||
log(f"Keep image: {image_file_path}")
|
||||
shutil.copy(image_file_path, to_keep_directory)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
console = ConsoleWindow()
|
||||
console.show()
|
||||
sys.exit(app.exec_())
|
||||
@ -1,296 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Demo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Set Up\n",
|
||||
"prerequisites\n",
|
||||
"- python 3.12\n",
|
||||
"\n",
|
||||
"``` shell\n",
|
||||
"$ cd ./package/{platform}/\n",
|
||||
"$ pip install KneronPLUS-2.3.0-py3-none-any.whl\n",
|
||||
"$ pip install --force-reinstall KneronPLUS-2.3.0-py3-none-any.whl\n",
|
||||
"$ pip install opencv-pythn\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Connect KL520"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import cv2\n",
|
||||
"import kp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"22\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"device_descriptors = kp.core.scan_devices()\n",
|
||||
"\n",
|
||||
"if 0 < device_descriptors.device_descriptor_number:\n",
|
||||
" usb_port_id = device_descriptors.device_descriptor_list[0].usb_port_id\n",
|
||||
" print(usb_port_id)\n",
|
||||
"else:\n",
|
||||
" print('Error: no Kneron device connect.')\n",
|
||||
" exit(0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"device_group = kp.core.connect_devices(usb_port_ids=[22])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kp.core.set_timeout(device_group=device_group,\n",
|
||||
" milliseconds=5000)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Load firmware, model, and test image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SCPU_FW_PATH = '../../res/firmware/KL520/fw_scpu.bin'\n",
|
||||
"NCPU_FW_PATH = '../../res/firmware/KL520/fw_ncpu.bin'\n",
|
||||
"kp.core.load_firmware_from_file(device_group=device_group,\n",
|
||||
" scpu_fw_path=SCPU_FW_PATH,\n",
|
||||
" ncpu_fw_path=NCPU_FW_PATH)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"MODEL_FILE_PATH = './photo_scorer_520.nef'\n",
|
||||
"model_nef_descriptor = kp.core.load_model_from_file(device_group=device_group,\n",
|
||||
" file_path=MODEL_FILE_PATH)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### pre-processing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"IMAGE_FILE_PATH = './test.jpg'\n",
|
||||
"\n",
|
||||
"img = cv2.imread(filename=IMAGE_FILE_PATH)\n",
|
||||
"img_bgr565 = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2BGR565)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"generic_inference_input_descriptor = kp.GenericImageInferenceDescriptor(\n",
|
||||
" model_id=model_nef_descriptor.models[0].id,\n",
|
||||
" inference_number=0,\n",
|
||||
" input_node_image_list=[\n",
|
||||
" kp.GenericInputNodeImage(\n",
|
||||
" image=img_bgr565,\n",
|
||||
" image_format=kp.ImageFormat.KP_IMAGE_FORMAT_RGB565,\n",
|
||||
" resize_mode=kp.ResizeMode.KP_RESIZE_ENABLE,\n",
|
||||
" padding_mode=kp.PaddingMode.KP_PADDING_CORNER,\n",
|
||||
" normalize_mode=kp.NormalizeMode.KP_NORMALIZE_KNERON\n",
|
||||
" )\n",
|
||||
" ]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"header\": {\n",
|
||||
" \"inference_number\": 0,\n",
|
||||
" \"crop_number\": 0,\n",
|
||||
" \"num_output_node\": 1,\n",
|
||||
" \"product_id\": 256,\n",
|
||||
" \"num_hw_pre_proc_info\": 1,\n",
|
||||
" \"hw_pre_proc_info_list\": {\n",
|
||||
" \"0\": {\n",
|
||||
" \"img_width\": 1200,\n",
|
||||
" \"img_height\": 800,\n",
|
||||
" \"resized_img_width\": 224,\n",
|
||||
" \"resized_img_height\": 149,\n",
|
||||
" \"pad_top\": 0,\n",
|
||||
" \"pad_bottom\": 75,\n",
|
||||
" \"pad_left\": 0,\n",
|
||||
" \"pad_right\": 0,\n",
|
||||
" \"model_input_width\": 224,\n",
|
||||
" \"model_input_height\": 224,\n",
|
||||
" \"crop_area\": {\n",
|
||||
" \"crop_box_index\": 0,\n",
|
||||
" \"x\": 0,\n",
|
||||
" \"y\": 0,\n",
|
||||
" \"width\": 0,\n",
|
||||
" \"height\": 0\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"raw_result\": {\n",
|
||||
" \"buffer_size\": 388\n",
|
||||
" }\n",
|
||||
"}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"kp.inference.generic_image_inference_send(device_group=device_group,\n",
|
||||
" generic_inference_input_descriptor=generic_inference_input_descriptor)\n",
|
||||
"generic_raw_result = kp.inference.generic_image_inference_receive(device_group=device_group)\n",
|
||||
"print(generic_raw_result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[{\n",
|
||||
" \"width\": 1,\n",
|
||||
" \"height\": 1,\n",
|
||||
" \"channel\": 1,\n",
|
||||
" \"channels_ordering\": \"ChannelOrdering.KP_CHANNEL_ORDERING_CHW\",\n",
|
||||
" \"num_data\": 1,\n",
|
||||
" \"ndarray\": [\n",
|
||||
" \"[[[[0.71443015]]]]\"\n",
|
||||
" ]\n",
|
||||
"}]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"inf_node_output_list = []\n",
|
||||
"\n",
|
||||
"for node_idx in range(generic_raw_result.header.num_output_node):\n",
|
||||
" inference_float_node_output = kp.inference.generic_inference_retrieve_float_node(node_idx=node_idx,\n",
|
||||
" generic_raw_result=generic_raw_result,\n",
|
||||
" channels_ordering=kp.ChannelOrdering.KP_CHANNEL_ORDERING_CHW)\n",
|
||||
" inf_node_output_list.append(inference_float_node_output)\n",
|
||||
"\n",
|
||||
"print(inf_node_output_list)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### post-processing\n",
|
||||
"Kneron PLUS python version doesn't support on-NPU post-processing, so this step is demonstrated here"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"The score of this photo is 0.7144301533699036\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"nd_array = inf_node_output_list[0].ndarray\n",
|
||||
"number = float(nd_array.flatten()[0])\n",
|
||||
"\n",
|
||||
"print(\"The score of this photo is\", number)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
720
demogui/main.py
720
demogui/main.py
@ -1,720 +0,0 @@
|
||||
import kp
|
||||
import cv2, os, shutil, sys
|
||||
from enum import Enum
|
||||
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLabel, QPushButton,
|
||||
QComboBox, QFileDialog, QMessageBox, QHBoxLayout, QDialog, QListWidget,
|
||||
QScrollArea, QFrame, QListWidgetItem, QTextEdit)
|
||||
from PyQt5.QtSvg import QSvgWidget
|
||||
from PyQt5.QtMultimedia import QCamera, QCameraImageCapture, QCameraInfo, QMediaRecorder, QAudioRecorder
|
||||
from PyQt5.QtMultimediaWidgets import QVideoWidget
|
||||
from PyQt5.QtGui import QPixmap, QMovie
|
||||
from PyQt5.QtCore import Qt, QTimer, QUrl
|
||||
|
||||
# Global Constants
|
||||
UXUI_ASSETS = "../../uxui/"
|
||||
WINDOW_SIZE = (1200, 900)
|
||||
BACKGROUND_COLOR = "#143058"
|
||||
SECONDARY_COLOR = "#1260E6"
|
||||
DEVICE_BOX_STYLE = f"background-color: {BACKGROUND_COLOR}; padding: 20px; border-radius: 20px; padding: 10px 20px;"
|
||||
BUTTON_STYLE = """
|
||||
QPushButton {
|
||||
background: transparent;
|
||||
color: white;
|
||||
border: 1px solid white;
|
||||
border-radius: 20px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 255, 255, 50);
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(255, 255, 255, 100);
|
||||
}
|
||||
"""
|
||||
SQUARE_BUTTON_STYLE = "background: transparent; color: white; border: 1px transparent; border-radius: 10px; "
|
||||
POPUP_SIZE_RATIO = 0.67
|
||||
NO_DEVICE_GIF = UXUI_ASSETS + "no_device_temp.gif"
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.init_ui()
|
||||
self.model_buttons = [
|
||||
('Face Detection', self.run_face_detection),
|
||||
('Gender/Age Detection', self.run_gender_age_detection),
|
||||
('Object Detection', self.run_object_detection),
|
||||
('Mask Detection', self.run_mask_detection),
|
||||
('Image Project', self.start_image_project),
|
||||
('Upload Model', self.upload_model)
|
||||
]
|
||||
|
||||
self.connected_devices = [
|
||||
]
|
||||
|
||||
self.input_directory = ""
|
||||
self.to_keep_directory = ""
|
||||
self.to_delete_directory = ""
|
||||
self.image_directory = ""
|
||||
self.label_directory = ""
|
||||
|
||||
self.video_widget = QVideoWidget(self)
|
||||
self.camera = QCamera(QCameraInfo.defaultCamera())
|
||||
self.image_capture = QCameraImageCapture(self.camera)
|
||||
self.media_recorder = QMediaRecorder(self.camera)
|
||||
self.audio_recorder = QAudioRecorder(self)
|
||||
self.camera.setViewfinder(self.video_widget)
|
||||
|
||||
self.right_layout = QVBoxLayout()
|
||||
self.left_layout = QVBoxLayout()
|
||||
|
||||
|
||||
# TODO: find the correct mapping of the values
|
||||
class K_(Enum):
|
||||
KL520 = 256
|
||||
KL720 = 720
|
||||
KL720_L = 512 #legacy
|
||||
KL530 = 530
|
||||
KL832 = 832
|
||||
KL730 = 732
|
||||
KL630 = 630
|
||||
KL540 = 540
|
||||
|
||||
|
||||
def init_ui(self):
|
||||
self.setGeometry(100, 100, *WINDOW_SIZE)
|
||||
self.setWindowTitle('Innovedus AI Playground')
|
||||
self.setStyleSheet(f"background-color: {BACKGROUND_COLOR};")
|
||||
self.layout = QVBoxLayout(self)
|
||||
|
||||
self.show_welcome_label()
|
||||
QTimer.singleShot(5000, self.show_device_popup_and_main_page)
|
||||
|
||||
|
||||
def show_welcome_label(self):
|
||||
welcome_label = QLabel(self)
|
||||
welcome_pixmap = QPixmap(UXUI_ASSETS + "kneron_logo.png")
|
||||
welcome_label.setPixmap(welcome_pixmap)
|
||||
welcome_label.setAlignment(Qt.AlignCenter)
|
||||
self.layout.addWidget(welcome_label)
|
||||
|
||||
|
||||
def close_connection_page(self):
|
||||
print("closing device connection page")
|
||||
device_descriptors = kp.core.scan_devices()
|
||||
if device_descriptors.device_descriptor_number > 0:
|
||||
for device in device_descriptors.device_descriptor_list:
|
||||
self.parse_and_store_devices(device_descriptors.device_descriptor_list)
|
||||
kp.core.connect_devices(usb_port_ids=[device.usb_port_id])
|
||||
self.load_firmware()
|
||||
self.popup_window.close()
|
||||
|
||||
|
||||
def load_firmware(self):
|
||||
print("loading firmware")
|
||||
for device in self.connected_devices:
|
||||
device_group = kp.core.connect_devices(usb_port_ids=[device.get["usb_port_id"]])
|
||||
kp.core.set_timeout(device_group=device_group, milliseconds=5000)
|
||||
SCPU_FW_PATH = f'../../external/res/firmware/{device.get["product_id"]}/fw_scpu.bin'
|
||||
NCPU_FW_PATH = f'../../external/res/firmware/{device.get["product_id"]}/fw_ncpu.bin'
|
||||
kp.core.load_firmware_from_file(device_group=device_group,
|
||||
scpu_fw_path=SCPU_FW_PATH,
|
||||
ncpu_fw_path=NCPU_FW_PATH)
|
||||
|
||||
|
||||
def show_error_popup(self, message):
|
||||
error_dialog = QMessageBox.critical(self, "Error", message)
|
||||
|
||||
|
||||
def parse_and_store_devices(self, devices):
|
||||
for device in devices:
|
||||
new_device = {
|
||||
'usb_port_id': device.usb_port_id,
|
||||
'product_id': device.product_id,
|
||||
'kn_number': device.kn_number
|
||||
}
|
||||
print(device)
|
||||
existing_device_index = next((index for (index, d) in enumerate(self.connected_devices)
|
||||
if d['usb_port_id'] == new_device['usb_port_id']), None)
|
||||
|
||||
if existing_device_index is not None:
|
||||
self.connected_devices[existing_device_index] = new_device
|
||||
else:
|
||||
self.connected_devices.append(new_device)
|
||||
|
||||
|
||||
def check_available_device(self):
|
||||
print("checking available devices")
|
||||
device_descriptors = kp.core.scan_devices()
|
||||
self.clear_device_layout(self.device_layout)
|
||||
|
||||
if device_descriptors.device_descriptor_number > 0:
|
||||
if device_descriptors.device_descriptor_number > 0:
|
||||
self.parse_and_store_devices(device_descriptors.device_descriptor_list)
|
||||
self.display_devices(device_descriptors.device_descriptor_list)
|
||||
else:
|
||||
self.show_no_device_gif()
|
||||
|
||||
|
||||
def get_dongle_type(self, product_id):
|
||||
for dongle_type in self.K_:
|
||||
if dongle_type.value == product_id:
|
||||
return dongle_type
|
||||
return None
|
||||
|
||||
|
||||
def display_devices(self, device_descriptor_list):
|
||||
hbox_layout = QHBoxLayout()
|
||||
hbox_layout.setAlignment(Qt.AlignCenter)
|
||||
|
||||
for device in device_descriptor_list:
|
||||
device_layout = QVBoxLayout()
|
||||
box_layout = QVBoxLayout()
|
||||
|
||||
icon = QLabel()
|
||||
pixmap = QPixmap(UXUI_ASSETS + "kneron_logo.png")
|
||||
icon.setPixmap(pixmap.scaled(50, 50, Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
||||
print(device.product_id)
|
||||
usb_type_label = QLabel(f"Device: {self.get_dongle_type(device.product_id)}")
|
||||
usb_type_label.setAlignment(Qt.AlignCenter)
|
||||
usb_type_label.setStyleSheet("color: white")
|
||||
|
||||
box_layout.addWidget(icon, alignment=Qt.AlignCenter)
|
||||
box_layout.addWidget(usb_type_label)
|
||||
|
||||
box_widget = QWidget()
|
||||
box_widget.setLayout(box_layout)
|
||||
|
||||
box_size = 200
|
||||
box_widget.setFixedSize(box_size, box_size)
|
||||
box_widget.setStyleSheet(DEVICE_BOX_STYLE)
|
||||
|
||||
usb_port_label = QLabel(f"KN number:\n{device.kn_number}")
|
||||
usb_port_label.setAlignment(Qt.AlignLeft)
|
||||
usb_port_label.setStyleSheet("color: white;")
|
||||
|
||||
label_icon_layout = QHBoxLayout()
|
||||
|
||||
small_icon = QSvgWidget(UXUI_ASSETS + "./Assets_svg/btn_dialog_device_disconnect_normal.svg")
|
||||
small_icon.setFixedSize(30, 30)
|
||||
|
||||
label_icon_layout.addWidget(usb_port_label)
|
||||
label_icon_layout.addWidget(small_icon, alignment=Qt.AlignRight)
|
||||
|
||||
device_layout.addWidget(box_widget)
|
||||
device_layout.addLayout(label_icon_layout)
|
||||
|
||||
device_widget = QWidget()
|
||||
device_widget.setLayout(device_layout)
|
||||
|
||||
hbox_layout.addWidget(device_widget)
|
||||
|
||||
self.device_layout.addLayout(hbox_layout)
|
||||
|
||||
|
||||
|
||||
def show_no_device_gif(self):
|
||||
no_device_label = QLabel(self)
|
||||
no_device_movie = QMovie(NO_DEVICE_GIF)
|
||||
no_device_label.setMovie(no_device_movie)
|
||||
no_device_movie.start()
|
||||
no_device_label.setAlignment(Qt.AlignCenter)
|
||||
self.device_layout.addWidget(no_device_label)
|
||||
|
||||
|
||||
def show_device_connection_popup(self):
|
||||
self.popup_window = QDialog(self)
|
||||
self.popup_window.setWindowTitle("Device Connection")
|
||||
self.popup_window.setFocusPolicy(Qt.StrongFocus)
|
||||
|
||||
popup_width = int(self.width() * POPUP_SIZE_RATIO)
|
||||
popup_height = int(self.height() * POPUP_SIZE_RATIO)
|
||||
self.popup_window.setGeometry(100, 100, popup_width, popup_height)
|
||||
self.popup_window.setStyleSheet(f"background-color: {SECONDARY_COLOR};")
|
||||
|
||||
popup_layout = QVBoxLayout()
|
||||
|
||||
self.device_layout = QVBoxLayout()
|
||||
|
||||
popup_title = QHBoxLayout()
|
||||
small_icon = QSvgWidget(UXUI_ASSETS + "./Assets_svg/ic_window_device.svg")
|
||||
small_icon.setFixedSize(30, 30)
|
||||
popup_title.addWidget(small_icon)
|
||||
device_popup_label = QLabel("Device Connection", self.popup_window)
|
||||
device_popup_label.setAlignment(Qt.AlignCenter)
|
||||
popup_title.addWidget(device_popup_label)
|
||||
popup_layout.addLayout(self.device_layout)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
refresh_button = QPushButton('Refresh')
|
||||
refresh_button.clicked.connect(self.check_available_device)
|
||||
refresh_button.setStyleSheet(BUTTON_STYLE)
|
||||
button_layout.addWidget(refresh_button)
|
||||
|
||||
done_button = QPushButton('Done')
|
||||
done_button.setStyleSheet(BUTTON_STYLE)
|
||||
#done_button.clicked.connect(self.close_connection_page)
|
||||
done_button.clicked.connect(lambda: self.close_connection_page())
|
||||
|
||||
button_layout.addWidget(done_button)
|
||||
|
||||
popup_layout.addLayout(button_layout)
|
||||
self.popup_window.setLayout(popup_layout)
|
||||
|
||||
self.popup_window.setModal(True)
|
||||
self.setEnabled(False)
|
||||
self.popup_window.finished.connect(lambda: self.setEnabled(True))
|
||||
|
||||
self.popup_window.show()
|
||||
|
||||
self.check_available_device()
|
||||
|
||||
|
||||
def show_device_popup_and_main_page(self):
|
||||
self.show_device_connection_popup()
|
||||
self.popup_window.finished.connect(self.main_page)
|
||||
|
||||
|
||||
|
||||
def clear_device_layout(self, layout):
|
||||
for i in reversed(range(layout.count())):
|
||||
layout.itemAt(i).widget().deleteLater()
|
||||
|
||||
|
||||
def clear_layout(self):
|
||||
for i in reversed(range(self.device_layout.count())):
|
||||
self.device_layout.itemAt(i).widget().deleteLater()
|
||||
|
||||
|
||||
def create_frame(self, title, icon_path):
|
||||
frame = QFrame(self)
|
||||
frame.setStyleSheet(f"border: none; background: {SECONDARY_COLOR}; border-radius: 20px;")
|
||||
layout = QVBoxLayout(frame)
|
||||
|
||||
title_layout = QHBoxLayout()
|
||||
title_icon = QSvgWidget(icon_path)
|
||||
title_icon.setFixedSize(40, 40)
|
||||
title_layout.addWidget(title_icon)
|
||||
title_label = QLabel(title)
|
||||
title_label.setStyleSheet("color: white;")
|
||||
title_layout.addWidget(title_label)
|
||||
|
||||
layout.addLayout(title_layout)
|
||||
return frame
|
||||
|
||||
|
||||
def add_model_buttons(self, layout):
|
||||
for model_name, run_function in self.model_buttons:
|
||||
button = QPushButton(model_name)
|
||||
button.clicked.connect(run_function)
|
||||
|
||||
button.setStyleSheet("""
|
||||
QPushButton {
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
background-color: transparent;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 255, 255, 50);
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(255, 255, 255, 100);
|
||||
}
|
||||
""")
|
||||
layout.addWidget(button)
|
||||
|
||||
|
||||
def start_camera(self):
|
||||
print("opening camera")
|
||||
self.right_layout.replaceWidget(self.canvas_label, self.video_widget)
|
||||
self.canvas_label.hide()
|
||||
self.camera.start()
|
||||
|
||||
|
||||
def stop_camera(self):
|
||||
self.camera.stop()
|
||||
|
||||
self.right_layout.replaceWidget(self.video_widget, self.canvas_label)
|
||||
self.video_widget.hide()
|
||||
self.canvas_label.show()
|
||||
|
||||
|
||||
# TODO: implement these functions and add button state/style change
|
||||
def record_video(self):
|
||||
output_file = "output_video.mp4"
|
||||
self.media_recorder.setOutputLocation(QUrl.fromLocalFile(os.path.abspath(output_file)))
|
||||
self.media_recorder.record()
|
||||
|
||||
def stop_recording(self):
|
||||
self.media_recorder.stop()
|
||||
|
||||
|
||||
def record_audio(self):
|
||||
audio_output_file = "output_audio.wav"
|
||||
self.audio_recorder.setOutputLocation(QUrl.fromLocalFile(os.path.abspath(audio_output_file)))
|
||||
self.audio_recorder.record()
|
||||
|
||||
|
||||
def stop_audio(self):
|
||||
self.audio_recorder.stop()
|
||||
|
||||
|
||||
def take_screenshot(self):
|
||||
self.image_capture.capture()
|
||||
self.image_capture.imageCaptured.connect(self.process_capture)
|
||||
|
||||
|
||||
def process_capture(self, requestId, image):
|
||||
file_name = f"screenshot_{requestId}.png"
|
||||
image.save(file_name)
|
||||
print(f"Screenshot saved as {file_name}")
|
||||
|
||||
|
||||
def run_face_detection(self):
|
||||
self.start_camera()
|
||||
print("Running Face Detection")
|
||||
|
||||
|
||||
def run_gender_age_detection(self):
|
||||
self.start_camera()
|
||||
print("Running Gender/Age Detection")
|
||||
|
||||
|
||||
def run_object_detection(self):
|
||||
self.start_camera()
|
||||
print("Running Object Detection")
|
||||
|
||||
|
||||
def run_mask_detection(self):
|
||||
self.start_camera()
|
||||
print("Running Mask Detection")
|
||||
|
||||
|
||||
def choose_folder(self):
|
||||
self.input_directory = QFileDialog.getExistingDirectory(self, "Select Input Directory")
|
||||
self.to_keep_directory = QFileDialog.getExistingDirectory(self, "Select 'To Keep' Directory")
|
||||
self.to_delete_directory = QFileDialog.getExistingDirectory(self, "Select 'To Delete' Directory")
|
||||
|
||||
if self.input_directory and self.to_keep_directory and self.to_delete_directory:
|
||||
print(f"Selected directories:\nInput: {self.input_directory}\nTo Keep: {self.to_keep_directory}\nTo Delete: {self.to_delete_directory}")
|
||||
|
||||
|
||||
def create_folder_button(self):
|
||||
folder_button_widget = QWidget()
|
||||
folder_button_layout = QVBoxLayout()
|
||||
|
||||
text_label = QLabel("Image")
|
||||
text_label.setAlignment(Qt.AlignCenter)
|
||||
text_label.setStyleSheet("color: white;")
|
||||
folder_button_layout.addWidget(text_label)
|
||||
|
||||
folder_button_widget.setLayout(folder_button_layout)
|
||||
folder_button_widget.setStyleSheet(f"""
|
||||
QWidget {{
|
||||
background-color: {SECONDARY_COLOR};
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
}}
|
||||
""")
|
||||
|
||||
return folder_button_widget
|
||||
|
||||
|
||||
def process_image_project(self):
|
||||
print("processing_image_project")
|
||||
|
||||
|
||||
def start_image_project(self):
|
||||
print("running image project")
|
||||
|
||||
self.popup_window = QDialog(self)
|
||||
self.popup_window.setWindowTitle("Choose Folder")
|
||||
|
||||
popup_width = int(self.width() * POPUP_SIZE_RATIO)
|
||||
popup_height = int(self.height() * POPUP_SIZE_RATIO)
|
||||
self.popup_window.setGeometry(100, 100, popup_width, popup_height)
|
||||
self.popup_window.setStyleSheet(f"background-color: {SECONDARY_COLOR};")
|
||||
|
||||
popup_layout = QVBoxLayout()
|
||||
|
||||
self.device_layout = QVBoxLayout()
|
||||
cust_label = QLabel("Customization", self.popup_window)
|
||||
cust_label.setAlignment(Qt.AlignCenter)
|
||||
cust_label.setStyleSheet("color: white")
|
||||
popup_layout.addWidget(cust_label)
|
||||
popup_layout.addLayout(self.device_layout)
|
||||
|
||||
folder_icon = QSvgWidget(UXUI_ASSETS + "./Assets_svg/ic_customization_upload_folder.svg")
|
||||
folder_icon.setFixedSize(100, 100)
|
||||
|
||||
upload_icon = QSvgWidget(UXUI_ASSETS + "./Assets_svg/bt_function_upload_normal.svg")
|
||||
upload_icon.setFixedSize(40, 40)
|
||||
|
||||
folder_button_widget = QWidget()
|
||||
folder_button_layout = QVBoxLayout()
|
||||
|
||||
text_label = QLabel("Image")
|
||||
text_label.setAlignment(Qt.AlignCenter)
|
||||
text_label.setStyleSheet("color: white; border: none")
|
||||
|
||||
folder_button_layout.addWidget(text_label)
|
||||
folder_button_layout.addWidget(folder_icon)
|
||||
|
||||
description_label = QLabel("Upload or drag files")
|
||||
description_label.setAlignment(Qt.AlignCenter)
|
||||
description_label.setStyleSheet("color: white; border: none")
|
||||
folder_button_layout.addWidget(description_label)
|
||||
folder_button_layout.addWidget(upload_icon)
|
||||
folder_button_layout.setAlignment(Qt.AlignCenter)
|
||||
|
||||
folder_button_widget.setLayout(folder_button_layout)
|
||||
|
||||
folder_frame = QFrame()
|
||||
folder_frame.setStyleSheet(f"""
|
||||
QFrame {{
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
background-color: {SECONDARY_COLOR};
|
||||
}}
|
||||
""")
|
||||
folder_frame.setLayout(QVBoxLayout())
|
||||
folder_frame.layout().addWidget(folder_button_widget)
|
||||
|
||||
folder_icon2 = QSvgWidget(UXUI_ASSETS + "./Assets_svg/ic_customization_upload_folder.svg")
|
||||
folder_icon2.setFixedSize(100, 100)
|
||||
upload_icon2 = QSvgWidget(UXUI_ASSETS + "./Assets_svg/bt_function_upload_normal.svg")
|
||||
upload_icon2.setFixedSize(40, 40)
|
||||
folder_button_widget2 = QWidget()
|
||||
folder_button_layout2 = QVBoxLayout()
|
||||
|
||||
text_label2 = QLabel("Label")
|
||||
text_label2.setAlignment(Qt.AlignCenter)
|
||||
text_label2.setStyleSheet("color: white; border: none")
|
||||
|
||||
folder_button_layout2.addWidget(text_label2)
|
||||
folder_button_layout2.addWidget(folder_icon2)
|
||||
folder_button_layout2.setAlignment(Qt.AlignCenter)
|
||||
|
||||
description_label2 = QLabel("Upload or drag files")
|
||||
description_label2.setAlignment(Qt.AlignCenter)
|
||||
description_label2.setStyleSheet("color: white; border: none")
|
||||
folder_button_layout2.addWidget(description_label2)
|
||||
folder_button_layout2.addWidget(upload_icon2)
|
||||
|
||||
folder_button_widget2.setLayout(folder_button_layout2)
|
||||
|
||||
folder_frame2 = QFrame()
|
||||
folder_frame2.setStyleSheet(f"""
|
||||
QFrame {{
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
background-color: {SECONDARY_COLOR};
|
||||
}}
|
||||
""")
|
||||
folder_frame2.setLayout(QVBoxLayout())
|
||||
folder_frame2.layout().addWidget(folder_button_widget2)
|
||||
|
||||
folder_buttons_layout = QHBoxLayout()
|
||||
folder_buttons_layout.addWidget(folder_frame)
|
||||
folder_buttons_layout.addWidget(folder_frame2)
|
||||
|
||||
popup_layout.addLayout(folder_buttons_layout)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
self.cancel_button = QPushButton('Cancel', self.popup_window)
|
||||
self.cancel_button.clicked.connect(self.popup_window.close)
|
||||
self.cancel_button.setStyleSheet(BUTTON_STYLE)
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.done_button = QPushButton('Done', self.popup_window)
|
||||
self.done_button.setStyleSheet(BUTTON_STYLE)
|
||||
self.done_button.clicked.connect(self.process_image_project)
|
||||
button_layout.addWidget(self.done_button)
|
||||
|
||||
popup_layout.addLayout(button_layout)
|
||||
|
||||
self.popup_window.setLayout(popup_layout)
|
||||
|
||||
self.popup_window.setModal(True)
|
||||
self.setEnabled(False)
|
||||
self.popup_window.finished.connect(lambda: self.setEnabled(True))
|
||||
|
||||
self.popup_window.show()
|
||||
|
||||
|
||||
def upload_model(self):
|
||||
print("Uploading Model")
|
||||
|
||||
|
||||
def main_page(self):
|
||||
self.clear_device_layout(self.layout)
|
||||
self.setWindowTitle('Innovedus AI Playground')
|
||||
self.setGeometry(100, 100, *WINDOW_SIZE)
|
||||
|
||||
main_layout = QHBoxLayout()
|
||||
top_nav = QHBoxLayout()
|
||||
|
||||
welcome_label = QLabel(self)
|
||||
welcome_pixmap = QPixmap(UXUI_ASSETS + "kneron_logo.png").scaled(150, 150, Qt.KeepAspectRatio)
|
||||
welcome_label.setPixmap(welcome_pixmap)
|
||||
top_nav.addWidget(welcome_label, alignment=Qt.AlignLeft)
|
||||
top_nav.addStretch()
|
||||
|
||||
settings_button = QPushButton("Settings", self)
|
||||
settings_button.setStyleSheet(BUTTON_STYLE)
|
||||
top_nav.addWidget(settings_button, alignment=Qt.AlignRight)
|
||||
self.layout.addLayout(top_nav)
|
||||
|
||||
|
||||
left_widget = QWidget()
|
||||
left_widget.setLayout(self.left_layout)
|
||||
left_widget.setFixedWidth(self.geometry().width() // 3)
|
||||
|
||||
right_widget = QWidget()
|
||||
right_widget.setLayout(self.right_layout)
|
||||
right_widget.setFixedWidth(self.geometry().width() * 2 // 3)
|
||||
|
||||
main_layout.addWidget(left_widget)
|
||||
main_layout.addWidget(right_widget)
|
||||
self.layout.addLayout(main_layout)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.create_device_layout()
|
||||
self.create_right_layout()
|
||||
|
||||
|
||||
def show_device_details(self):
|
||||
print("show_device_details")
|
||||
|
||||
|
||||
def create_device_layout(self):
|
||||
devices_frame = self.create_frame("Device", UXUI_ASSETS + "./Assets_svg/ic_window_device.svg")
|
||||
devices_frame_layout = QVBoxLayout()
|
||||
self.device_list = QListWidget(self)
|
||||
|
||||
print(self.connected_devices)
|
||||
|
||||
for device in self.connected_devices:
|
||||
usb_port_id = device.get("usb_port_id")
|
||||
product_id = device.get("product_id")
|
||||
kn_number = device.get("kn_number")
|
||||
|
||||
h_layout = QHBoxLayout()
|
||||
icon = QSvgWidget(UXUI_ASSETS + "./Assets_svg/ic_window_device.svg")
|
||||
icon.setFixedSize(40, 40)
|
||||
h_layout.addWidget(icon)
|
||||
|
||||
text_layout = QVBoxLayout()
|
||||
line1_label = QLabel(f"Dongle: {product_id}")
|
||||
line1_label.setStyleSheet("font-weight: bold; color: white;")
|
||||
text_layout.addWidget(line1_label)
|
||||
|
||||
line2_label = QLabel(f"KN number: {kn_number}")
|
||||
line2_label.setStyleSheet("color: white;")
|
||||
text_layout.addWidget(line2_label)
|
||||
|
||||
h_layout.addLayout(text_layout)
|
||||
|
||||
item_widget = QWidget()
|
||||
item_widget.setLayout(h_layout)
|
||||
list_item = QListWidgetItem()
|
||||
list_item.setSizeHint(item_widget.sizeHint())
|
||||
self.device_list.addItem(list_item)
|
||||
self.device_list.setItemWidget(list_item, item_widget)
|
||||
|
||||
devices_frame_layout.addWidget(self.device_list)
|
||||
|
||||
detail_button = QPushButton("Details", self)
|
||||
detail_button.clicked.connect(self.show_device_details)
|
||||
devices_frame_layout.addWidget(detail_button)
|
||||
|
||||
devices_frame.setLayout(devices_frame_layout)
|
||||
self.left_layout.addWidget(devices_frame)
|
||||
|
||||
self.models_frame = self.create_frame("AI Toolbox", UXUI_ASSETS + "./Assets_svg/ic_window_toolbox.svg")
|
||||
models_layout = QVBoxLayout(self.models_frame)
|
||||
self.models_frame.setLayout(models_layout)
|
||||
|
||||
self.add_model_buttons(self.models_frame.layout())
|
||||
self.left_layout.addWidget(self.models_frame)
|
||||
|
||||
|
||||
def create_right_layout(self):
|
||||
self.canvas_label = QLabel("Canvas Area (Camera Screen)", self)
|
||||
self.canvas_label.setAlignment(Qt.AlignCenter)
|
||||
self.canvas_label.setStyleSheet("border: 1px transparent; background: gray; border-radius: 20px; ")
|
||||
self.right_layout.addWidget(self.canvas_label)
|
||||
|
||||
button_overlay_layout = QVBoxLayout()
|
||||
button_overlay_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.create_square_buttons(button_overlay_layout)
|
||||
|
||||
button_overlay_widget = QWidget(self)
|
||||
button_overlay_widget.setLayout(button_overlay_layout)
|
||||
button_overlay_widget.setStyleSheet(f"background: {SECONDARY_COLOR}; border-radius: 20px; padding: 10px;")
|
||||
|
||||
button_overlay_widget.setFixedHeight(150)
|
||||
self.right_layout.addWidget(button_overlay_widget, alignment=Qt.AlignBottom | Qt.AlignRight)
|
||||
|
||||
|
||||
def create_square_buttons(self, layout):
|
||||
square_buttons_info = [
|
||||
('video', UXUI_ASSETS + "./Assets_svg/ic_recording_camera.svg"),
|
||||
('voice', UXUI_ASSETS + "./Assets_svg/ic_recording_voice.svg"),
|
||||
('screenshot', UXUI_ASSETS + "./Assets_svg/bt_function_screencapture_normal.svg"),
|
||||
]
|
||||
|
||||
for button_name, icon_path in square_buttons_info:
|
||||
button = QPushButton(self)
|
||||
button.setFixedSize(50, 50)
|
||||
button.setStyleSheet(SQUARE_BUTTON_STYLE)
|
||||
button_layout = QHBoxLayout(button)
|
||||
button_layout.setContentsMargins(0, 0, 0, 0)
|
||||
icon = QSvgWidget(icon_path)
|
||||
icon.setFixedSize(40, 40)
|
||||
button_layout.addWidget(icon)
|
||||
|
||||
layout.addWidget(button)
|
||||
|
||||
|
||||
def upload_model(self):
|
||||
model_file, _ = QFileDialog.getOpenFileName(self, "Upload Model", "", "NEF Files (*.nef)")
|
||||
if model_file:
|
||||
if model_file.endswith('.nef'):
|
||||
model_name = os.path.basename(model_file)
|
||||
self.model_buttons.insert(-1, (model_name, self.run_uploaded_model))
|
||||
print(f"Model uploaded: {model_name}")
|
||||
self.refresh_model_buttons()
|
||||
else:
|
||||
self.show_error_popup("Invalid file format. Please upload a .nef file.")
|
||||
|
||||
|
||||
def refresh_model_buttons(self):
|
||||
layout = self.models_frame.layout()
|
||||
|
||||
for i in reversed(range(layout.count())):
|
||||
widget_to_remove = layout.itemAt(i).widget()
|
||||
if widget_to_remove is not None:
|
||||
widget_to_remove.deleteLater()
|
||||
|
||||
self.add_model_buttons(layout)
|
||||
|
||||
|
||||
def run_uploaded_model(self):
|
||||
print("Running uploaded model")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec_())
|
||||
160
demogui/utils.py
160
demogui/utils.py
@ -1,160 +0,0 @@
|
||||
import os
|
||||
import cv2
|
||||
import kp
|
||||
import numpy as np
|
||||
import numpy as np
|
||||
from sklearn.cluster import DBSCAN
|
||||
|
||||
|
||||
# -------------------- General Dongle Connection -------------------------------#
|
||||
def connect_and_load_firmware(device_descriptors):
|
||||
# device_descriptors = kp.core.scan_devices()
|
||||
if 0 < device_descriptors.device_descriptor_number:
|
||||
for device in device_descriptors.device_descriptor_list:
|
||||
usb_port_id = device.usb_port_id
|
||||
device_group = kp.core.connect_devices(usb_port_ids=[22])
|
||||
kp.core.set_timeout(device_group=device_group,
|
||||
milliseconds=5000)
|
||||
SCPU_FW_PATH = '../../res/firmware/KL520/fw_scpu.bin'
|
||||
NCPU_FW_PATH = '../../res/firmware/KL520/fw_ncpu.bin'
|
||||
kp.core.load_firmware_from_file(device_group=device_group,
|
||||
scpu_fw_path=SCPU_FW_PATH,
|
||||
ncpu_fw_path=NCPU_FW_PATH)
|
||||
else:
|
||||
print('Error: no Kneron device connect.')
|
||||
exit(0)
|
||||
|
||||
def load_firmware():
|
||||
print("loading firmware")
|
||||
|
||||
def list_image_files(directory):
|
||||
"""List all image files in a given directory."""
|
||||
valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')
|
||||
return [os.path.join(directory, f) for f in os.listdir(directory) if f.lower().endswith(valid_extensions)]
|
||||
|
||||
|
||||
# -------------------- Decluttering & Photo Quality Model -------------------------------#
|
||||
|
||||
def preprocess_image(image_file_path):
|
||||
maxbytes = 500000
|
||||
file_size = os.path.getsize(image_file_path)
|
||||
img = cv2.imread(filename=image_file_path)
|
||||
|
||||
if file_size > maxbytes:
|
||||
scale_factor = (maxbytes / file_size) ** 0.5
|
||||
new_width = int(img.shape[1] * scale_factor)
|
||||
new_height = int(img.shape[0] * scale_factor)
|
||||
if new_width % 2 != 0:
|
||||
new_width += 1
|
||||
img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA)
|
||||
else:
|
||||
if img.shape[1] % 2 != 0:
|
||||
img = cv2.resize(img, (img.shape[1] + 1, img.shape[0]), interpolation=cv2.INTER_AREA)
|
||||
|
||||
img_bgr565 = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2BGR565)
|
||||
return img_bgr565
|
||||
|
||||
|
||||
def perform_inference(device_group, model_nef_descriptor, img_bgr565):
|
||||
generic_inference_input_descriptor = kp.GenericImageInferenceDescriptor(
|
||||
model_id=model_nef_descriptor.models[0].id,
|
||||
inference_number=0,
|
||||
input_node_image_list=[
|
||||
kp.GenericInputNodeImage(
|
||||
image=img_bgr565,
|
||||
image_format=kp.ImageFormat.KP_IMAGE_FORMAT_RGB565,
|
||||
resize_mode=kp.ResizeMode.KP_RESIZE_ENABLE,
|
||||
padding_mode=kp.PaddingMode.KP_PADDING_CORNER,
|
||||
normalize_mode=kp.NormalizeMode.KP_NORMALIZE_KNERON
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
kp.inference.generic_image_inference_send(device_group=device_group,
|
||||
generic_inference_input_descriptor=generic_inference_input_descriptor)
|
||||
generic_raw_result = kp.inference.generic_image_inference_receive(device_group=device_group)
|
||||
|
||||
inf_node_output_list = []
|
||||
|
||||
for node_idx in range(generic_raw_result.header.num_output_node):
|
||||
inference_float_node_output = kp.inference.generic_inference_retrieve_float_node(
|
||||
node_idx=node_idx,
|
||||
generic_raw_result=generic_raw_result,
|
||||
channels_ordering=kp.ChannelOrdering.KP_CHANNEL_ORDERING_CHW
|
||||
)
|
||||
inf_node_output_list.append(inference_float_node_output)
|
||||
|
||||
return inf_node_output_list
|
||||
|
||||
|
||||
def post_process_inference(inf_node_output_list):
|
||||
"""Processes the inference output and returns a mean score."""
|
||||
data = inf_node_output_list[0]
|
||||
raw_ndarray = data.ndarray
|
||||
|
||||
if isinstance(raw_ndarray, np.ndarray):
|
||||
ndarray_np = raw_ndarray
|
||||
else:
|
||||
ndarray_np = np.array(raw_ndarray)
|
||||
|
||||
ndarray_np = ndarray_np.flatten()
|
||||
ndarray_np = ndarray_np.reshape((data.channel, data.height, data.width))
|
||||
|
||||
ndarray_np = ndarray_np.flatten()
|
||||
result = np.mean(ndarray_np) # Mean score
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def process_image(device_group, model_nef_descriptor, image_file_path):
|
||||
"""Full pipeline: preprocess image, perform inference, and post-process to get a score."""
|
||||
img_bgr565 = preprocess_image(image_file_path)
|
||||
inf_node_output_list = perform_inference(device_group, model_nef_descriptor, img_bgr565)
|
||||
nd_array = inf_node_output_list[0].ndarray
|
||||
number = float(nd_array.flatten()[0])
|
||||
return number
|
||||
|
||||
|
||||
def cosine_similarity(tensor1, tensor2):
|
||||
"""Compute the cosine similarity between two tensors."""
|
||||
dot_product = np.dot(tensor1, tensor2)
|
||||
norm1 = np.linalg.norm(tensor1)
|
||||
norm2 = np.linalg.norm(tensor2)
|
||||
return dot_product / (norm1 * norm2)
|
||||
|
||||
|
||||
def compare_images_cosine_similarity(image_paths, device_group, model_nef_descriptor):
|
||||
"""Compare the cosine similarity between feature tensors of photos in the given image file paths."""
|
||||
num_images = len(image_paths)
|
||||
features = []
|
||||
for image_path in image_paths:
|
||||
feature = process_image(device_group, model_nef_descriptor, image_path)
|
||||
features.append(feature)
|
||||
|
||||
similarity_matrix = np.zeros((num_images, num_images))
|
||||
for i in range(num_images):
|
||||
for j in range(num_images):
|
||||
if i != j:
|
||||
similarity_matrix[i, j] = cosine_similarity(features[i], features[j])
|
||||
else:
|
||||
similarity_matrix[i, j] = 1.0
|
||||
return similarity_matrix
|
||||
|
||||
|
||||
def cluster_images_with_dbscan(image_paths, feature_extractor, model_nef_descriptor, similarity_threshold=0.8, min_samples=2):
|
||||
"""Cluster images based on cosine similarity using DBSCAN and return clusters as arrays of file paths."""
|
||||
similarity_matrix = compare_images_cosine_similarity(image_paths, feature_extractor, model_nef_descriptor)
|
||||
distance_matrix = 1 - similarity_matrix
|
||||
dbscan = DBSCAN(eps=1-similarity_threshold, min_samples=min_samples, metric='precomputed')
|
||||
labels = dbscan.fit_predict(distance_matrix)
|
||||
|
||||
clusters = []
|
||||
unique_labels = set(labels)
|
||||
for label in unique_labels:
|
||||
if label != -1:
|
||||
cluster = [image_paths[i] for i in range(len(labels)) if labels[i] == label]
|
||||
clusters.append(cluster)
|
||||
return clusters
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user