반응형
#define _WINSOCK_DEPRECATED_NO_WARNINGS 넣어준다.
그리고 #include <WinSock2.h> 부분은 opencv 헤더파일을 include하는 라인보다 위에있어야 에러가 생기지 않는다.
링커 -> 입력 -> 추가 종속성 : ws2_32.lib; 추가하는데 이 때 구성을 '모든구성'으로 하면 안된다.
이 프로젝트에서는 opencv라이브러리도 같이 추가되어있는데 모든구성으로해서 바꿔버리면 opencv관련 라이브러리가 추가항목에서 사라지게 된다. 따라서 직접 Release, Debug로 구성을 맞춰놓고 각각에 ws2_32.lib; 를 추가하면서 opencv_world349(opencv버전은 이 글을 보고 있는 본인의 버전에 맞추면 된다.)가 살아있는지 확인하면서 같이 넣도록 하자.
그리고 #pragma(lib."ws2_32") 이렇게 넣는 경우도 있는데 이렇게 하는 것도 '모든 구성'으로 라이브러리를 추가하는 것과 같은 효과라서 opencv라이브러리 항목이 무시되는 경우가 있으니 조심하자.
opencv(optical flow), 소켓통신이 들어가있는 부분 소스는 다음과 같다.
각각을 optical flow와 메세지 송신부분은 각각 스레드로해서 돌렸다.
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include<stdlib.h> #include<WinSock2.h> #include "opencv2\highgui.hpp" //#include "opencv2\imgproc.hpp" //#include "opencv2\objdetect\objdetect.hpp" #include "opencv2/video/tracking.hpp" // calcOpticalFlowFarneback #include <iostream> #include <time.h> // fps 계산용 #define GRID_INTERVAL 10 #define _SQR(x) ((x) * (x)) #define ROI_X_FROM 0.333 #define ROI_X_TO 0.666 #define ROI_Y_FROM 0 #define ROI_Y_TO 1 #define INT2CHAR(n) (n + '0') typedef struct dataPacket { int nDirection; int nStride; int nCalorie; /*dataPacket() {} dataPacket(int& direction, int& stride, int& calorie) : nDirection(direction), nStride(stride), nCalorie(calorie) { }*/ }data_packet; using namespace cv; using namespace std; SOCKET client; char g_cSendData[5]; bool ParsingData(data_packet& dp) { if (dp.nCalorie > 999) { dp.nCalorie = 999; } if (dp.nDirection > 0 && dp.nDirection < 5 && dp.nStride < 4) // 예외처리 { int tmp = 0; // jf.cSendData로 파싱해야한다. g_cSendData[0] = INT2CHAR(dp.nDirection); g_cSendData[1] = INT2CHAR(dp.nStride); tmp = dp.nCalorie / 100; g_cSendData[2] = INT2CHAR(tmp); tmp = (dp.nCalorie % 100) / 10; g_cSendData[3] = INT2CHAR(tmp); tmp = dp.nCalorie % 10; g_cSendData[4] = INT2CHAR(tmp); return true; } else { cout << "These is a problem on your data packet. please check it"; return false; } } DWORD WINAPI ThreadSend(void* data) { while (1) { //데이터 송신 send(client, g_cSendData, sizeof(g_cSendData), 0); //이렇게 두개가 딱 딱 받아지면 이대로하고 Sleep(20); //이거 지워도 된다. } return 0; } DWORD WINAPI Opticalflow(void* data) { // add your file name VideoCapture cap(0); Mat flow, frame; // some faster than mat image container //UMat flowUmat, prevgray; Mat flowUmat, prevgray; int nKineticEnergy = 0; clock_t start = clock(); dataPacket dpPacket = { 0,0,0 }; while (1) { bool Is = cap.grab(); if (Is == false) { // if video capture failed cout << "Video Capture Fail" << endl; break; } else { // 오류가 없으면 실행 Mat img; Mat original; // capture frame from video file cap.retrieve(img, CV_CAP_OPENNI_BGR_IMAGE); resize(img, img, Size(640, 480)); // save original for later img.copyTo(original); img = img(Range(img.rows * ROI_Y_FROM, img.rows * ROI_Y_TO), Range(img.cols * ROI_X_FROM, img.cols * ROI_X_TO)); // ROI 설정, Mat사이즈가 바뀐다. // just make current frame gray cvtColor(img, img, COLOR_BGR2GRAY); if (!prevgray.empty()) { // 이전 gray frame이 있으면 실행 // calculate optical flow //parameter : prev, next, flow, pyramid가 줄어드는 정도, 피라미드 층 갯수, win_size, 피라미드계층에서 반복횟수, //미분계산에서 사용되는 가우시안 함수의 표준편차1, 표준편차2, flag calcOpticalFlowFarneback(prevgray, img, flow, 0.5, 1, 12, 1, 7, 1.5, 0); // 큰 움직임 감지 못하면 7번째 파라미터(반복횟수)를 1씩 키우자 //내가 바꾼 모드 (at -> ptr) // By y += 5, x += 5 you can specify the grid nKineticEnergy = 0; // 운동에너지 초기화 for (int y = original.rows * ROI_Y_FROM; y < original.rows * ROI_Y_TO; y += GRID_INTERVAL) { Point2f* flowatxy = flow.ptr<Point2f>(y); //flow 는 해당 픽셀의 (u,v)값을 저장하고 있는 행렬이다. for (int x = original.cols * ROI_X_FROM; x < original.cols * ROI_X_TO; x += GRID_INTERVAL) { // 이 for문 안에서 [x]는 x좌표를 의미하고, .x는 optical flow의 방향벡터 u를 의미한다. // 마찬가지로 .y는 optical flow의 방향벡터 v를 의미. //운동에너지 픽셀마다 더한다. nKineticEnergy += _SQR(flowatxy[x].x) + _SQR(flowatxy[x].y); // draw line at flow direction line(original, Point(x, y), Point(cvRound(x + flowatxy[x].x * 10), cvRound(y + flowatxy[x].y * 10)), Scalar(255, 0, 0)); // draw initial point circle(original, Point(x, y), 1, Scalar(0, 0, 0), -1); } } // 여기까지 optical flow 계산 //------data packet 업데이트 dpPacket.nCalorie += 17; //test dpPacket.nDirection = dpPacket.nDirection < 4 ? dpPacket.nDirection + 1 : 1; //test dpPacket.nStride = dpPacket.nStride < 2 ? dpPacket.nStride + 1 : 0; //test //----- 위의 test소스를 지우고 dpPacket 업데이트 소스를 작성하면 됩니다. ParsingData(dpPacket); /*cout << "direction : " << dpPacket.nDirection << endl; cout << "stride : " << dpPacket.nStride << endl; cout << "calorie : " << dpPacket.nCalorie << endl << endl;*/ //printf("운동에너지 : %d\n", nKineticEnergy); /*printf("%.3lf\n", (double)(clock() - start)); // 걸린 시간 출력(ms) start = clock();*/ // draw the results namedWindow("prew", WINDOW_AUTOSIZE); imshow("prew", original); // fill previous image again img.copyTo(prevgray); } else { // fill previous image in case prevgray.empty() == true img.copyTo(prevgray); } int key1 = waitKey(1); } } return 0; } int main(int argc, const char** argv) { WSADATA wsa; WSAStartup(MAKEWORD(2, 2), &wsa); client = socket(AF_INET, SOCK_STREAM, 0); //서버 IP/PORT 설정 //클라이언트는 접속할 서버의 IP와 PORT를 알고있어야함 //IP나 PORT가 틀리면 서버연결할 수 없음 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); serverAddr.sin_port = htons(8088); //서버 연결 - connect() // connect(서버와연결할 클라이언트 소켓, SOCKADDR구조체주소, 사이즈) int error = connect(client, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); if (error == SOCKET_ERROR)//서버 연결에 실패한 경우 { printf("서버연결 실패\n"); system("pause"); exit(0); } printf("서버와의 소켓통신을 시작합니다.\n"); HANDLE hThreadOpenCV = CreateThread(NULL, 0, Opticalflow, NULL, 0, NULL); HANDLE hThreadSend = CreateThread(NULL, 0, ThreadSend, NULL, 0, NULL); WaitForSingleObject(hThreadOpenCV, INFINITE); WaitForSingleObject(hThreadSend, INFINITE); closesocket(client); WSACleanup(); system("pause"); }
반응형
'project > 캡스톤' 카테고리의 다른 글
[회의] 캡스톤 회의 0424 (0) | 2020.04.20 |
---|---|
[CPP 환경설정] CMake로 파일 만들고 환경설정하기(opencv + socket) (0) | 2020.04.17 |
[CPP 환경설정] opencv 환경설정 + 비쥬얼 소켓통신 환경설정 (0) | 2020.04.12 |
[캡스톤 강의내용 정리3] 3주차 강의 (0) | 2020.03.30 |
[캡스톤 강의정리] 2주차 (0) | 2020.03.23 |