前言:大家好,我是一名高中物理教師,比較喜歡學習編程,由於平時批改作業比較忙,所以突然冒出個想法,做個攝像頭答題卡識別就會減輕我平時批改作業的很多負擔,特別是選擇題,重復性的勞動,意義不大,如果用機器代替工作那該多好呀,網上一搜,有很多教程,但是都不太滿意,所以我趁着躲避新冠在家隔離的這段時間,邊學邊做,終於做成了,還沒開學,等開學了就去試試,通過博客園,把我的心得分享給大家!
首先,我學習了三本書,python3.7 Pyqt5 opencv ,對我的幫助很大,感謝這幾本書的作者。
第二,軟件環境: anaconda(python3.7)+pycharm +pqty5 + opencv4.2.0+Excel2016 + 一堆庫
第三,硬件環境: 高拍儀(1000W像素,分辨率1920*1080)
、
第四,實現的功能: ①識別選擇題
②識別名字(用漢字區位碼)
③識別考號
④計算得分
⑤統計全班的每題得分率
⑥選擇題柱狀圖
第五,答題卡設置要求:橫平豎直,格子的寬高相同(我設置的是64行,23列),便於分割!
第六,識別部分:① 打開攝像頭,捕獲一幀。
② 對圖像四角變換
④ 把圖像分割,計算每個格子中塗卡面積占比
⑤ 輸出選項到列表
具體代碼:
#① 打開攝像頭,捕獲一幀。這里用了定時器,否則會卡 self.timer = QTimer() # 初始化定時器 self.timer.timeout.connect(self.time)#定時器信號 self.cap = cv2.VideoCapture(0) #打開視頻 self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1366)#圖像寬 self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 768) #圖像高 self.timer.start(1)
self.ret,self.frame = self.cap.read() #讀取內存中的幀
# ②對圖像四角變換 if (self.cap.isOpened()): M = cv2.getRotationMatrix2D((self.frame.shape[1] / 2, self.frame.shape[0] / 2), -90, 0.8) # 獲得旋轉矩陣 self.frame = cv2.warpAffine(self.frame, M, (self.frame.shape[1], self.frame.shape[0])) # 旋轉90度 gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # 轉換為灰度圖像 blurred = cv2.GaussianBlur(gray, (3, 3), 0) # 高斯濾波1 edged = cv2.Canny(blurred, 10, 100) # 邊緣檢測 #cv2.imshow('edged', edged) cnts = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 查找輪廓 cnts = cnts[1] if imutils.is_cv2() else cnts[0] # # 用以區分OpenCV2.4和OpenCV3 docCnt = None if len(cnts) > 0: # 確保至少有一個輪廓被找到 cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # 將輪廓按大小降序排序 for c in cnts: # 對排序后的輪廓循環處理 peri = cv2.arcLength(c, True) # 周長# 獲取近似的輪廓 approx = cv2.approxPolyDP(c, 0.02 * peri, True) # 如果近似輪廓有四個頂點,那么就認為找到了答題卡 if len(approx) == 4: docCnt = approx break self.framexianshi = self.frame.copy() # 復制原圖 self.paper = four_point_transform(self.frame, docCnt.reshape(4, 2)) # 對原始圖像進行四點透視變換 self.framexianshi = cv2.drawContours(self.framexianshi, cnts, 0, (0, 255, 0), 2) #畫綠邊輪廓
#③ 形態學變換(灰度 反向二值化 開運算 膨脹) paper = cv2.resize(self.paper, (1196, 1946)) # 重新縮放指定尺寸統一尺寸 便於分割 #cv2.imshow('suofanghou', paper) hanggao = paper.shape[0] hanggao_1 = hanggao // 64 liekuan = paper.shape[1] liekuan_1 = liekuan // 23 huidu = cv2.cvtColor(paper, cv2.COLOR_BGR2GRAY) # 灰度圖 t, erzhihua = cv2.threshold(huidu, 95, 255, cv2.THRESH_BINARY_INV) # 反向二值化 # cv2.imshow('erzhihua', erzhihua) k = np.ones((8, 8), np.uint8) # 開運算 kaiyunsuan = cv2.morphologyEx(erzhihua, cv2.MORPH_OPEN, k) # 開運算 # cv2.imshow('kaiyunsuan', kaiyunsuan) peng = np.ones((3, 3), np.uint8) kaiyunsuan = cv2.dilate(kaiyunsuan, peng) # 膨脹

#分割后的圖像 for heng in range(0, hanggao + hanggao_1, hanggao_1): # 顯示分割的橫線豎線 paper = cv2.line(paper, (0, heng), (liekuan, heng), (0, 0, 255), 1) # 顯示分割的橫線豎線 for j in range(0, liekuan, liekuan_1): # 顯示分割的橫線豎線 paper = cv2.line(paper, (j, 0), (j, liekuan), (0, 0, 255), 1) # 顯示分割的橫線豎線 cv2.imshow('paperbianxian1', paper)

# ④ 塗卡面積的占比 這里應該有更好的辦法,我只用了這個辦法來識別,把感興趣區域截取更小一些或許更好,這樣也完全夠了!姓名與考號與此法類似我就不再重復了!
# 插入列表時候多選我使用了字典處理的
for ii in range(0, 5): # 識別1-5 的選擇題 for jj in range(17, 21): lie = ii * liekuan_1 hang = jj * hanggao_1 baisemianji = cv2.countNonZero(kaiyunsuan[hang: hang + hanggao_1, lie: lie + liekuan_1]) # 塗卡的面積 quanbumianji = hanggao_1 * liekuan_1 # 全部的面積 ratio = baisemianji * 100 / quanbumianji # 塗卡比率; 比例; # print(ratio) if (ratio > self.mianjibaifenbi): if jj == 17: # print(f'第 {ii+1} 題選:A ') self.charuxuan[ii + 1].append('A') elif jj == 18: self.charuxuan[ii + 1].append('B') elif jj == 19: self.charuxuan[ii + 1].append('C') elif jj == 20: self.charuxuan[ii + 1].append('D') self.gengxinruxuan[ii + 1].append(''.join(self.charuxuan[ii + 1])) for ii in range(6, 11): # 識別6-10 的選擇題 for jj in range(17, 21): lie = ii * liekuan_1 hang = jj * hanggao_1 baisemianji = cv2.countNonZero(kaiyunsuan[hang: hang + hanggao_1, lie: lie + liekuan_1]) quanbumianji = kaiyunsuan[hanggao_1: hanggao_1 + hanggao_1, liekuan_1: liekuan_1 + liekuan_1].shape[0] * \ erzhihua[hang: hang + hanggao_1, lie: lie + liekuan_1].shape[1] ratio = baisemianji * 100 / quanbumianji # 比率; 比例; if (ratio > self.mianjibaifenbi): if jj == 17: self.charuxuan[ii].append('A') elif jj == 18: self.charuxuan[ii].append('B') elif jj == 19: self.charuxuan[ii].append('C') elif jj == 20: self.charuxuan[ii].append('D') self.gengxinruxuan[ii].append(''.join(self.charuxuan[ii])) for ii in range(12, 17): # 識別11-15 的選擇題 for jj in range(17, 21): lie = ii * liekuan_1 hang = jj * hanggao_1 baisemianji = cv2.countNonZero(kaiyunsuan[hang: hang + hanggao_1, lie: lie + liekuan_1]) quanbumianji = kaiyunsuan[hanggao_1: hanggao_1 + hanggao_1, liekuan_1: liekuan_1 + liekuan_1].shape[0] * \ erzhihua[hang: hang + hanggao_1, lie: lie + liekuan_1].shape[1] ratio = baisemianji * 100 / quanbumianji # 比率; 比例; # print(ratio) if (ratio > self.mianjibaifenbi): if jj == 17: self.charuxuan[ii - 1].append('A') elif jj == 18: self.charuxuan[ii - 1].append('B') elif jj == 19: self.charuxuan[ii - 1].append('C') elif jj == 20: self.charuxuan[ii - 1].append('D') self.gengxinruxuan[ii - 1].append(''.join(self.charuxuan[ii - 1])) for ii in range(18, 23): # 識別16-20 的選擇題 for jj in range(17, 21): lie = ii * liekuan_1 hang = jj * hanggao_1 baisemianji = cv2.countNonZero(kaiyunsuan[hang: hang + hanggao_1, lie: lie + liekuan_1]) quanbumianji = kaiyunsuan[hanggao_1: hanggao_1 + hanggao_1, liekuan_1: liekuan_1 + liekuan_1].shape[0] * \ erzhihua[hang: hang + hanggao_1, lie: lie + liekuan_1].shape[1] ratio = baisemianji * 100 / quanbumianji # 比率; 比例; if (ratio > self.mianjibaifenbi): if jj == 17: self.charuxuan[ii - 2].append('A') elif jj == 18: self.charuxuan[ii - 2].append('B') elif jj == 19: self.charuxuan[ii - 2].append('C') elif jj == 20: self.charuxuan[ii - 2].append('D') self.gengxinruxuan[ii - 2].append(''.join(self.charuxuan[ii - 2])) self.xuan = list(self.gengxinruxuan.values()) # 字典變成二維列表 self.xuan = list(chain.from_iterable(self.xuan)) # 二維列表變成一維 print(self.xuan) self.tishu = int(self.lineEdit_tishu.text()) self.xuan = self.xuan[: self.tishu] # 切片除題目數量 self.xuan[self.tishu:] = ' ' self.xuan = self.xuan[0:20]
第七,答案處理:① 把答案輸出到列表1
② 把學生選項輸出到列表2
③ 對比兩個列表的元素 判斷正誤
#① 判斷正確與否是請教QQ群里面的大神,我覺得每次請教可以用紅包的方式來請教,雖然都差錢,但是每次你花10元-20元的紅包來請教,一來你耽誤了別人的寶貴時間,二來別人看你的問題給你解答要動腦筋的,我覺得付費是理所當然的 for i in range(len(self.answer)): dd = set(self.answer[i].upper()) xx = set(self.xuan[i].upper()) if xx == dd and self.answer[i] != '': self.right = self.right + 1 if i == 0: self.lineEdit_001.setStyleSheet("color:rgb(0, 170, 0)") self.label_001.setText('第1題√ ') self.label_001.setStyleSheet("color: rgb(0, 170, 0)") elif i == 1: self.lineEdit_002.setStyleSheet("color:rgb(0, 170, 0)") self.label_002.setText('第2題√ ') self.label_002.setStyleSheet("color:rgb(0, 170, 0)") elif i == 2: self.lineEdit_003.setStyleSheet("color:rgb(0, 170, 0)") self.label_003.setText('第3題√ ') self.label_003.setStyleSheet("color:rgb(0, 170, 0)") elif i == 3: self.lineEdit_004.setStyleSheet("color:rgb(0, 170, 0)") self.label_004.setText('第4題√ ') self.label_004.setStyleSheet("color:rgb(0, 170, 0)") elif i == 4: self.lineEdit_005.setStyleSheet("color:rgb(0, 170, 0)") self.label_005.setText('第5題√ ') self.label_005.setStyleSheet("color:rgb(0, 170, 0)") elif i == 5: self.lineEdit_006.setStyleSheet("color:rgb(0, 170, 0)") self.label_006.setText('第6題√ ') self.label_006.setStyleSheet("color:rgb(0, 170, 0)") elif i == 6: self.lineEdit_007.setStyleSheet("color:rgb(0, 170, 0)") self.label_007.setText('第7題√ ') self.label_007.setStyleSheet("color:rgb(0, 170, 0)") elif i == 7: self.lineEdit_008.setStyleSheet("color:rgb(0, 170, 0)") self.label_008.setText('第8題√ ') self.label_008.setStyleSheet("color:rgb(0, 170, 0)") elif i == 8: self.lineEdit_009.setStyleSheet("color:rgb(0, 170, 0)") self.label_009.setText('第9題√ ') self.label_009.setStyleSheet("color:rgb(0, 170, 0)") elif i == 9: self.lineEdit_010.setStyleSheet("color:rgb(0, 170, 0)") self.label_010.setText('10題√ ') self.label_010.setStyleSheet("color:rgb(0, 170, 0)") elif i == 10: self.lineEdit_011.setStyleSheet("color:rgb(0, 170, 0)") self.label_011.setText('11題√ ') self.label_011.setStyleSheet("color:rgb(0, 170, 0)") elif i == 11: self.lineEdit_012.setStyleSheet("color:rgb(0, 170, 0)") self.label_012.setText('12題√ ') self.label_012.setStyleSheet("color:rgb(0, 170, 0)") elif i == 12: self.lineEdit_013.setStyleSheet("color:rgb(0, 170, 0)") self.label_013.setText('13題√ ') self.label_013.setStyleSheet("color:rgb(0, 170, 0)") elif i == 13: self.lineEdit_014.setStyleSheet("color:rgb(0, 170, 0)") self.label_014.setText('14題√ ') self.label_014.setStyleSheet("color:rgb(0, 170, 0)") elif i == 14: self.lineEdit_015.setStyleSheet("color:rgb(0, 170, 0)") self.label_015.setText('15題√ ') self.label_015.setStyleSheet("color:rgb(0, 170, 0)") elif i == 15: self.lineEdit_016.setStyleSheet("color:rgb(0, 170, 0)") self.label_016.setText('16題√ ') self.label_016.setStyleSheet("color:rgb(0, 170, 0)") elif i == 16: self.lineEdit_017.setStyleSheet("color:rgb(0, 170, 0)") self.label_017.setText('17題√ ') self.label_017.setStyleSheet("color:rgb(0, 170, 0)") elif i == 17: self.lineEdit_018.setStyleSheet("color:rgb(0, 170, 0)") self.label_018.setText('18題√ ') self.label_018.setStyleSheet("color:rgb(0, 170, 0)") elif i == 18: self.lineEdit_019.setStyleSheet("color:rgb(0, 170, 0)") self.label_019.setText('19題√ ') self.label_019.setStyleSheet("color:rgb(0, 170, 0)") elif i == 19: self.lineEdit_020.setStyleSheet("color:rgb(0, 170, 0)") self.label_020.setText('20題√ ') self.label_020.setStyleSheet("color:rgb(0, 170, 0)") elif (xx.issubset(dd) == True) and (dd.difference(xx) != set()) and (self.answer[i] != '') and (self.xuan[i] != ''): self.bandu = self.bandu + 1 if i == 0: self.lineEdit_001.setStyleSheet("color:rgb(255, 0, 255)") self.label_001.setText('第1題乄 ') self.label_001.setStyleSheet("color: rgb(255, 0, 255)") elif i == 1: self.lineEdit_002.setStyleSheet("color:rgb(255, 0, 255)") self.label_002.setText('第2題乄 ') self.label_002.setStyleSheet("color:rgb(255, 0, 255)") elif i == 2: self.lineEdit_003.setStyleSheet("color:rgb(255, 0, 255)") self.label_003.setText('第3題乄 ') self.label_003.setStyleSheet("color:rgb(255, 0, 255)") elif i == 3: self.lineEdit_004.setStyleSheet("color:rgb(255, 0, 255)") self.label_004.setText('第4題乄 ') self.label_004.setStyleSheet("color:rgb(255, 0, 255)") elif i == 4: self.lineEdit_005.setStyleSheet("color:rgb(255, 0, 255)") self.label_005.setText('第5題乄 ') self.label_005.setStyleSheet("color:rgb(255, 0, 255)") elif i == 5: self.lineEdit_006.setStyleSheet("color:rgb(255, 0, 255)") self.label_006.setText('第6題乄 ') self.label_006.setStyleSheet("color:rgb(255, 0, 255)") elif i == 6: self.lineEdit_007.setStyleSheet("color:rgb(255, 0, 255)") self.label_007.setText('第7題乄 ') self.label_007.setStyleSheet("color:rgb(255, 0, 255)") elif i == 7: self.lineEdit_008.setStyleSheet("color:rgb(255, 0, 255)") self.label_008.setText('第8題乄 ') self.label_008.setStyleSheet("color:rgb(255, 0, 255)") elif i == 8: self.lineEdit_009.setStyleSheet("color:rgb(255, 0, 255)") self.label_009.setText('第9題乄 ') self.label_009.setStyleSheet("color:rgb(255, 0, 255)") elif i == 9: self.lineEdit_010.setStyleSheet("color:rgb(255, 0, 255)") self.label_010.setText('10題乄 ') self.label_010.setStyleSheet("color:rgb(255, 0, 255)") elif i == 10: self.lineEdit_011.setStyleSheet("color:rgb(255, 0, 255)") self.label_011.setText('11題乄 ') self.label_011.setStyleSheet("color:rgb(255, 0, 255)") elif i == 11: self.lineEdit_012.setStyleSheet("color:rgb(255, 0, 255)") self.label_012.setText('12題乄 ') self.label_012.setStyleSheet("color:rgb(255, 0, 255)") elif i == 12: self.lineEdit_013.setStyleSheet("color:rgb(255, 0, 255)") self.label_013.setText('13題乄 ') self.label_013.setStyleSheet("color:rgb(255, 0, 255)") elif i == 13: self.lineEdit_014.setStyleSheet("color:rgb(255, 0, 255)") self.label_014.setText('14題乄 ') self.label_014.setStyleSheet("color:rgb(255, 0, 255)") elif i == 14: self.lineEdit_015.setStyleSheet("color:rgb(255, 0, 255)") self.label_015.setText('15題乄 ') self.label_015.setStyleSheet("color:rgb(255, 0, 255)") elif i == 15: self.lineEdit_016.setStyleSheet("color:rgb(255, 0, 255)") self.label_016.setText('16題乄 ') self.label_016.setStyleSheet("color:rgb(255, 0, 255)") elif i == 16: self.lineEdit_017.setStyleSheet("color:rgb(255, 0, 255)") self.label_017.setText('17題乄 ') self.label_017.setStyleSheet("color:rgb(255, 0, 255)") elif i == 17: self.lineEdit_018.setStyleSheet("color:rgb(255, 0, 255)") self.label_018.setText('18題乄 ') self.label_018.setStyleSheet("color:rgb(255, 0, 255)") elif i == 18: self.lineEdit_019.setStyleSheet("color:rgb(255, 0, 255)") self.label_019.setText('19題乄 ') self.label_019.setStyleSheet("color:rgb(255, 0, 255)") elif i == 19: self.lineEdit_020.setStyleSheet("color:rgb(255, 0, 255)") self.label_020.setText('20題乄 ') self.label_020.setStyleSheet("color:rgb(255, 0, 255)") elif self.answer[i] != '' : self.wrong = self.wrong + 1 if i == 0: self.lineEdit_001.setStyleSheet("color:rgb(255, 0, 0)") self.label_001.setText('第1題× ') self.label_001.setStyleSheet("color: rgb(255, 0, 0)") elif i == 1: self.lineEdit_002.setStyleSheet("color:rgb(255, 0, 0)") self.label_002.setText('第2題× ') self.label_002.setStyleSheet("color:rgb(255, 0, 0)") elif i == 2: self.lineEdit_003.setStyleSheet("color:rgb(255, 0, 0)") self.label_003.setText('第3題× ') self.label_003.setStyleSheet("color:rgb(255, 0, 0)") elif i == 3: self.lineEdit_004.setStyleSheet("color:rgb(255, 0, 0)") self.label_004.setText('第4題× ') self.label_004.setStyleSheet("color:rgb(255, 0, 0)") elif i == 4: self.lineEdit_005.setStyleSheet("color:rgb(255, 0, 0)") self.label_005.setText('第5題× ') self.label_005.setStyleSheet("color:rgb(255, 0, 0)") elif i == 5: self.lineEdit_006.setStyleSheet("color:rgb(255, 0, 0)") self.label_006.setText('第6題× ') self.label_006.setStyleSheet("color:rgb(255, 0, 0)") elif i == 6: self.lineEdit_007.setStyleSheet("color:rgb(255, 0, 0)") self.label_007.setText('第7題× ') self.label_007.setStyleSheet("color:rgb(255, 0, 0)") elif i == 7: self.lineEdit_008.setStyleSheet("color:rgb(255, 0, 0)") self.label_008.setText('第8題× ') self.label_008.setStyleSheet("color:rgb(255, 0, 0)") elif i == 8: self.lineEdit_009.setStyleSheet("color:rgb(255, 0, 0)") self.label_009.setText('第9題× ') self.label_009.setStyleSheet("color:rgb(255, 0, 0)") elif i == 9: self.lineEdit_010.setStyleSheet("color:rgb(255, 0, 0)") self.label_010.setText('10題× ') self.label_010.setStyleSheet("color:rgb(255, 0, 0)") elif i == 10: self.lineEdit_011.setStyleSheet("color:rgb(255, 0, 0)") self.label_011.setText('11題× ') self.label_011.setStyleSheet("color:rgb(255, 0, 0)") elif i == 11: self.lineEdit_012.setStyleSheet("color:rgb(255, 0, 0)") self.label_012.setText('12題× ') self.label_012.setStyleSheet("color:rgb(255, 0, 0)") elif i == 12: self.lineEdit_013.setStyleSheet("color:rgb(255, 0, 0)") self.label_013.setText('13題× ') self.label_013.setStyleSheet("color:rgb(255, 0, 0)") elif i == 13: self.lineEdit_014.setStyleSheet("color:rgb(255, 0, 0)") self.label_014.setText('14題× ') self.label_014.setStyleSheet("color:rgb(255, 0, 0)") elif i == 14: self.lineEdit_015.setStyleSheet("color:rgb(255, 0, 0)") self.label_015.setText('15題× ') self.label_015.setStyleSheet("color:rgb(255, 0, 0)") elif i == 15: self.lineEdit_016.setStyleSheet("color:rgb(255, 0, 0)") self.label_016.setText('16題× ') self.label_016.setStyleSheet("color:rgb(255, 0, 0)") elif i == 16: self.lineEdit_017.setStyleSheet("color:rgb(255, 0, 0)") self.label_017.setText('17題× ') self.label_017.setStyleSheet("color:rgb(255, 0, 0)") elif i == 17: self.lineEdit_018.setStyleSheet("color:rgb(255, 0, 0)") self.label_018.setText('18題× ') self.label_018.setStyleSheet("color:rgb(255, 0, 0)") elif i == 18: self.lineEdit_019.setStyleSheet("color:rgb(255, 0, 0)") self.label_019.setText('19題× ') self.label_019.setStyleSheet("color:rgb(255, 0, 0)") elif i == 19: self.lineEdit_020.setStyleSheet("color:rgb(255, 0, 0)") self.label_020.setText('20題× ') self.label_020.setStyleSheet("color:rgb(255, 0, 0)") self.lineEdit_daduitishu.setText(str(self.right)) # 顯示正確錯誤半對的數量 self.lineEdit_banduitishu.setText(str(self.bandu)) # 顯示正確錯誤半對的數量 self.lineEdit_dacuotishu.setText(str(self.wrong)) # 顯示正確錯誤半對的數量
#② 把答案保存在電子表格,用Opencvyxl 庫 self.chengji = [''] * 24 self.chengji[0] = self.imgname #序號入列表 self.chengji[1] = self.diyigezichuan + self.diergezichuan + self.disangezichuan #姓名入列表 self.chengji[2] = self.kaohaochuan #考號入列表 self.chengji[3] = (self.right * self.meitifenshu) + (self.bandu * self.bufendefen) #成績入列表 self.chengji[4:] = self.xuan #選項入列表 self.chengjiexcel = openpyxl.load_workbook('chengji.xlsx') # 打開excel self.sh1 = self.chengjiexcel['chengjish'] # 打開表單一 self.sh2 = self.chengjiexcel['tongjish'] # 打開表單二 for col in range(len(self.chengji)): # 信息入電子表格 self.sh1.cell(row =self.imgname + 1 , column = col+1 ).value = self.chengji[col] self.chengjiexcel.save('chengji.xlsx') #保存
#③ 把選擇的正確率做成柱狀圖用 matplotlib 庫 for zhu in range(len(self.answer)): #循環顯示柱狀圖 if self.answer[zhu] != '': plt.figure('第'+ str(zhu+1)+'題') x = ['A', 'B', 'C', 'D'] y = [(eval('di' + str(zhu+1) + 'ti').count('A')),(eval('di' + str(zhu+1) + 'ti').count('B')),(eval('di' + str(zhu+1) + 'ti').count('C')),(eval('di' + str(zhu+1) + 'ti').count('D'))] plt.bar(x, y, label='第'+str((zhu+1))+'題選' + self.answer[zhu], color='g') plt.legend() plt.savefig('imgzhu\\'+ str((zhu+1))+'題'+'.jpg') plt.show()
#④用到的庫如下 # -*- coding: utf-8 -*- import sys,os if hasattr(sys, 'frozen'): os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH'] import cv2 import numpy as np import imutils import openpyxl from itertools import chain from PyQt5 import QtWidgets from untitled import Ui_Form from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * import matplotlib.pyplot as plt from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QApplication from imutils.perspective import four_point_transform
第八,程序打包:
安裝:pip uninstall pyinstaller
打開:CMD
切換路徑:自己工程的路徑並輸入 pyinstaller -F -w Run.py
如果出現錯誤:
1.在執行命令 pyinstaller -F D:\py\programe\banksystem.py打包生成.exe文件時報錯:python maximum recursion depth exceeded
2.處理辦法分三步走:
①.命令行輸入:pyi-makespec -F D:\py\programe\清單核對\bomcheck.py,會生成一個bomcheck.spec文件
②.找到bomcheck.spec這個文件給它的第二行插入下面兩行代碼
import sys
sys.setrecursionlimit(50000)
③.重新編譯生成命令行輸入:pyinstaller -F Run.spec即可
總結:說得好像論七八糟,大神請略過,第一次發博客手生,請見諒!