screwdriver/Milwaukee.py
2025-02-06 16:10:58 +08:00

363 lines
17 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import copy
import threading
import time
from datetime import datetime
import sys
from PyQt5.QtGui import QImage, QPixmap, QColor
from PyQt5.QtWidgets import QFileDialog, QApplication, QTableWidgetItem, QHeaderView, QWidget
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
from Main import Ui_MainWindow
from ScrewDrive import ScrewDrive
from Camera import Camera
from Modbus import Modbus
from Screwdriver_Database import DB_MainWindow
from Motor import Motor
from ROI_Window.ROI import ROIWindow
import logging
from Myini import Myini
# pip install -r C:\Users\YC03SRA003\Desktop\0507ProgramBackup\package_new.txt
'''
pip install psycopg2
pip install pyserial
pip install SerialPort
pip install pypylon
pip install PyQt5
'''
class Main_Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self) # 創建主界面對象
self.setupUi(self)
self.iniLogging()
self.dev_logger.info('Program Start')
self.iniGuiEvent()
self.label_image_Main.setScaledContents(True)
self.label_image_Result.setScaledContents(True)
self.MYINI = Myini()
self.motor = Motor()
if self.motor.Motor_isOpen == False:
self.pushButton_MotorMove.setEnabled(False)
self.pushButton_MotorMove.setText('馬達未連線')
self.pushButton_MotorMove.setStyleSheet('color: red')
self.pushButton_MotorMove.setEnabled(False)
# self.serialPort = SerialPort()
self.modbus = Modbus(self.dev_logger)
if self.modbus.Modbus_isOpen is False:
self.pushButton_Light_Control.setEnabled(False)
self.pushButton_Light_Control.setText('IO卡未連線')
self.pushButton_Light_Control.setStyleSheet('color: red')
# self.screwdrive = ScrewDrive(r".\model")
# self.screwdrive = ScrewDrive(r".\models")
# self.screwdrive.report.connect(self.NG_Report)
# self.screwdrive.output_finish.connect(self.receive_output_message_Finish)
# self.screwdrive.status.connect(self.statusChange)
# self.Identity = ['alpha', 'beta', 'gamma', 'delta']
self.screwdrives = list()
for i, k in enumerate(self.MYINI.Identity_CodeName):
sd = ScrewDrive(r".\model", self.dev_logger, k, myIni=self.MYINI)
sd.report.connect(self.NG_Report)
sd.status.connect(self.statusChange)
sd.output_finish.connect(self.receive_output_message_Finish)
self.screwdrives.append(sd)
self.tableWidget_OutputMessage.setColumnCount(4)
self.tableWidget_OutputMessage.setRowCount(10)
self.tableWidget_OutputMessage.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget_OutputMessage.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)
self.tableWidget_OutputMessage_AllResult.setColumnCount(7)
self.tableWidget_OutputMessage_AllResult.setRowCount(10)
self.tableWidget_OutputMessage_AllResult.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget_OutputMessage_AllResult.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)
self.camera = Camera()
if self.camera.Camera_isOpen:
self.camera.FreeRun.connect(self.freerun)
else:
self.pushButton_cameralink.setEnabled(False)
self.pushButton_cameralink.setText('相機未連線')
self.pushButton_cameralink.setStyleSheet('color: red')
self.pushButton_Grab.setEnabled(False)
self.comboBox_recipe.addItems([recipe for recipe in self.MYINI.recipes])
# self.AI_Light()
self.dbwindow = DB_MainWindow()
self.pushButton_Grab.setEnabled(False)
self.Operate_stop()
# self.ExposureTimeTuple = (46103, 48103, 50103, 52103, 54103)
def iniLogging(self):
logging_FileName = time.strftime('%Y%m%d')
self.dev_logger: logging.Logger = logging.getLogger(name='dev')
self.dev_logger.setLevel(logging.DEBUG)
handler: logging.StreamHandler = logging.StreamHandler()
formatter: logging.Formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s')
handler.setFormatter(formatter)
self.dev_logger.addHandler(handler)
file_handler: logging.FileHandler = logging.FileHandler(rf'.\Logging\{logging_FileName}_dev.log', mode='a')
file_handler.setFormatter(formatter)
self.dev_logger.addHandler(file_handler)
def iniGuiEvent(self):
self.pushButton_Seach.clicked.connect(self.Main)
self.pushButton_cameralink.clicked.connect(self.CameraLink)
self.pushButton_Grab.clicked.connect(self.CameraGrab)
self.pushButton_ROIWindow.clicked.connect(self.Open_ROIWindow)
self.pushButton_Database_Window.clicked.connect(self.Open_DBWindow)
self.horizontalSlider_ExposureTime.valueChanged.connect(self.WantToCreateExposureTime)
self.pushButton_Light_Control.clicked.connect(self.IO_Control)
self.pushButton_MotorMove.clicked.connect(self.motorGO)
self.pushButton_NGReset.clicked.connect(self.Operate_stop)
self.comboBox_recipe.currentIndexChanged.connect(self.Recipe_Change)
def Recipe_Change(self):
try:
self.camera.Recipe_Change(self.comboBox_recipe.currentText())
self.dev_logger.info(f'Recipe_Change {self.MYINI.recipe} --> {self.comboBox_recipe.currentText()}')
self.MYINI.recipe_change(self.comboBox_recipe.currentText())
self.screwdrives.clear()
for i, k in enumerate(self.MYINI.Identity_CodeName):
sd = ScrewDrive(r".\model", self.dev_logger, k, myIni=self.MYINI)
sd.report.connect(self.NG_Report)
sd.status.connect(self.statusChange)
sd.output_finish.connect(self.receive_output_message_Finish)
self.screwdrives.append(sd)
except Exception as e:
self.dev_logger.error(
f'Recipe_Change {self.MYINI.recipe} --> {self.comboBox_recipe.currentText()}\n{e}')
def motorGO(self):
if self.motor.Motor_isOpen:
self.motor.Move()
def Operate_start(self):
if self.motor.Motor_isOpen:
self.motor.Off()
self.motor.Green()
def Operate_stop(self):
if self.motor.Motor_isOpen:
self.motor.Off()
self.motor.Yellow()
def DetectNG(self):
if self.motor.Motor_isOpen:
self.motor.Off()
# self.motor.Buzzer()
self.motor.Red()
def IO_Control(self):
if self.pushButton_Light_Control.text() == 'AOILight':
self.AOI_Light()
self.pushButton_Light_Control.setText('AILight')
else:
self.AI_Light()
self.pushButton_Light_Control.setText('AOILight')
def AI_Light(self):
# self.horizontalSlider_ExposureTime.setValue(40000)
if self.modbus.Modbus_isOpen:
if self.modbus.com1_Status:
self.modbus.com1_off()
self.modbus.com1_Status = not self.modbus.com1_Status
if self.modbus.com2andcom3_Status is False:
self.modbus.com2andcom3_on()
self.modbus.com2andcom3_Status = not self.modbus.com2andcom3_Status
def AOI_Light(self):
# self.horizontalSlider_ExposureTime.setValue(25000)
if self.modbus.Modbus_isOpen:
if self.modbus.com2andcom3_Status:
self.modbus.com2andcom3_off()
self.modbus.com2andcom3_Status = not self.modbus.com2andcom3_Status
if self.modbus.com1_Status is False:
self.modbus.com1_on()
self.modbus.com1_Status = not self.modbus.com1_Status
def Open_ROIWindow(self):
self.roiwindow = ROIWindow(self.camera, self.screwdrives[0], self.motor, self.MYINI)
self.roiwindow.show()
def Open_DBWindow(self):
self.dbwindow.show()
def closeEvent(self, event):
QApplication.closeAllWindows()
print('MainWindow was closed')
self.motor.Off()
self.modbus.com_all_off()
self.motor.Motor_isForwards = True
self.motor.Move()
def WantToCreateExposureTime(self):
self.camera.SetExposureTime(float(self.horizontalSlider_ExposureTime.value()))
self.label_ExposureTime.setText(str(self.horizontalSlider_ExposureTime.value()))
def CameraLink(self):
self.camera.start()
self.pushButton_cameralink.setEnabled(False)
self.pushButton_Grab.setEnabled(True)
def CameraGrab(self):
self.Operate_start()
self.motorGO()
self.AI_Light()
time.sleep(1)
self.label_status.setText('calculating')
self.dbwindow.reset_data()
self.dbwindow.creat_Serial_Number()
self.dbwindow.aoi_start = datetime.now()
self.starttime_ALLTIME = time.time()
self.tableWidget_OutputMessage.clear()
self.tableWidget_OutputMessage_AllResult.clear()
self.messages_Finish_count = 0
self.All_AIPass = True
self.All_Report_count = 0
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
threading.Thread(target=self.camera.SetExposureTime, args=(self.MYINI.Camera_Setting['exposuretime_aoi'],)).start()
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
for sd in self.screwdrives:
sd.Result = self.Result
sd.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
sd.Main(1, self.dbwindow.aoi_start)
# self.camera.SetExposureTime(float(100000))
self.AOI_Light()
time.sleep(0.15)
# cv2.imwrite(rf'./AI.png', self.screwdrive.image_AI)
for sd in self.screwdrives:
sd.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1), cv2.COLOR_BGR2GRAY)
sd.AOIimage_ISREADY = True
print(f'!!AOI拍照時間 : {time.time() - self.starttime_ALLTIME}')
# cv2.imwrite(rf'./AOI.png', self.screwdrive.image_AOI)
# self.horizontalSlider_ExposureTime.setValue(27000)
threading.Thread(target=self.After_CameraGrab, args=()).start()
def After_CameraGrab(self):
self.motorGO()
self.camera.SetExposureTime(self.MYINI.Camera_Setting['exposuretime_ai'])
if self.modbus.com1_Status:
self.modbus.com1_off()
self.modbus.com1_Status = not self.modbus.com1_Status
def freerun(self):
image = self.camera.Image_RealTime
self.imageLable_Show(self.label_image_Main, image)
def Seach(self):
for i in range(0, 2):
filename, _ = QFileDialog.getOpenFileName(self, 'Open Image', r'D:\ScrewdriverFile\ScrewdriverImage', 'Image Files(*.png *.jpg *.bmp *.jpeg)')
self.inputimage_filename = filename
if filename:
try:
self.inputimage = cv2.imread(filename, cv2.IMREAD_COLOR)
# self.inputimage = self.rotate_and_mirror(self.inputimage)
if i == 0:
self.Result = cv2.flip(self.inputimage, 1)
self.screwdrive.Result = self.Result
# self.inputimage = cv2.imdecode(np.fromfile(filename, dtype=np.uint8), -1)
self.imageLable_Show(self.label_image_Main, self.inputimage)
elif i == 1:
self.Result_2 = cv2.flip(self.inputimage, 1)
self.Result_2 = cv2.cvtColor(self.Result_2, cv2.COLOR_BGR2GRAY)
except BaseException as e:
print('openFiles:', e)
def Main(self):
self.label_status.setText('caculating')
self.dbwindow.reset_data()
self.dbwindow.creat_Serial_Number()
self.dbwindow.aoi_start = datetime.now()
self.Seach()
self.tableWidget_OutputMessage.clear()
self.tableWidget_OutputMessage_AllResult.clear()
self.All_Report_count = 0
self.All_AIPass = True
Result_Gray = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
self.screwdrive.Main(1)
self.messages_Finish_count = 0
def NG_Report(self, is_OK, confidence, Index, diameter, numberofvertices):
item = QTableWidgetItem(self.MYINI.Class_Name_All[Index])
self.tableWidget_OutputMessage_AllResult.setItem(self.All_Report_count, 0, item)
if is_OK == 1:
item = QTableWidgetItem('正確')
else:
if is_OK == 404:
item = QTableWidgetItem('NotValid')
item.setBackground(QColor(29, 230, 181))
else:
item = QTableWidgetItem('錯誤')
item.setBackground(QColor(254, 142, 109))
if self.dbwindow.ng_bits_index == '':
self.dbwindow.ng_bits_index = self.All_Report_count + 1
else:
self.dbwindow.ng_bits_index = f'{self.dbwindow.ng_bits_index},{self.All_Report_count + 1}'
self.tableWidget_OutputMessage_AllResult.setItem(self.All_Report_count, 1, item)
confidences = confidence.split(',')
for i, cf in enumerate(confidences):
item = QTableWidgetItem(cf)
self.tableWidget_OutputMessage_AllResult.setItem(self.All_Report_count, 2 + i, item)
item = QTableWidgetItem(diameter)
self.tableWidget_OutputMessage_AllResult.setItem(self.All_Report_count, 3, item)
item = QTableWidgetItem(numberofvertices)
self.tableWidget_OutputMessage_AllResult.setItem(self.All_Report_count, 4, item)
self.All_Report_count += 1
self.tableWidget_OutputMessage_AllResult.setRowCount(self.All_Report_count + 1)
if self.All_Report_count == len(self.MYINI.Class_Name_All):
if self.dbwindow.ng_bits_index == '':
self.dbwindow.pass_or_failure = True
self.Operate_stop()
else:
self.DetectNG()
formatted_time = self.dbwindow.aoi_start.strftime('%Y%m%d_%H%M%S')
cv2.imwrite(f'./Defect AI Image/{formatted_time}.png', self.Result)
if is_OK == 0:#AI False
self.All_AIPass = False
def statusChange(self, statusNow):
# if self.All_AIPass or self.checkBox_saveImage.isChecked():
# output_file_name = f'{self.camera.cam.ExposureTime.GetValue()}.png'
# output_file_path = fr"D:\ScrewdriverFile\ScrewdriverImage\0922\{output_file_name}"
# cv2.imwrite(output_file_path, self.inputimage)
print('statusChange')
if statusNow:
self.imageLable_Show(self.label_image_Result, self.Result)
self.label_status.setText('end')
self.dbwindow.aoi_end = datetime.now()
print(f'!!ALLTIME : {time.time() - self.starttime_ALLTIME}')
starttime = time.time()
self.dbwindow.write_data()
endtime = time.time()
print(f'!!上傳資料庫 : {endtime - starttime}')
print(f'********************結束********************')
def imageLable_Show(self, image_label, Show_image):
Show_image = cv2.cvtColor(Show_image, cv2.COLOR_BGR2RGB) # 圖像存儲使用8-8-8 24位RGB格式
rows, cols, channels = Show_image.shape # 獲取圖片長寬
QImg = QImage(Show_image.data, cols, rows, cols*channels, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(QImg)
image_label.setPixmap(pixmap)
def rotate_and_mirror(self, input_image):
# 進行順時針旋轉90度
rotated_img = cv2.rotate(input_image, cv2.ROTATE_90_CLOCKWISE)
# 沿著Y軸鏡射
mirrored_img = cv2.flip(rotated_img, 1)
return mirrored_img
def receive_output_message_Finish(self, image_number, type, succese, failure_type):
item = QTableWidgetItem(image_number)
self.tableWidget_OutputMessage.setItem(self.messages_Finish_count, 0, item)
item = QTableWidgetItem(type)
self.tableWidget_OutputMessage.setItem(self.messages_Finish_count, 1, item)
item = QTableWidgetItem(succese)
self.tableWidget_OutputMessage.setItem(self.messages_Finish_count, 2, item)
item = QTableWidgetItem(failure_type)
self.tableWidget_OutputMessage.setItem(self.messages_Finish_count, 3, item)
self.messages_Finish_count += 1
self.tableWidget_OutputMessage.setRowCount(self.messages_Finish_count+1)
if __name__ == '__main__':
app = QApplication(sys.argv) # 固定的PyQt5程式都需要QApplication對象。sys.argv是命令列參數清單確保程式可以按兩下運行
MyWindow = Main_Window() # 初始化
MyWindow.show() # 將視窗控制項顯示在螢幕上
sys.exit(app.exec_()) # 程式運行sys.exit方法確保程式完整退出