이번에는 Data Receive 버튼을 클릭했을 시 실행되는
Connectwindow 구현에 대하여 포스팅 할 것입니다.
Connectwindow는 위와 같이 구성되어 있습니다.
우선, 코드 전문입니다.
class ConnectWindow(Ui_Connect):
def __init__(self, w2):
self.IP = ""
self.Port = ""
self.workingFlag = 0
self.successFlag = 0
self.ConnectThread = DataRecvThread()
self.ConnectThread.connectState.connect(self.connectLog)
Ui_Connect.__init__(self)
self.Dialog = w2
self.setupUi(self.Dialog)
self.connectButton.clicked.connect(self.RecvData)
self.cancelButton.clicked.connect(self.CancelProcess)
def RecvData(self):
flist1 = os.listdir("temp/")
flist2 = os.listdir("slice/")
for f in flist1:
os.remove("temp/" + f)
for f in flist2:
os.remove("slice/" + f)
self.IP = self.IPplainTextEdit.toPlainText()
self.Port = self.PortplainTextEdit.toPlainText()
self.ConnectThread.IP = self.IP
self.ConnectThread.Port = self.Port
self.ConnectThread.start()
def CancelProcess(self):
if self.ConnectThread.workingFlag == 0:
self.Dialog.close()
elif self.ConnectThread.workingFlag == 1:
self.connectLog(6)
def connectLog(self, flag):
if flag == 1:
self.workingFlag = 1
self.loglabel.setText("Receiving file...")
elif flag == 2:
self.loglabel.setText("Slicing video...")
elif flag == 3:
self.workingFlag = 0
self.loglabel.setText("Data Receive Success!")
elif flag == 4:
self.loglabel.setText("Timeout! Please Reconnect.")
elif flag == 5:
self.loglabel.setText("Data Receive Fail...")
elif flag == 6:
self.loglabel.setText("Data Receiving now... Please Wait.")
elif flag == 7:
self.successFlag = 1 # receive success
elif flag == 8:
self.successFlag = 2 # receive fail
한 Widget은 하나의 클래스로 작성할 수 있습니다.
Mainwindow에서 했던 것과 같이 Ui_Connect를 상속받아 UI를 구성합니다.
def __init__(self, w2):
# IP와 Port를 저장할 함수, 각종 플래그를 선언
self.IP = ""
self.Port = ""
self.workingFlag = 0
self.successFlag = 0
# 데이터 전송 기능을 구현한 쓰레드 변수 선언
self.ConnectThread = DataRecvThread()
self.ConnectThread.connectState.connect(self.connectLog)
# UI 구성
Ui_Connect.__init__(self)
self.Dialog = w2
self.setupUi(self.Dialog)
# 각 버튼을 함수와 연결
self.connectButton.clicked.connect(self.RecvData)
self.cancelButton.clicked.connect(self.CancelProcess)
__init__ 함수입니다.
앞서 말했던 함수들과 비슷합니다.
필요한 정보들을 저장할 변수를 먼저 선언하고
처리 기능은 쓰레드로 구현했습니다.
마지막으로 clicked.connect() 함수를 이용해 버튼과 각 함수를 연결해 줍니다.
def RecvData(self):
flist1 = os.listdir("temp/")
flist2 = os.listdir("slice/")
# 경로 확인 후 각 캐시 폴더 초기화
for f in flist1:
os.remove("temp/" + f)
for f in flist2:
os.remove("slice/" + f)
# 입력받은 텍스트를 변수에 저장
self.IP = self.IPplainTextEdit.toPlainText()
self.Port = self.PortplainTextEdit.toPlainText()
# 쓰레드 변수에 IP, Port 전달
self.ConnectThread.IP = self.IP
self.ConnectThread.Port = self.Port
#데이터 전송 쓰레드를 실행
self.ConnectThread.start()
Connect 버튼을 클릭했을 때 실행되는 함수입니다.
먼저 전송받을 데이터에 문제가 없도록 각 캐시 폴더들을 초기화 합니다.
그 후 입력받은 IP와 Port를 변수에 저장하고 쓰레드로 전달합니다.
데이터를 전송받는 기능은 Analysis와 같이 쓰레드로 구현했습니다.
class DataRecvThread(QThread):
connectState = pyqtSignal(int)
IP = ""
Port = ""
workingFlag = 0
def run(self):
try:
# 진행상황을 메시지로 전송하며 진행
self.workingFlag = 1
self.connectState.emit(1)
server.so(self.IP, int(self.Port)) # 소켓통신 실행
self.connectState.emit(2)
vfs.capture() # 데이터 전처리 실행
self.connectState.emit(3)
self.connectState.emit(7)
self.workingFlag = 0
except:
# 오류시 오류메시지 출력 후 종료
self.connectState.emit(5)
self.connectState.emit(8)
self.workingFlag = 0
쓰레드가 실행되면 진행상황을 로그로 전달하며 데이터 전송이 진행됩니다.
server.so() 함수는 소켓통신을 구현한 함수입니다.
아래와 같이 구현되어 있습니다.
from socket import *
import socket
import os
import time
import sys
import subprocess
def fileName():
# 이미지 파일 저장경로
src = "../temp/"
dte = time.localtime()
Year = dte.tm_year
Mon = dte.tm_mon
Day = dte.tm_mday
WDay = dte.tm_wday
Hour = dte.tm_hour
Min = dte.tm_min
Sec = dte.tm_sec
imgFileName = src + str(Year) + '-' + str(Mon) + '-' + str(Day) + '_' + str(Hour) + ':' + str(Min) + ':' + str(Sec)
return imgFileName
def so(IP, Port):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((IP, int(Port)))
server_socket.listen(5)
file_recive_cnt = 0
print("TCPServer Waiting for client on port " + str(Port))
# print(os.getcwd())
for _ in range(2):
# 클라이언트 요청 대기중 .
client_socket, address = server_socket.accept()
# 연결 요청 성공
print("I got a connection from ", address)
data = None
# Data 수신
while True:
rev_path = 'temp/'
rev_flist = os.listdir(rev_path)
if ".DS_Store" in rev_flist:
rev_flist.remove(".DS_Store")
# if len(rev_flist) >= 2:
# for fname in rev_flist:
# os.system('rm ' + 'temp/' + fname)
# # subprocess.call('rm ' + 'temp/'+fname, shell=True)
# file_recive_cnt = 0
img_data = client_socket.recv(1000000)
data = img_data
if img_data:
while img_data:
print("recving Img...")
img_data = client_socket.recv(1000000)
data += img_data
print(len(data))
else:
break
# 받은 데이터 저장
img_fileName = fileName()
print(img_fileName)
if file_recive_cnt == 0:
img_fileName = img_fileName+".mp4"
elif file_recive_cnt == 1:
img_fileName = img_fileName+'.txt'
img_file = open("temp/"+img_fileName, "wb")
print("finish img recv")
print(sys.getsizeof(data))
img_file.write(data)
img_file.close()
client_socket.close()
print("Finish ")
data=None
file_recive_cnt+=1
vfs.capture() 함수는 영상을 0.1초 단위로 slice하는 전처리를 수행하는 함수입니다.
참고로 vfs는 video frame slice의 약자입니다.
아래와 같이 구현되어 있습니다.
import cv2
import os
def capture():
videopath = 'temp/'
filelist = os.listdir(videopath)
if ".DS_Store" in filelist:
filelist.remove(".DS_Store")
for fname in filelist:
if ".mp4" in fname:
videoname = fname
video = cv2.VideoCapture(videopath + videoname)
temp = int()
index = int()
result_frame_list = list()
if not os.path.isdir("slice/"):
os.mkdir("slice/")
while(video.isOpened()):
ret, frame = video.read()
print(ret)
if index % 3 == 0:
result_frame_list.append(frame)
cv2.imwrite("slice/" + str(int(index/3)) + ".jpg",frame)
if ret == True:
temp = temp + 1
index = index + 1
if ret == False:
break;
video.release()
print(temp)
해당 기능들은 이정민 학우(https://jeongmin-lee.tistory.com/)와 최남기 학우(https://namki-learning.tistory.com/)가 개발해 주었습니다.
전송 중 출력되는 각종 로그들은 플래그에 의해 관리되고
각 플래그마다 출력될 문자열들은 connectLog 함수에 정의되어 있습니다.
def connectLog(self, flag):
if flag == 1:
self.workingFlag = 1
self.loglabel.setText("Receiving file...")
elif flag == 2:
self.loglabel.setText("Slicing video...")
elif flag == 3:
self.workingFlag = 0
self.loglabel.setText("Data Receive Success!")
elif flag == 4:
self.loglabel.setText("Timeout! Please Reconnect.")
elif flag == 5:
self.loglabel.setText("Data Receive Fail...")
elif flag == 6:
self.loglabel.setText("Data Receiving now... Please Wait.")
elif flag == 7:
self.successFlag = 1 # receive success
elif flag == 8:
self.successFlag = 2 # receive fail
connectLog 함수입니다.
전송받는 플래그에 따라 동작중인지 아닌지 판별하는 workingFlag를 관리하고
해당하는 작업상태의 메시지를 출력해 줍니다.
def CancelProcess(self):
if self.ConnectThread.workingFlag == 0:
self.Dialog.close()
elif self.ConnectThread.workingFlag == 1:
self.connectLog(6)
마지막으로 Cancel 버튼을 클릭했을 때 실행되는 함수입니다.
데이터 전송중에 Widget을 종료할 경우 문제가 발생하므로 데이터 전송이 동작중인지 판별하여
데이터 전송 및 전처리중일 경우 안내 메시지를 출력하고
동작중이 아닐 경우에는 창을 동료할 수 있도록 만들었습니다.
Data Receive 기능은 이상입니다.
'프로젝트 이야기 > 드론을 이용한 식물 이상 탐지 시스템' 카테고리의 다른 글
드론을 이용한 식물 이상 탐지 시스템 - DBwindow 구현 (0) | 2019.06.23 |
---|---|
드론을 이용한 식물 이상 탐지 시스템 - Mainwindow 구현 (0) | 2019.06.23 |
드론을 이용한 식물 이상 탐지 시스템 - PyQt5 UI 만들기 (0) | 2019.06.23 |
드론을 이용한 식물 이상 탐지 시스템 - Qt UI 만들기 (0) | 2019.06.22 |
드론을 이용한 식물 이상 탐지 시스템 - PyQt5 설치 (0) | 2019.06.22 |