Source code for controllers.control_saving_media
"""
This module contains the SaveMedia class, which provides methods for saving images to a selected folder,
loading saved images into the GUI's list widget, recording videos, and other related functionalities.
"""
import cv2
import os
from PyQt6 import QtWidgets, QtCore, QtGui
[docs]
class SaveMedia:
"""
Class to handle saving images and recording videos in the application.
Attributes:
_controller: The main controller object.
_ui_object: The UI object.
_model: The model object.
__dir_save: The directory path for saving images.
__base_dir_save: The base directory path for saving images.
_record_option: The recording option.
_video_writer: The video writer object.
Methods:
__init__(self, main_control): Initializes the SaveMedia object.
_connect_event(self): Connects event signals to their respective slots.
save_image_ori_result(self, image_result=True): Saves an image to a selected folder.
load_saved_image_list(self, load=False): Loads saved images into the GUI's list widget.
add_widget_save_image(self, image, name_file, load=False): Adds a widget for a saved image to the list widget.
list_widget_saved_image_activated(self): Handles the activation of a saved image in the list widget.
onclick_clear_button_list_saved_image(self): Clears the saved image list.
onclick_record_video_button(self): Handles the click event on the Record Video button.
_enable_action_while_record(self, status=True): Enables or disables actions while recording video.
_check_status_record(self): Checks the status of Anypoint or Panorama recording.
set_position_frame_save_image(self, config, file_name, original=False): Sets the position of a saved frame in the configuration view.
"""
[docs]
def __init__(self, main_control):
self._controller = main_control
self._ui_object = self._controller.ui_object
self._model = self._controller.model
self.__dir_save = None
self.__base_dir_save = None
self._record_option = None
self._video_writer = None
self._file_name_vid = None
self._connect_event()
[docs]
def _connect_event(self):
self._ui_object.pushButton.clicked.connect(self.onclick_clear_button_list_saved_image)
self._ui_object.screenshoot_button.clicked.connect(self.save_image_ori_result)
self._ui_object.record_button.clicked.connect(self.onclick_record_video_button)
self._ui_object.record_button.setShortcut("Ctrl+R")
@property
def record_option(self):
"""
Get the recording option.
Return:
str: The recording option.
"""
return self._record_option
@record_option.setter
def record_option(self, value):
"""
Set the recording option.
Arg:
value (str): The recording option to be set.
"""
self._record_option = value
@property
def video_writer(self):
"""
Get the video writer.
Return:
Any: The video writer object.
"""
return self._video_writer
@video_writer.setter
def video_writer(self, value):
"""
Set the video writer.
Arg:
value (Any): The video writer object to be set.
"""
self._video_writer = value
[docs]
def save_image_ori_result(self, image_result=True):
"""
Save the current or resulting image to a selected folder.
Arg:
image_result (bool, optional): Determines whether to save the resulting image
(`True`) or the original image (`False`). Defaults to `True`.
Raise:
FileNotFoundError: If the base directory for saving images is not found.
"""
try:
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: save_image_ori_result(), Process save image in directory")
if self._controller.model.image_result is not None:
if not self.__base_dir_save:
try:
self.__base_dir_save = self._model.select_directory(parent_dir="../saved_image",
title="Select Folder")
except FileNotFoundError as e:
self._model.activity_logger.error(f"Failed to select directory: {str(e)}")
QtWidgets.QMessageBox.critical(None, "Error", f"Failed to select directory: {str(e)}")
return
if self.__base_dir_save:
if self._model.mode_view == "FisheyeView":
self.__dir_save = self.__base_dir_save + "/original/"
elif self._model.mode_view == "AnypointView":
self.__dir_save = self.__base_dir_save + "/anypoint/"
elif self._model.mode_view == "PanoramaView":
self.__dir_save = self.__base_dir_save + "/panorama/"
else:
self.__dir_save = self.__base_dir_save + "/unknown/"
if not os.path.exists(self.__dir_save):
try:
os.makedirs(self.__dir_save)
except OSError as e:
self._model.activity_logger.error(f"Failed to create directory: {str(e)}")
QtWidgets.QMessageBox.critical(None, "Error", f"Failed to create directory: {str(e)}")
return
image = self._model.image_result if image_result else self._model.image_original
try:
self._model.saving_media.save_image_file(image,
self.__dir_save,
self._model.main_config["Parameter_name"])
self._model.save_main_config_update()
self.load_saved_image_list(load=True)
QtWidgets.QMessageBox.information(None, "Information",
f"Image saved !!\n\nLoc @: {self.__dir_save}")
except Exception as e:
self._model.activity_logger.error(f"Error while saving image: {str(e)}")
QtWidgets.QMessageBox.critical(None, "Error", f"Failed to save image: {str(e)}")
else:
self._model.activity_logger.error("Base directory for saving images is not defined.")
QtWidgets.QMessageBox.critical(None, "Error", "Base directory for saving images is not defined.")
else:
self._model.activity_logger.error("No image to save. image_result is None.")
QtWidgets.QMessageBox.critical(None, "Error", "No image to save. image_result is None.")
print('save_image failed')
except Exception as e:
self._model.activity_logger.error(f"Unexpected error in save_image_ori_result: {str(e)}")
QtWidgets.QMessageBox.critical(None, "Error", f"Unexpected error: {str(e)}")
[docs]
def load_saved_image_list(self, load=False):
"""
Load saved images into the GUI's list widget.
Arg:
load (bool, optional): Whether to load the images into the list widget. Defaults to False.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: load_saved_image_list(), "
"Load saved image and show to user interface")
self._ui_object.listWidget_saved_image.clear()
saved_image_list = list(self._model.main_config["Image_saved"].keys())
for path_file in saved_image_list:
image = cv2.imread(path_file)
name_file = os.path.basename(path_file)
self.add_widget_save_image(image, name_file, load)
if self._model.debug_mode:
self._model.activity_logger.info(
f"Loading saved images number {saved_image_list.index((name_file, path_file))} "
"and displaying them in the user interface widget.")
[docs]
def add_widget_save_image(self, image, name_file, load=False):
"""
Add a new widget to the saved image list with the given image and file name.
Args:
image (numpy.ndarray): The image to be displayed in the widget.
name_file (str): The name of the image file.
load (bool, optional): Whether the widget is being added during load or not. Defaults to False.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: add_widget_save_image(), "
"Show widget image to user interface")
self._ui_object.listWidget_saved_image.setIconSize(QtCore.QSize(140, 120))
new_widget = QtWidgets.QListWidgetItem()
h, w, _ = image.shape
if h == w:
image_ = self._model.resize_image(image, 108)
else:
image_ = self._model.resize_image(image, 140)
image_pixmap = QtGui.QImage(
image_.data,
image_.shape[1],
image_.shape[0],
QtGui.QImage.Format.Format_RGB888).rgbSwapped()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(image_pixmap))
new_widget.setIcon(icon)
if load:
new_widget.setText(str(name_file))
else:
new_widget.setText(str(name_file) + ".png")
self._ui_object.listWidget_saved_image.addItem(new_widget)
self._model.saving_media.add_position_video_on_saved_image()
[docs]
def list_widget_saved_image_activated(self):
"""
Handle the activation of a saved image in the list widget.
The function sets the appropriate image view mode and opens the saved image.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: list_widget_saved_image_activated(), "
"List widget saved image activated")
self._model.model_save_image.load_saved_image = False
self._model.view_zoom_area.state_rubberband = False
config = self._controller.ctrl_config.load_config()
saved_image_list = list(config["Image_saved"].keys())
file_name = saved_image_list[self._ui_object.listWidget_saved_image.currentRow()]
config = self._controller.ctrl_config.load_config()
view = file_name.split('/')[-2]
if view == "original":
self._ui_object.widget_mode_view.setEnabled(True)
self._ui_object.widget_mode_view.hide()
if self._model.video:
self._controller.unlock_menu_state_view()
self.set_position_frame_save_image(config, file_name, True)
else:
self._controller.unlock_menu_state_view()
self._model.model_save_image.reopen_saved_image(config["Parameter_name"],
file_name)
self._ui_object.btn_fisheye_view.setStyleSheet(self._controller.ctrl_stylesheet.set_style_selected_menu())
elif view == "anypoint":
self._controller.lock_menu_state_view()
self._ui_object.btn_anypoint_view.setStyleSheet(self._controller.ctrl_stylesheet.set_style_selected_menu())
self._ui_object.widget_mode_view.show()
self._ui_object.frame_22.hide()
self._ui_object.widget_mode_view.setEnabled(False)
self._ui_object.widget_mode_view.setCurrentIndex(0)
self._model.model_save_image.reopen_saved_image(config["Parameter_name"], file_name)
elif view == "panorama":
self._controller.lock_menu_state_view()
self._ui_object.frame_22.hide()
self._ui_object.btn_panorama_view.setStyleSheet(self._controller.ctrl_stylesheet.set_style_selected_menu())
self._ui_object.widget_mode_view.show()
self._ui_object.widget_mode_view.setEnabled(False)
self._ui_object.widget_mode_view.setCurrentIndex(1)
self._model.model_save_image.reopen_saved_image(config["Parameter_name"], file_name)
else:
return
[docs]
def onclick_clear_button_list_saved_image(self):
"""
Clear the saved image list and the UI list widget.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: onclick_clear_button_list_saved_image(), "
"Click button clear list saved image")
config = self._controller.model.main_config
config["Image_saved"] = {}
self._controller.model.save_main_config_update()
self._ui_object.listWidget_saved_image.clear()
[docs]
def onclick_record_video_button(self):
"""
Handle the click event on the Record Video button.
This function displays an information message indicating that video recording is currently under development,
and unchecks the Record Video button.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: onclick_record_video_button(), Click button record video")
self.video_writer = None
if self._ui_object.record_button.isChecked():
if self._model.image_original is not None:
self._controller.ctrl_message_box.show_message_box_record()
if self.record_option is not None:
self.video_writer, self._file_name_vid = self._model.video_config.record_video_pressed(self.record_option)
if self.video_writer is not None:
self._enable_action_while_record(False)
self._controller.ctrl_message_box.display_message_box("Recording started!!", "Information")
self._ui_object.record_button.setIcon(QtGui.QIcon("icons:video_red.svg"))
else:
self._check_status_record()
else:
self._enable_action_while_record()
self._ui_object.record_button.setChecked(False)
else:
self._enable_action_while_record()
self._ui_object.record_button.setChecked(False)
else:
self._enable_action_while_record()
message = f"Recording finish, file saved on: \n{self._file_name_vid}"
self._controller.ctrl_message_box.display_message_box(message, "Information")
self._ui_object.record_button.setIcon(QtGui.QIcon("icons:video.svg"))
self.video_writer = None
[docs]
def _enable_action_while_record(self, status=True):
"""
Enable or disable certain actions while recording video.
Args:
status (bool): If True, enables the actions. If False, disables them.
Return:
None
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: _enable_action_while_record(), "
"Check action while record video")
if self.record_option == "Processed":
self._ui_object.doubleSpinBox_pano_car_crop_left.setEnabled(status)
self._ui_object.doubleSpinBox_pano_car_crop_right.setEnabled(status)
self._ui_object.doubleSpinBox_pano_car_crop_top.setEnabled(status)
self._ui_object.doubleSpinBox_pano_car_crop_bottom.setEnabled(status)
[docs]
def _check_status_record(self):
"""
Check the status of Anypoint or Panorama recording.
If video_writer is not None, it sets the record button status to False and displays an informational message
prompting the user to select Anypoint or Panorama View to record Processed Video.
Return:
None
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: _check_status_record(), "
"Check status Anypoint or Panorama record")
if self.video_writer is not None:
self._ui_object.record_button.setChecked(False)
self._controller.ctrl_media_player.show_message("Information",
"Select Anypoint or Panorama View to record Processed Video")
[docs]
def set_position_frame_save_image(self, config, file_name, original=False):
"""
This function sets the position of a saved frame from the `Image_saved` list in the configuration view.
If the timer is active, it will be stopped and the status will be emitted. If the parent path of the saved image
is the same as the media source, the position of the frame will be set and the next frame signal
will be emitted. If the parent path is different, the saved image will be reopened.
Args:
config
file_name (str): The name of the saved file.
original (bool, optional): Flag to indicate if the view is in original or not. Defaults to False.
"""
if self._model.debug_mode:
self._model.activity_logger.info("SaveMedia: set_position_frame_save_image(), "
"Set position frame save on video")
if self._controller.timer.isActive():
self._controller.timer.stop()
self._model.timer_status.emit(self._controller.timer.isActive())
if config["Image_saved"][file_name]["parent_path"] == config["Media_path"]:
if config["Image_saved"][file_name]["is_video"]:
pos = config["Image_saved"][file_name]["pos_frame"]
self._model.cap.set(cv2.CAP_PROP_POS_FRAMES, pos)
if original:
self._model.mode_view = "FisheyeView"
self._controller.next_frame_signal()
else:
self.reopen_saved_image(config["Parameter_name"], file_name)