From e4d07f3d6f881efdbafb3b356c8e0d872141f38b Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Fri, 23 May 2025 19:30:28 +0200 Subject: [PATCH] this work now --- fedora_setup.sh | 0 opencam/coco.names | 80 ++++++++ opencam/main.py | 433 ++++++++++++++++++++++++++++------------ opencam/yolov4-tiny.cfg | 294 +++++++++++++++++++++++++++ requirements.txt | 3 + 5 files changed, 678 insertions(+), 132 deletions(-) mode change 100644 => 100755 fedora_setup.sh create mode 100644 opencam/coco.names create mode 100644 opencam/yolov4-tiny.cfg create mode 100644 requirements.txt diff --git a/fedora_setup.sh b/fedora_setup.sh old mode 100644 new mode 100755 diff --git a/opencam/coco.names b/opencam/coco.names new file mode 100644 index 0000000..ca76c80 --- /dev/null +++ b/opencam/coco.names @@ -0,0 +1,80 @@ +person +bicycle +car +motorbike +aeroplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +sofa +pottedplant +bed +diningtable +toilet +tvmonitor +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush diff --git a/opencam/main.py b/opencam/main.py index be740c4..4e47788 100644 --- a/opencam/main.py +++ b/opencam/main.py @@ -3,11 +3,12 @@ import cv2 import numpy as np from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget, QComboBox, QMessageBox, - QProgressBar, QDialog) + QProgressBar, QDialog, QFileDialog, QCheckBox, QStatusBar) from PyQt5.QtGui import QImage, QPixmap -from PyQt5.QtCore import QTimer, Qt +from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal import os import urllib.request +import time class DownloadProgressBar(QDialog): def __init__(self, parent=None): @@ -18,7 +19,7 @@ class DownloadProgressBar(QDialog): layout = QVBoxLayout() - self.label = QLabel("Downloading...") + self.label = QLabel("Downloading YOLO files...") layout.addWidget(self.label) self.progress = QProgressBar() @@ -26,101 +27,218 @@ class DownloadProgressBar(QDialog): self.progress.setMaximum(100) layout.addWidget(self.progress) + self.cancel_button = QPushButton("Cancel") + self.cancel_button.clicked.connect(self.reject) + layout.addWidget(self.cancel_button) + self.setLayout(layout) def update_progress(self, current, total): percentage = int((current / total) * 100) self.progress.setValue(percentage) + QApplication.processEvents() - def set_file_label(self, filename): + def update_label(self, filename): self.label.setText(f"Downloading {filename}...") + QApplication.processEvents() class DownloadProgressHandler: def __init__(self, progress_dialog): self.progress_dialog = progress_dialog self.current_size = 0 self.total_size = 0 + self.last_update = 0 def handle_progress(self, count, block_size, total_size): self.total_size = total_size - self.current_size += block_size - self.progress_dialog.update_progress(self.current_size, self.total_size) + self.current_size = count * block_size + + current_time = time.time() + if current_time - self.last_update > 0.1: + self.progress_dialog.update_progress(self.current_size, self.total_size) + self.last_update = current_time + +class DetectionThread(QThread): + detection_done = pyqtSignal(np.ndarray) + + def __init__(self, net, classes, output_layers, frame): + super().__init__() + self.net = net + self.classes = classes + self.output_layers = output_layers + self.frame = frame.copy() + self.running = True + + def run(self): + if not self.running or self.net is None or self.classes is None: + self.detection_done.emit(self.frame) + return + + height, width = self.frame.shape[:2] + blob = cv2.dnn.blobFromImage(self.frame, 1/255.0, (416, 416), swapRB=True, crop=False) + + self.net.setInput(blob) + outs = self.net.forward(self.output_layers) + + class_ids = [] + confidences = [] + boxes = [] + + for out in outs: + for detection in out: + scores = detection[5:] + class_id = np.argmax(scores) + confidence = scores[class_id] + if confidence > 0.5: + box = detection[0:4] * np.array([width, height, width, height]) + (center_x, center_y, box_width, box_height) = box.astype("int") + x = int(center_x - (box_width / 2)) + y = int(center_y - (box_height / 2)) + boxes.append([x, y, int(box_width), int(box_height)]) + confidences.append(float(confidence)) + class_ids.append(class_id) + + indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) + + if len(indexes) > 0: + for i in indexes.flatten(): + (x, y, w, h) = boxes[i] + label = str(self.classes[class_ids[i]]) + confidence = confidences[i] + color = (0, 255, 0) + cv2.rectangle(self.frame, (x, y), (x + w, y + h), color, 2) + cv2.putText(self.frame, f"{label}: {confidence:.2f}", + (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) + + self.detection_done.emit(self.frame) + + def stop(self): + self.running = False + self.wait() class CameraApp(QMainWindow): def __init__(self): super().__init__() - self.setWindowTitle("Object Detection Camera Viewer") - self.setGeometry(100, 100, 800, 600) + self.setWindowTitle("Advanced Object Detection Camera Viewer") + self.setGeometry(100, 100, 1000, 800) + # Initialize attributes first self.camera_index = 0 self.cap = None self.timer = QTimer() - self.timer.timeout.connect(self.update_frame) self.available_cameras = [] - - # Initialize object detection + self.detection_thread = None self.net = None self.classes = None self.output_layers = None - self.load_yolo() - + self.detection_enabled = True + self.model_loaded = False + self.fps = 0 + self.frame_count = 0 + self.last_fps_update = time.time() + + # Initialize UI self.init_ui() + + # Load YOLO after UI is ready + QTimer.singleShot(100, self.load_yolo) def init_ui(self): self.central_widget = QWidget() self.setCentralWidget(self.central_widget) layout = QVBoxLayout() + # Video display self.video_label = QLabel(self) + self.video_label.setAlignment(Qt.AlignCenter) + self.video_label.setMinimumSize(640, 480) layout.addWidget(self.video_label) + # Camera controls self.camera_select = QComboBox(self) - self.detect_cameras() layout.addWidget(self.camera_select) - self.camera_select.currentIndexChanged.connect(self.change_camera) + # Detection controls + self.detection_checkbox = QCheckBox("Enable Object Detection", self) + self.detection_checkbox.setChecked(True) + self.detection_checkbox.stateChanged.connect(self.toggle_detection) + layout.addWidget(self.detection_checkbox) + + # Button controls + button_layout = QVBoxLayout() + self.start_button = QPushButton("Start Camera", self) self.start_button.clicked.connect(self.start_camera) - layout.addWidget(self.start_button) + button_layout.addWidget(self.start_button) self.stop_button = QPushButton("Stop Camera", self) self.stop_button.clicked.connect(self.stop_camera) - layout.addWidget(self.stop_button) + button_layout.addWidget(self.stop_button) + + self.snapshot_button = QPushButton("Take Snapshot", self) + self.snapshot_button.clicked.connect(self.take_snapshot) + button_layout.addWidget(self.snapshot_button) + + layout.addLayout(button_layout) + + # Status bar + self.status_bar = QStatusBar() + self.setStatusBar(self.status_bar) + self.status_label = QLabel("Initializing...") + self.status_bar.addPermanentWidget(self.status_label) self.central_widget.setLayout(layout) + + # Set up timer after UI is ready + self.timer.timeout.connect(self.update_frame) + + # Detect cameras after UI is ready + QTimer.singleShot(100, self.detect_cameras) + + def toggle_detection(self, state): + self.detection_enabled = state == Qt.Checked + self.status_label.setText(f"Detection {'enabled' if self.detection_enabled else 'disabled'}") def detect_cameras(self): self.camera_select.clear() self.available_cameras = [] - # Try to get the list of available cameras using DirectShow backend - for i in range(10): # Check first 10 indexes - cap = cv2.VideoCapture(i, cv2.CAP_DSHOW) - if cap.isOpened(): - # Get camera name - cap.set(cv2.CAP_PROP_SETTINGS, 1) # This might show camera properties dialog - name = f"Camera {i}" - - # Try to get camera resolution to verify it's working - width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) - height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) - - if width and height: - name = f"{name} ({int(width)}x{int(height)})" - self.available_cameras.append(i) - self.camera_select.addItem(name, i) - - cap.release() + # Check for available cameras (try both backends) + backends = [cv2.CAP_DSHOW, cv2.CAP_V4L2, cv2.CAP_ANY] + max_cameras_to_check = 10 + + for backend in backends: + for i in range(max_cameras_to_check): + try: + cap = cv2.VideoCapture(i, backend) + if cap.isOpened(): + # Get camera properties + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + fps = cap.get(cv2.CAP_PROP_FPS) + + name = f"Camera {i} ({width}x{height})" + if fps > 0: + name += f" @ {fps:.1f}FPS" + + self.available_cameras.append((i, backend)) + self.camera_select.addItem(name, (i, backend)) + cap.release() + break # Only add once per camera index + cap.release() + except Exception as e: + # Ignore errors for non-existent cameras + pass if len(self.available_cameras) == 0: + self.status_label.setText("No cameras detected") QMessageBox.warning(self, "Warning", "No cameras detected!") - print("Error: No available cameras detected.") else: - print(f"Detected {len(self.available_cameras)} cameras") + self.status_label.setText(f"Found {len(self.available_cameras)} cameras") def change_camera(self, index): - if index >= 0: # Only change if a valid camera is selected - self.camera_index = self.camera_select.itemData(index) + if index >= 0 and index < len(self.available_cameras): + self.camera_index, backend = self.camera_select.itemData(index) if self.cap is not None and self.cap.isOpened(): self.stop_camera() self.start_camera() @@ -129,24 +247,32 @@ class CameraApp(QMainWindow): if self.cap is not None: self.stop_camera() + if not self.available_cameras: + QMessageBox.warning(self, "Error", "No cameras available") + return + try: - self.cap = cv2.VideoCapture(self.camera_index, cv2.CAP_DSHOW) + current_index = max(0, self.camera_select.currentIndex()) + self.camera_index, backend = self.camera_select.itemData(current_index) + + self.cap = cv2.VideoCapture(self.camera_index, backend) if not self.cap.isOpened(): QMessageBox.warning(self, "Error", f"Cannot open camera {self.camera_index}") - print(f"Error: Cannot open camera {self.camera_index}") + self.status_label.setText(f"Failed to open camera {self.camera_index}") return - # Set camera properties for better performance + # Set camera properties self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) - self.cap.set(cv2.CAP_PROP_FPS, 30) + self.cap.set(cv2.CAP_PROP_FPS, 60) + self.cap.set(cv2.CAP_PROP_AUTOFOCUS, 0) self.timer.start(30) - print(f"Started camera {self.camera_index}") + self.status_label.setText(f"Camera {self.camera_index} started") except Exception as e: QMessageBox.critical(self, "Error", f"Error starting camera: {str(e)}") - print(f"Error starting camera: {str(e)}") + self.status_label.setText(f"Error: {str(e)}") def stop_camera(self): if self.cap: @@ -154,45 +280,92 @@ class CameraApp(QMainWindow): self.cap.release() self.cap = None self.video_label.clear() - print("Camera stopped") + self.status_label.setText("Camera stopped") + + if self.detection_thread: + self.detection_thread.stop() + self.detection_thread = None def load_yolo(self): - # Download YOLO files if they don't exist - weights_path = "yolov3.weights" - config_path = "yolov3.cfg" + weights_url = "https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights" + config_url = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg" + classes_url = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names" + + weights_path = "yolov4-tiny.weights" + config_path = "yolov4-tiny.cfg" classes_path = "coco.names" - if not all(os.path.exists(f) for f in [weights_path, config_path, classes_path]): - QMessageBox.information(self, "Download", "Downloading YOLO model files. This may take a moment...") - self.download_yolo_files() + files_valid = True + for path, min_size in [(weights_path, 10000000), (config_path, 10000), (classes_path, 1000)]: + if not os.path.exists(path) or os.path.getsize(path) < min_size: + files_valid = False + break + + if not files_valid: + reply = QMessageBox.question( + self, "Download Files", + "YOLO model files need to be downloaded (~25MB). Continue?", + QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) + + if reply == QMessageBox.No: + self.status_label.setText("Object detection disabled - model not loaded") + return + + self.download_yolo_files(weights_url, config_url, classes_url) try: - self.net = cv2.dnn.readNet(weights_path, config_path) + self.net = cv2.dnn.readNetFromDarknet(config_path, weights_path) + + if cv2.cuda.getCudaEnabledDeviceCount() > 0: + self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) + self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) + self.status_label.setText("Using CUDA acceleration") + else: + self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) + self.status_label.setText("Using CPU (no CUDA available)") + with open(classes_path, "r") as f: self.classes = [line.strip() for line in f.readlines()] layer_names = self.net.getLayerNames() self.output_layers = [layer_names[i - 1] for i in self.net.getUnconnectedOutLayers()] - print("YOLO model loaded successfully") + self.model_loaded = True + self.status_label.setText("YOLOv4 model loaded successfully") + except Exception as e: - print(f"Error loading YOLO model: {str(e)}") + self.model_loaded = False + self.status_label.setText(f"Error loading model: {str(e)}") QMessageBox.warning(self, "Error", "Failed to load object detection model") - def download_yolo_files(self): + def download_yolo_files(self, weights_url, config_url, classes_url): files = { - "yolov3.weights": "https://pjreddie.com/media/files/yolov3.weights", - "yolov3.cfg": "https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg", - "coco.names": "https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names" + "yolov4-tiny.weights": weights_url, + "yolov4-tiny.cfg": config_url, + "coco.names": classes_url } progress_dialog = DownloadProgressBar(self) progress_dialog.show() - for file_name, url in files.items(): - if not os.path.exists(file_name): + try: + for file_name, url in files.items(): + if os.path.exists(file_name): + try: + if file_name == "yolov4-tiny.weights" and os.path.getsize(file_name) < 10000000: + raise ValueError("Incomplete weights file") + elif file_name == "yolov4-tiny.cfg" and os.path.getsize(file_name) < 10000: + raise ValueError("Incomplete config file") + elif file_name == "coco.names" and os.path.getsize(file_name) < 1000: + raise ValueError("Incomplete names file") + continue + except Exception as e: + print(f"Existing file {file_name} is invalid: {str(e)}") + print(f"Downloading {file_name}...") - progress_dialog.set_file_label(file_name) + progress_dialog.update_label(file_name) + try: progress_handler = DownloadProgressHandler(progress_dialog) urllib.request.urlretrieve( @@ -204,91 +377,87 @@ class CameraApp(QMainWindow): except Exception as e: print(f"Error downloading {file_name}: {str(e)}") QMessageBox.critical(self, "Error", f"Failed to download {file_name}") + progress_dialog.close() + return - progress_dialog.close() - - def detect_objects(self, frame): - if self.net is None or self.classes is None: - return frame - - height, width, _ = frame.shape - blob = cv2.dnn.blobFromImage(frame, 0.00392, (416, 416), (0, 0, 0), True, crop=False) - - self.net.setInput(blob) - outs = self.net.forward(self.output_layers) - - # Showing information on the screen - class_ids = [] - confidences = [] - boxes = [] - - # Showing information on the screen - for out in outs: - for detection in out: - scores = detection[5:] - class_id = np.argmax(scores) - confidence = scores[class_id] - if confidence > 0.5: - # Object detected - center_x = int(detection[0] * width) - center_y = int(detection[1] * height) - w = int(detection[2] * width) - h = int(detection[3] * height) - - # Rectangle coordinates - x = int(center_x - w / 2) - y = int(center_y - h / 2) - - boxes.append([x, y, w, h]) - confidences.append(float(confidence)) - class_ids.append(class_id) - - indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) - - for i in range(len(boxes)): - if i in indexes: - x, y, w, h = boxes[i] - label = str(self.classes[class_ids[i]]) - confidence = confidences[i] - color = (0, 255, 0) # Green - cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2) - cv2.putText(frame, f"{label} {confidence:.2f}", (x, y - 10), - cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) - - return frame + finally: + progress_dialog.close() def update_frame(self): if self.cap is None or not self.cap.isOpened(): return ret, frame = self.cap.read() - if ret: - # Perform object detection - frame = self.detect_objects(frame) - - # Convert the frame from BGR to RGB - rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - h, w, ch = rgb_image.shape - bytes_per_line = ch * w - - # Convert the frame to QImage - q_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) - - # Scale the image to fit the label while maintaining aspect ratio - scaled_pixmap = QPixmap.fromImage(q_image).scaled( - self.video_label.size(), - aspectRatioMode=1 # Qt.KeepAspectRatio - ) - self.video_label.setPixmap(scaled_pixmap) + if not ret: + self.status_label.setText("Failed to capture frame") + return + + self.frame_count += 1 + current_time = time.time() + if current_time - self.last_fps_update >= 1.0: + self.fps = self.frame_count / (current_time - self.last_fps_update) + self.last_fps_update = current_time + self.frame_count = 0 + self.status_label.setText(f"Running at {self.fps:.1f} FPS") + + rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + if self.detection_enabled and self.model_loaded: + if self.detection_thread is None or not self.detection_thread.isRunning(): + self.detection_thread = DetectionThread(self.net, self.classes, self.output_layers, rgb_frame) + self.detection_thread.detection_done.connect(self.display_frame) + self.detection_thread.start() + else: + self.display_frame(rgb_frame) else: - print("Failed to get frame from camera") + self.display_frame(rgb_frame) + + def display_frame(self, frame): + h, w, ch = frame.shape + bytes_per_line = ch * w + q_image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888) + + scaled_pixmap = QPixmap.fromImage(q_image).scaled( + self.video_label.size(), + Qt.KeepAspectRatio, + Qt.SmoothTransformation + ) + self.video_label.setPixmap(scaled_pixmap) + + def take_snapshot(self): + if self.cap is None or not self.cap.isOpened(): + QMessageBox.warning(self, "Warning", "No active camera to take snapshot from") + return + + ret, frame = self.cap.read() + if not ret: + QMessageBox.warning(self, "Warning", "Failed to capture frame") + return + + options = QFileDialog.Options() + file_name, _ = QFileDialog.getSaveFileName( + self, "Save Snapshot", "", + "JPEG Images (*.jpg *.jpeg);;PNG Images (*.png)", + options=options) + + if file_name: + rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + success = cv2.imwrite(file_name, rgb_frame) + if success: + self.status_label.setText(f"Snapshot saved to {file_name}") + else: + QMessageBox.warning(self, "Error", "Failed to save snapshot") def closeEvent(self, event): self.stop_camera() + if self.detection_thread: + self.detection_thread.stop() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) + app.setStyle("Fusion") + window = CameraApp() window.show() sys.exit(app.exec_()) \ No newline at end of file diff --git a/opencam/yolov4-tiny.cfg b/opencam/yolov4-tiny.cfg new file mode 100644 index 0000000..d990b51 --- /dev/null +++ b/opencam/yolov4-tiny.cfg @@ -0,0 +1,294 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=1 +width=416 +height=416 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 + +max_batches = 2000200 +policy=steps +steps=1600000,1800000 +scales=.1,.1 + + +#weights_reject_freq=1001 +#ema_alpha=0.9998 +#equidistant_point=1000 +#num_sigmas_reject_badlabels=3 +#badlabels_rejection_percentage=0.2 + + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +################################## + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + + +[yolo] +mask = 3,4,5 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=80 +num=6 +jitter=.3 +scale_x_y = 1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +ignore_thresh = .7 +truth_thresh = 1 +random=0 +resize=1.5 +nms_kind=greedynms +beta_nms=0.6 +#new_coords=1 +#scale_x_y = 2.0 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 23 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 1,2,3 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=80 +num=6 +jitter=.3 +scale_x_y = 1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +ignore_thresh = .7 +truth_thresh = 1 +random=0 +resize=1.5 +nms_kind=greedynms +beta_nms=0.6 +#new_coords=1 +#scale_x_y = 2.0 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b916dac --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +PyQt5>=5.15.0 +opencv-python>=4.5.0 +numpy>=1.19.0