1- # Developed By Sihab Sahariar
1+ __author__ = "Sihab Sahariar"
2+ __contact__ = "www.github.com/sihabsahariar"
3+ __credits__ = ["Pavel Bar" ]
4+ __version__ = "1.0.1"
5+
26import io
37import sys
8+ import time
49import argparse
510
611# import OpenCV module
712import cv2
813
9- import folium # pip install folium
14+ import folium
1015
1116# PyQt5 imports - Core
1217from PyQt5 .QtCore import QRect , QSize , QTimer , Qt , QCoreApplication , QMetaObject
1318# PyQt5 imports - GUI
14- from PyQt5 .QtGui import QPixmap , QImage , QFont
19+ from PyQt5 .QtGui import QPixmap , QImage , QFont , QPainter , QPen
1520# PyQt5 imports - Widgets
1621from PyQt5 .QtWidgets import (
1722 QApplication , QWidget , QHBoxLayout , QLabel , QFrame , QPushButton ,
2732
2833
2934class Ui_MainWindow (object ):
35+ # Main window dimensions constants
36+ WINDOW_WIDTH = 1117
37+ WINDOW_HEIGHT = 636
38+
3039 # Webcam widget dimensions constants
3140 WEBCAM_WIDTH = 321
3241 WEBCAM_HEIGHT = 331
33-
42+
3443 def __init__ (self , video_path = None ):
3544 self .video_path = video_path
36-
45+
3746 def setupUi (self , MainWindow ):
3847 MainWindow .setObjectName ("MainWindow" )
39- MainWindow .setFixedSize (1117 , 636 )
48+ MainWindow .setFixedSize (Ui_MainWindow . WINDOW_WIDTH , Ui_MainWindow . WINDOW_HEIGHT )
4049 MainWindow .setStyleSheet ("background-color: rgb(30, 31, 40);" )
4150 self .centralwidget = QWidget (MainWindow )
4251 self .centralwidget .setObjectName ("centralwidget" )
4352 self .label = QLabel (self .centralwidget )
44- self .label .setGeometry (QRect (0 , 0 , 1111 , 651 ))
53+ self .label .setGeometry (QRect (0 , 0 , Ui_MainWindow . WINDOW_WIDTH , Ui_MainWindow . WINDOW_HEIGHT ))
4554 self .label .setText ("" )
4655 self .label .setPixmap (QPixmap (":/bg/Untitled (1).png" ))
4756 self .label .setScaledContents (True )
@@ -671,7 +680,7 @@ def setupUi(self, MainWindow):
671680
672681 self .webcam = QLabel (self .frame_map )
673682 self .webcam .setObjectName (u"webcam" )
674- self .webcam .setGeometry (QRect (500 , 40 , self .WEBCAM_WIDTH , self .WEBCAM_HEIGHT ))
683+ self .webcam .setGeometry (QRect (500 , 40 , Ui_MainWindow .WEBCAM_WIDTH , Ui_MainWindow .WEBCAM_HEIGHT ))
675684
676685 MainWindow .setCentralWidget (self .centralwidget )
677686 self .show_dashboard ()
@@ -689,36 +698,65 @@ def setupUi(self, MainWindow):
689698)
690699 self .label_km .setAlignment (Qt .AlignCenter )
691700
692- def _read_video_frame (self ):
701+ def display_error_message (self , message ):
702+ """Display error message in the video area with proper styling."""
703+ # Create a QPixmap with the same dimensions as the webcam area
704+ error_pixmap = QPixmap (Ui_MainWindow .WEBCAM_WIDTH , Ui_MainWindow .WEBCAM_HEIGHT )
705+ error_pixmap .fill (Qt .black ) # Black background to match the UI
706+
707+ # Draw the error message on the pixmap
708+ painter = QPainter (error_pixmap )
709+ painter .setPen (QPen (Qt .red , 2 ))
710+ painter .setFont (QFont ("Arial" , 12 , QFont .Bold ))
711+
712+ # Draw border
713+ painter .drawRect (2 , 2 , Ui_MainWindow .WEBCAM_WIDTH - 4 , Ui_MainWindow .WEBCAM_HEIGHT - 4 )
714+
715+ # Draw error message in center
716+ painter .setPen (QPen (Qt .white , 1 ))
717+ text_rect = error_pixmap .rect ()
718+ text_rect .adjust (10 , 0 , - 10 , 0 ) # Add some margin
719+ painter .drawText (text_rect , Qt .AlignCenter | Qt .TextWordWrap , message )
720+
721+ painter .end ()
722+
723+ # Set the error pixmap to the webcam label
724+ self .webcam .setPixmap (error_pixmap )
725+
726+ @staticmethod
727+ def _read_video_frame ():
693728 """Read and validate a video frame from the capture device.
694-
729+
695730 Returns:
696731 numpy.ndarray: Valid image frame, or None if no valid frame available
697732 """
698733 ret , image = cap .read ()
699-
734+
700735 # Validate frame
701736 if not ret or image is None or image .size == 0 :
702737 return None
703-
738+
704739 return image
705740
706741 def view_video (self ):
707- image = self ._read_video_frame ()
742+ """Displays camera / video stream and handles errors."""
743+ image = Ui_MainWindow ._read_video_frame ()
708744
709745 # Check if frame is valid
710746 if image is None :
711747 # Video ended or no frame available
712748 if self .video_path :
713749 # For video files, restart from beginning (loop)
714750 cap .set (cv2 .CAP_PROP_POS_FRAMES , 0 )
715- image = self ._read_video_frame ()
751+ image = Ui_MainWindow ._read_video_frame ()
716752 if image is None :
717- # If still no frame, stop the timer
753+ # If still no frame, show error and stop the timer
754+ self .display_error_message ("Video file is unavailable or corrupted!\n \n Please check video file." )
718755 self .quit_video ()
719756 return
720757 else :
721- # For camera, stop the timer
758+ # For camera, show error and stop the timer
759+ self .display_error_message ("Camera is unavailable!\n \n Please check camera connection." )
722760 self .quit_video ()
723761 return
724762
@@ -729,8 +767,8 @@ def view_video(self):
729767 height , width , channel = image .shape
730768
731769 # Calculate scaling to fit within target area while maintaining aspect ratio
732- scale_w = self .WEBCAM_WIDTH / width
733- scale_h = self .WEBCAM_HEIGHT / height
770+ scale_w = Ui_MainWindow .WEBCAM_WIDTH / width
771+ scale_h = Ui_MainWindow .WEBCAM_HEIGHT / height
734772 scale = min (scale_w , scale_h ) # Use smaller scale to fit entirely
735773
736774 # Calculate new dimensions
@@ -762,6 +800,8 @@ def controlTimer(self):
762800 cap = cv2 .VideoCapture (self .video_path )
763801 else :
764802 cap = cv2 .VideoCapture (0 )
803+ # Give camera time to initialize for better robustness
804+ time .sleep (0.1 )
765805 self .timer .start (20 )
766806
767807 def retranslateUi (self , MainWindow ):
@@ -885,10 +925,26 @@ def progress(self):
885925 parser = argparse .ArgumentParser (description = 'Smart Car Dashboard GUI' )
886926 parser .add_argument ('--play-video' , metavar = 'path' , type = str , help = '[Optional] path to video file to play instead of camera' )
887927 args = parser .parse_args ()
888-
928+
929+ # Enable automatic high DPI scaling
930+ QApplication .setAttribute (Qt .AA_EnableHighDpiScaling , True )
931+ # Enable crisp rendering on high DPI displays
932+ QApplication .setAttribute (Qt .AA_UseHighDpiPixmaps , True )
933+ # Disable window context help button
934+ QApplication .setAttribute (Qt .AA_DisableWindowContextHelpButton , True )
935+
889936 app = QApplication (sys .argv )
890- MainWindow = QMainWindow ()
937+ main_app_window = QMainWindow ()
891938 ui = Ui_MainWindow (video_path = args .play_video )
892- ui .setupUi (MainWindow )
893- MainWindow .show ()
939+ ui .setupUi (main_app_window )
940+
941+ # Center window on screen
942+ screen = app .primaryScreen ()
943+ screen_geometry = screen .geometry ()
944+ window_geometry = main_app_window .frameGeometry ()
945+ center_point = screen_geometry .center ()
946+ window_geometry .moveCenter (center_point )
947+ main_app_window .move (window_geometry .topLeft ())
948+
949+ main_app_window .show ()
894950 sys .exit (app .exec_ ())
0 commit comments