C++ -> 검은색 바탕
Python -> 흰색 바탕
Socket통신 도중 GUI 쓰레드가 Block되면 안되기 때문에 쓰레드로 등록할 소켓 클래스 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class SocWorker : public QObject{ Q_OBJECT public: SocWorker(); ~SocWorker(); public slots: void connectServer(const QString _addr, const int _port); void disConnectServer(); void onServerConnected(); void onAskTask(QString _fPath, int _mode, bool compress, QString _option = "" ); void onRecv(); signals: void resultReady(const QByteArray result); void sendMsg(const QString _text); private: QString hostName; QString port; QTcpSocket* sendSock; QByteArray recvData; int targetLength = -1; bool is_recvStart = false; }; | cs |
GUI로부터 IP와 PORT번호를 받아서 Python 서버 측으로 서버 접속 시도
1 2 3 4 5 6 7 8 9 10 | void SocWorker::connectServer(const QString _addr, const int _port){ qDebug() << __func__; sendSock->connectToHost(_addr, _port); if(!sendSock->waitForConnected(TIMEOUT)){ emit sendMsg("server is not responding"); } } | cs |
Python Server측에서는 localhost의 아이피로 소켓을 생성하고 1234포트를 열고서 listen 함수에서 접속을 대기하고 있다가 접속 요청이 오면 수락한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ########### 통신 ############# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((RECV_TCP_IP, RECV_TCP_PORT)) # Wating For Connect s.listen(True) # When Connetion Sucessed , Return Handler and address of client conn, addr = s.accept() conn.setblocking(True) print(conn) print(addr) | cs |
C++쪽 createProc 함수에서 프로토콜을 생성한후 소켓을 한번 비워주고(버그 예방차원에서..) 해당 프로토콜을 전송한후 제대로 전송할때까지 스레드를 블락한다.
1 2 3 4 5 6 7 8 9 | QByteArray proc = createProc(_fPath, _mode, compress, _option); qDebug() << "send data size : " << proc.length(); sendSock->flush(); sendSock->write(proc); sendSock->waitForBytesWritten(1000); | cs |
서버측에서는 recvAndLoad 함수에서 프로토콜을 읽고 각 바이트에 맞는 정보로 분할한뒤 해당 명령이 어떤 명령인지 int형으로 리턴한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | def recvAndLoad(): global DRIVER_NAME, FILE_PATH, VALUE, LUT, inImage, outImage, b_img, inH, inW, outW, outH global R, G, V, H, S, V, sx, ex, sy, ey sx = ex = sy = ey = 0 i_totLength = b_totData = b_meta = list_meta = 0 # 전체 데이터 크기 읽기 4바이트 i_totLength = int.from_bytes(recvall(conn, 4), byteorder='big') print("TOTAL LENGTH : ", i_totLength) # 4바이트 용량제외하고 모두다 읽기 b_totData = recvall(conn, i_totLength - 4) # 첫 200바이트는 메타데이터 b_meta = b_totData[0: 200] list_meta = str(b_meta).split(":") DRIVER_NAME = list_meta[0] FILE_PATH = list_meta[1] MODE = list_meta[2] OPTION = list(filter(lambda x: x != "", list_meta[3].split("|"))) OPTION.extend( [''] * 3 ); WIDTH = OPTION[0] HEIGHT = OPTION[1] COMPRESS = OPTION[2] VALUE = int( OPTION[3] ) if OPTION[3].isdigit() else OPTION[3] POINTS = OPTION[4] print(POINTS) if POINTS != '': if POINTS[0] == "P": loadPerspectiveValues(POINTS[1 : ]) elif POINTS[0] == "Z": loadRoi(POINTS[ 1 : ]) else: loadRois(POINTS) # 나머지는 이미지 데이터 b_img = b_totData[200:] print("OPTION :", OPTION ) print("DRIVER_NAME :", DRIVER_NAME ) print("FILE_PATH :", FILE_PATH ) print("MODE :", MODE ) print("IMAGE WIDTH :", WIDTH ) print("IMAGE HEIGHT :", HEIGHT ) print("IMAGE COMPRESS :", COMPRESS ) print("VALUE :", VALUE ) loadImage(WIDTH, HEIGHT) return int(MODE) | cs |
recvAndLoad 함수로부터 어떤 명령인지를 받으면 해당 명령에 따라서 영상처리 알고리즘을 적용시킨다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | mode = recvAndLoad() if mode == 0: equalImage() elif mode == 1: addImage() elif mode == 2: reverseImage() elif mode == 3: binImage() elif mode == 4: paraImage() ............. | cs |
알고리즘이 적용된 이미지를 바이트로 만든 후 해당바이트의 길이를 4바이트 인트형으로 먼저 전송한 후 이미지를 뒤이어 전송한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def sendImage(): global DRIVER_NAME, FILE_PATH, VALUE, LUT, START, inImage, outImage, b_img, inH, inW, outW, outH, b_outImg FIXED_OUTH = 512 FIXED_OUTW = 512 R = Image.fromarray(outImage[0].reshape((FIXED_OUTH, FIXED_OUTW))) G = Image.fromarray(outImage[1].reshape((FIXED_OUTH, FIXED_OUTW))) B = Image.fromarray(outImage[2].reshape((FIXED_OUTH, FIXED_OUTW))) b_outImg = Image.merge("RGB", (R, G, B)).tobytes() length = len(b_outImg) print("bytes To Send : ", length) conn.send(length.to_bytes(4, byteorder='little')) print(conn.send(b_outImg[:])) print( "elapsed time : ", time.time() - START ) | cs |
readyRead시그널에 의해서 onRecv 함수가 호출되고
1 | connect(sendSock, &QTcpSocket::readyRead , this, &SocWorker::onRecv ); | cs |
onRecv 함수에서는 첫 4바이트를 먼저 읽고 전체 바이트가 도착할때까지 recvData에 붙이다가 전체 데이터가 도착하면 데이터를 resultReady시그널과 같이 보낸다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | void SocWorker::onRecv(){ if(is_recvStart != true){ char header[4]; sendSock -> read(header, 4); targetLength = *reinterpret_cast<int*>(header); is_recvStart = true; recvData.clear(); } recvData.push_back(sendSock->readAll()); if(recvData.length() == targetLength){ emit resultReady( recvData ); is_recvStart = false; targetLength = -1; } } | cs |
'진행중인 프로젝트 > ImageHandler' 카테고리의 다른 글
[Qt5] 사용자 정의(. ui)로 다이얼로그 띄운 부분 (0) | 2019.06.29 |
---|---|
[Qt5] 페인트 이벤트를 받을 수 있는 사용자 정의 위젯 부분 (0) | 2019.06.29 |
Data Compression With Low-Rank Approximation [ 소스코드 ] (0) | 2019.06.29 |
[ Linear Algebra ] Data Compression With Low-Rank Approximation (0) | 2019.06.28 |
ImageHandler 0.0.1 Beta Relese. (0) | 2019.06.28 |