Scientia Conditorium
[소켓 프로그래밍001] opencv를 이용한 동영상 이미지 전송 프로그램 본문
[소켓 프로그래밍001] opencv를 이용한 동영상 이미지 전송 프로그램
우연히 소켓 프로그래밍을 해야할 일이 생겼다.
비전공자 출신으로 네트워크 수업도 들어본 적 없으며 뭐가뭔지 한참을 헤맸지만 조금씩 헤쳐나갔다.
윈도우에서 간단하게 서버/클라이언트를 생성하여 동영상 이미지를 프레임 단위로 전송하는 간단한 프로그램을 만들어보았다.
먼저 서버다.
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
#include <WinSock2.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/background_segm.hpp>
#include <opencv2/video/tracking.hpp>
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 480
cv::Mat cameraFeed;
SOCKET server, client;
int height, width, IM_HEIGHT, IM_WIDTH, imgSize;
void Server()
{
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
{
return;
}
server = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN serverAddr, clientAddr;
serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7200);
int retval = bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (retval == SOCKET_ERROR)
{
std::cout << "bind() error" << std::endl;
return;
}
retval = listen(server, 0);
if (retval == SOCKET_ERROR)
{
std::cout << "listen() error" << std::endl;
return;
}
std::cout << "Listening for incoming connections..." << std::endl;
char buffer[1024];
int clientAddrSize = sizeof(clientAddr);
if ((client = accept(server, (SOCKADDR*)&clientAddr, &clientAddrSize)))
{
std::cout << "Client connected!" << std::endl;
}
}
int main()
{
Server();
cv::VideoCapture cap("simulation.mp4");
if (!cap.isOpened())
{
std::cout << "Can't open the camera" << std::endl;
return -1;
}
while (true)
{
//cap >> cameraFeed;
if (!cap.read(cameraFeed))
{
std::cout << "Video Ended" << std::endl;
break;
}
height = cameraFeed.rows;
width = cameraFeed.cols;
IM_HEIGHT = FRAME_HEIGHT;
IM_WIDTH = FRAME_WIDTH;
cv::resize(cameraFeed, cameraFeed, cv::Size(IM_WIDTH, IM_HEIGHT));
imgSize = cameraFeed.total() * cameraFeed.elemSize();
int retval = send(client, reinterpret_cast<const char*>(cameraFeed.data), imgSize, 0);
if (retval == SOCKET_ERROR)
{
std::cout << "send() error" << std::endl;
}
cv::imshow("Server", cameraFeed);
if (cv::waitKey(30) == 27)
{
closesocket(client);
std::cout << "Client disconnected" << std::endl;
break;
}
}
return 0;
}
다음은 클라이언트다.
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h.>
#include <Windows.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/background_segm.hpp>
#include <opencv2/video/tracking.hpp>
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 480
int main()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 0), &wsa) != 0)
{
return -1;
}
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(7200);
int retval = inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr.S_un.S_addr));
if (retval == SOCKET_ERROR)
{
std::cout << "inet_pton() error" << std::endl;
return -1;
}
retval = connect(server, (SOCKADDR*)&addr, sizeof(addr));
if (retval == SOCKET_ERROR)
{
std::cout << "connect() error" << std::endl;
return -1;
}
std::cout << "Connected to server!" << std::endl;
int bytes = 0;
while (true)
{
int IM_HEIGHT = FRAME_HEIGHT;
int IM_WIDTH = FRAME_WIDTH;
cv::Mat img = cv::Mat::zeros(FRAME_HEIGHT, FRAME_WIDTH, CV_8UC3);
int imgSize = img.total() * img.elemSize();
const int ah = 921600;
char sockData[ah];
for (int i = 0; i < imgSize; i += bytes)
{
std::cout << bytes << std::endl;
if ((bytes = recv(server, sockData + i, imgSize - i, 0)) == SOCKET_ERROR)
{
std::cout << "recv() error" << std::endl;
}
}
int ptr = 0;
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
img.at<cv::Vec3b>(i, j) = cv::Vec3b(sockData[ptr + 0], sockData[ptr + 1], sockData[ptr + 2]);
ptr = ptr + 3;
}
}
cv::namedWindow("Client", cv::WindowFlags::WINDOW_AUTOSIZE);
cv::imshow("Client", img);
if (cv::waitKey(30) == 27)
{
closesocket(server);
std::cout << "Server disconnected" << std::endl;
break;
}
}
return 0;
}
위 두 프로그램을 각각 다른 솔루션으로 작성하여 실행하면 아래와 같은 결과가 나온다.
우선은 코드만 올려놓고 설명은 다음 포스팅에서 하는 것으로 하겠다.