# MoilApp with thread inspection application
# Writer: Haryanto
# Moil (Ming Chi University of Technology)
import cv2
import json
import numpy as np
import exif_lib
import datetime
from Moildev import Moildev
from Moildev import draw_polygon
from base_plugin import Plugin
from .widgets.Ui_MainWindow import *
from .process_image.anypoint import AnypointView
from .process_image.panorama import PanoramaView
from .controller.video_controller import VideoController
from .controller.select_source_camera import OpenCameraSource
from .help.help import open_information_moildev, help_moildev_apps, about_us
from .view.show_to_widgets import ShowImage
from .view.manipulate_view import ManipulateView
from .view.control_frame import FrameWidgets
from .controller.serial_controller import AxisController
from .tools.utils import select_file, resize_image, calculate_height, read_image
from .controller.mouse_control_event import MouseController
from .parameter_source.camera_parameters import CameraParameters
[docs]
class Controller(QtWidgets.QMainWindow):
# create public variable.
resized = QtCore.pyqtSignal()
camera_parameter = 'camera_parameters/camera_parameters.json'
def __init__(self, main_application):
"""
This Class is for control the widget event to the execute function.
Args:
main_application (): This argument send QWidget from main application.
This also be a parent of this class, which is can access the function and variable from that class
"""
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.parent = main_application
self.image = None
self.cap = None
self.cam = False
self.normal_view = True
self.panorama_view = False
self.anypoint_view = False
self.axis_controller = False
self.dir_save = None
self.mapX = None
self.mapY = None
self.mapX_pano = None
self.mapY_pano = None
self.moildev = None
self.type_camera = "Raspi"
self.num = 0
self.pos_x = 0
self.w = 0
self.h = 0
self.result_image = None
self.width_original_image = 300
self.width_result_image = 1400
self.angle = 0
self.connect_event()
self.openCam = QtWidgets.QDialog()
self.winOpenCam = OpenCameraSource(self, self.openCam)
self.camParams = QtWidgets.QDialog()
self.winCamParams = CameraParameters(self, self.camParams)
self.show_image = ShowImage(self)
self.video_controller = VideoController(self)
self.anypoint = AnypointView(self)
self.panorama = PanoramaView(self)
self.axis_control = AxisController(self)
self.control_mouse = MouseController(self)
self.manipulate = ManipulateView(self)
self.control_frame = FrameWidgets(self)
self.video_controller.set_button_disable()
self.ui.frame_panorama.hide()
self.ui.frame_navigator.hide()
self.ui.frame_axis.hide()
[docs]
def connect_event(self):
"""
Connect every event on user interface like button event, mouse event
and etc to the function processing.
"""
self.ui.actionLoad_Image.triggered.connect(self.open_image)
self.ui.actionLoad_Video.triggered.connect(self.onclick_load_video)
self.ui.actionOpen_Cam.triggered.connect(
self.onclick_open_camera_button)
self.ui.actionSave_Image.triggered.connect(self.save_image)
self.ui.actionAbout_Apps.triggered.connect(about_us)
self.ui.actionAbout_Us.triggered.connect(open_information_moildev)
self.ui.actionCamera_Parameters.triggered.connect(
self.open_cam_params_window)
self.ui.actionExit.triggered.connect(self.onclick_exit)
self.ui.btn_Open_Image.clicked.connect(self.open_image)
self.ui.btn_Home.clicked.connect(self.go_to_home_application)
self.ui.btn_Open_Cam.clicked.connect(self.onclick_open_camera_button)
self.ui.btn_Open_Video.clicked.connect(self.onclick_load_video)
self.ui.btn_Quit.clicked.connect(self.onclick_exit)
self.ui.btn_show_help.clicked.connect(self.help)
self.ui.btn_Save_Image.clicked.connect(self.save_image)
self.ui.listWidget.currentItemChanged.connect(
self.saved_image_activated)
self.ui.pushButton_29.clicked.connect(about_us)
self.ui.pushButton_18.clicked.connect(open_information_moildev)
self.ui.btn_normal.clicked.connect(self.show_normal)
# self.resized.connect(self.set_place_frame_parameter)
[docs]
def open_image(self):
"""
Open Dialog to search the file image from directory. This function also will read the comment from
metadata image.
"""
self.reset_mode_view()
if self.cam:
self.video_controller.stop_video()
self.cap.release()
filename = select_file(
"Select Image",
"../",
"Image Files (*.jpeg *.jpg *.png *.gif *.bmg)")
if filename:
img = exif_lib.MetaImage(filename)
self.type_camera = img.read_comment()
self.image = read_image(filename)
self.h, self.w = self.image.shape[:2]
self.video_controller.set_button_disable()
self.show_to_window()
self.cam = False
img.close()
[docs]
def connect_to_moildev(self):
"""
Connect to Moildev SDK, need provide camera parameter database and type of camera.
"""
if self.type_camera:
self.moildev = Moildev(self.camera_parameter, self.type_camera)
else:
QtWidgets.QMessageBox.warning(
self,
"Warning!!",
"The image not support for this application, \n\nPlease contact developer!!")
print("the image not support for this application, please contact developer!!")
[docs]
def onclick_load_video(self):
"""
Open Dialog to search video file from Directory. after you select the video file, it will show the prompt
to select the type of camera.
"""
self.reset_mode_view()
video_source = select_file(
"Select Video Files",
"../",
"Video Files (*.mp4 *.avi *.mpg *.gif *.mov)")
if video_source:
self.select_camera_type()
if self.type_camera is not None:
self.moildev = Moildev(self.camera_parameter, self.type_camera)
self.running_video(video_source)
[docs]
def select_camera_type(self):
"""
Select the camera type prompt.
"""
with open(self.camera_parameter) as f:
data = json.load(f)
new_list = []
for key in data.keys():
new_list.append(key)
self.Dialog = QtWidgets.QDialog()
self.Dialog.setObjectName("Dialog")
self.Dialog.setWindowTitle("Select Camera !!!")
self.Dialog.resize(240, 120)
buttonBox = QtWidgets.QDialogButtonBox(self.Dialog)
buttonBox.setGeometry(QtCore.QRect(20, 80, 200, 32))
buttonBox.setOrientation(QtCore.Qt.Horizontal)
buttonBox.setStandardButtons(
QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
buttonBox.setObjectName("buttonBox")
self.comboBox_cam_type = QtWidgets.QComboBox(self.Dialog)
self.comboBox_cam_type.setGeometry(QtCore.QRect(20, 40, 200, 30))
self.comboBox_cam_type.setObjectName("comboBox")
self.comboBox_cam_type.addItems(new_list)
label = QtWidgets.QLabel(self.Dialog)
label.setGeometry(QtCore.QRect(10, 10, 220, 30))
font = QtGui.QFont()
font.setFamily("DejaVu Serif")
font.setPointSize(13)
label.setFont(font)
label.setAlignment(QtCore.Qt.AlignCenter)
label.setObjectName("label")
label.setText("Select the camera type !!!")
buttonBox.accepted.connect(self.dialog_camera_oke)
buttonBox.rejected.connect(self.Dialog.reject)
self.Dialog.exec_()
[docs]
def dialog_camera_oke(self):
"""
The function will execute when you press accept or ok in dialog camera type selection.
"""
self.type_camera = self.comboBox_cam_type.currentText()
self.Dialog.close()
[docs]
def open_cam_params_window(self):
"""
Open the window of camera parameter form, this window you can update, add, and
delete the camera parameter from database.
"""
self.camParams.show()
[docs]
def open_camera(self):
"""
open the camera from the available source in the system,
this function provide 2 source namely USB cam and Streaming Cam from Raspberry pi.
"""
self.reset_mode_view()
camera_source = self.winOpenCam.camera_source_used()
self.select_camera_type()
if self.type_camera is not None:
self.moildev = Moildev(self.camera_parameter, self.type_camera)
self.running_video(camera_source)
[docs]
def running_video(self, video_source):
"""
Open Video following the source given.
Args:
video_source (): the source of media, can be camera and video file.
"""
self.video_controller.set_button_enable()
self.cap = cv2.VideoCapture(video_source)
_, image = self.cap.read()
if image is None:
QtWidgets.QMessageBox.information(
self, "Information", "No source camera founded")
else:
# print("here")
self.cam = True
self.video_controller.next_frame_slot()
[docs]
def show_normal(self):
"""
Showing the original image into Label frame in UI.
"""
if self.image is not None:
self.normal_view = True
self.panorama_view = False
self.anypoint_view = False
self.angle = 0
self.show_image.show_original_image(
self.image, self.width_original_image)
self.show_image.show_result_image(
self.image, self.width_result_image, self.angle)
self.ui.frame_navigator.hide()
self.ui.frame_panorama.hide()
# migrate to show result
[docs]
def show_to_window(self):
"""
Showing the processing result image into the frame UI.
"""
if self.normal_view:
self.show_image.show_original_image(
self.image, self.width_original_image)
self.show_image.show_result_image(
self.image, self.width_result_image, self.angle)
else:
if self.panorama_view:
# image = draw_polygon(
# self.image.copy(),
# self.mapX_pano,
# self.mapY_pano)
mapX = np.load(
'./plugins/Thread_inspection/process_image/maps_pano/mapX.npy')
mapY = np.load(
'./plugins/Thread_inspection/process_image/maps_pano/mapY.npy')
rho = self.panorama.rho
self.result_image = cv2.remap(
self.image,
mapX,
mapY,
cv2.INTER_CUBIC)
self.result_image = self.result_image[round(
rho + round(self.moildev.getRhoFromAlpha(30))):self.h, 0:self.w]
# print(self.width_result_image)
self.show_image.show_original_image(
self.image, self.width_original_image)
else:
image = draw_polygon(self.image.copy(), self.mapX, self.mapY)
self.result_image = cv2.remap(
self.image,
self.mapX,
self.mapY,
cv2.INTER_CUBIC)
self.show_image.show_original_image(
image, self.width_original_image)
self.show_image.show_result_image(
self.result_image, self.width_result_image, self.angle)
[docs]
def help(self):
"""
Showing the message box to show help information obout this application.
"""
self.openCam.close()
help_moildev_apps()
[docs]
def save_image(self):
"""
Save image into local directory, it can save original image or
result image from panorama or anypoint processing.
"""
if self.image is not None:
ss = datetime.datetime.now().strftime("%m%d%H_%M%S")
if self.normal_view:
image = self.image
else:
image = self.result_image
if self.dir_save is None or self.dir_save == "":
self.selectDir()
else:
name = self.dir_save + "/" + str(ss) + ".png"
cv2.imwrite(name, image)
img = exif_lib.MetaImage(name)
img.modify_comment(self.type_camera)
self.addWidget(image)
img.close()
QtWidgets.QMessageBox.information(
self, "Information", "Image saved !!\n\nLoc @: " + self.dir_save)
[docs]
def saved_image_activated(self):
"""
Function that for connect with the event in list widget to reopen the image.
"""
filename = self.dir_save + "/" + self.ui.listWidget.currentItem().text()
img = exif_lib.MetaImage(filename)
self.type_camera = img.read_comment()
if self.cam:
self.video_controller.pause_video()
self.reset_mode_view()
self.image = read_image(filename)
self.h, self.w = self.image.shape[:2]
img.close()
self.show_to_window()
[docs]
def selectDir(self):
"""
Select directory to save image. This function create to make it not always ask the directory by open dialog,
after directory save not None, it will pass open dialog prompt.
Returns:
None.
"""
self.dir_save = QtWidgets.QFileDialog.getExistingDirectory(
self, 'Select Save Folder')
if self.dir_save:
self.save_image()
[docs]
def reset_mode_view(self):
"""
Update the properties view when you reset.
"""
self.moildev = None
self.normal_view = True
self.ui.btn_Record_video.setChecked(False)
[docs]
def go_to_home_application(self):
"""
This function is for close the main window and show the home application
to chose another application
- self : represent the current user interface
- self parent : represent the home window to select the application
Returns:
Back to home apps!!
"""
if self.cam:
self.video_controller.stop_video()
self.cap.release()
self.parent.show()
self.hide()
[docs]
def onclick_exit(self):
"""
Function that connect to exit button to close tha window.
"""
self.close()
[docs]
def resizeEvent(self, event):
"""
Resize window event controller.
Args:
event ():
"""
self.resized.emit()
[docs]
def closeEvent(self, event):
"""
Control the close event by ask the question yes or no.
Args:
event ():
Returns:
"""
reply = QtWidgets.QMessageBox.question(
self,
'Message',
"Are you sure to quit?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.onclick_exit()
event.accept()
else:
event.ignore()
[docs]
class Internal_Inspection(Plugin):
def __init__(self):
"""
The class that represent the plugins application, class name will be read as
the name of application.
"""
super().__init__()
self.apps = None
self.description = "This is default application"