刪除 demogui 原先的 folder

This commit is contained in:
Mason Huang 2025-03-07 11:48:03 +08:00
parent a8ed1ac592
commit c12bbd29fd
5 changed files with 0 additions and 2691 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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_())

View File

@ -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
}

View File

@ -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_())

View File

@ -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