使用OpenCV和socket传输图片

本文使用OpenCV和socket传输图片,采用了固定图片大小的方式,且暂时不考虑手动分包的问题。
Server.cpp

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#include <opencv2/opencv.hpp>

const int PORT = 5678;                //端口号
//const char *IP = "192.168.3.6";       //IP地址
struct sockaddr_in server_addr, client_addr; //定义服务端和客户端的地址结构体

const int Width = 640;  //图片的宽
const int Heigth = 480; //图片的高
cv::Mat GetImage(int sockfd);
void InitAddr(int sokckfd);

int main(int argc, char **argv)
{
    char client_IP[1024];
    //创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //TCP传输
    if (sockfd == -1)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }
    InitAddr(sockfd); //初始化地址,并将地址结构体绑定到套接字上

    //阻塞等待客户端的连接请求
    while (true)
    {
        bzero(&client_addr, sizeof(client_addr));
        socklen_t client_len = sizeof(client_addr);
        std::cout<<"wait"<<std::endl;
        int connectfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
        if (connectfd == -1)
        {
            perror("accept errno");
            exit(1);
        }
        //打印客户端的IP地址和端口号
        printf("client ip:%s port:%d\n",
               inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_IP, 1024),
               ntohs(client_addr.sin_port));

        //此时就可以读取connectfd中的数据
        cv::Mat image = GetImage(connectfd);
        //保存图片
        cv::imwrite("../Get/image.jpg", image);
    }
    return 0;
}

void InitAddr(int sockfd)
{
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    //设置端口复用
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1)
    {
        perror("bind errno");
        exit(1);
    }
    //std::cout<<"bind success"<<std::endl;

    ret = listen(sockfd, 10);
    if (ret == -1)
    {
        perror("listen errno");
        exit(1);
    }
    //std::cout<<"listen success"<<std::endl;
}


cv::Mat GetImage(int connectfd)
{
    cv::Mat mat = cv::Mat::zeros(Heigth, Width, CV_8UC1);
    const int imgSize = mat.total() * mat.elemSize();
    uchar bufferData[imgSize*2 ];
    int bytes = 0;
    int i = 0;
    for (i = 0; i < imgSize; i += bytes)
    {
        bytes = recv(connectfd, bufferData + i, imgSize - i, 0);
        if (bytes == -1)
        {
            std::cout << "status == -1   errno == " << errno << "  in Socket::recv\n";
            exit(EXIT_FAILURE);
        }
    }
    // std::cout << "recv " << i << "bytes" << std::endl;
    mat = cv::Mat(Heigth, Width, CV_8UC1, bufferData);
    return mat;
}

Client.cpp

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#include <opencv2/opencv.hpp>

const int PORT = 5678;          //端口号
const char *IP = "127.0.0.1"; //IP地址
struct sockaddr_in server_addr;        //定义服务端的地址结构体

const int Width = 640;  //图片的宽
const int Heigth = 480; //图片的高

void SendImage(const cv::Mat &mat, int sockfd);

void InitAddr();

int main(int argc, char **argv)
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //TCP通信
    if (sockfd == -1)
    {
        perror("socket errno");
        exit(EXIT_FAILURE);
    }
    InitAddr();
    //std::cout<<"socket success"<<std::endl;
    int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(ret == -1)
	{
		perror("connect error");
		exit(1);
	}
    std::cout<<"connect succedd"<<std::endl;
    cv::Mat Srcimage = cv::imread("../Send/img1.jpg",0);
    cv::Mat image;
    cv::resize(Srcimage,image,cv::Size(Width,Heigth));
    SendImage(image,sockfd);

    close(sockfd);
    return 0;
}

void InitAddr()
{
    //std::cout<<"Initing"<<std::endl;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    //需要将服务器端的IP地址进行转换
    int ret = inet_pton(AF_INET, IP, &server_addr.sin_addr.s_addr);
    if (ret == -1)
    {
        perror("inet_pton error");
        exit(EXIT_FAILURE);
    }

}

void SendImage(const cv::Mat &mat, int sockfd)
{
    int ret = send (sockfd, mat.data, mat.cols * mat.rows, MSG_NOSIGNAL );
    if(ret == -1)
    {
        perror("send error");
        exit(EXIT_FAILURE);
    }
}
  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用OpenCVSocket进行视频传输,您可以按照以下步骤进行操作: 1. 服务端(发送端): - 使用OpenCV读取视频文件或捕获摄像头的实时视频。 - 将每一帧编码为图像数据(如JPEG或PNG)。 - 使用Socket将编码后的图像数据发送到客户端。 2. 客户端(接收端): - 创建Socket连接到服务端。 - 接收服务端发送的图像数据。 - 解码图像数据并显示(使用OpenCV)。 下面是一个简单的示例代码,演示了如何在Python中使用OpenCVSocket进行视频传输: 服务端代码: ```python import cv2 import socket import pickle # 创建Socket连接 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8000)) server_socket.listen(1) print("Waiting for client connection...") # 接受客户端连接 client_socket, address = server_socket.accept() print("Client connected:", address) # 打开视频文件或启动摄像头 cap = cv2.VideoCapture('path_to_video_file') # 或者使用摄像头:cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break # 编码图像数据 data = pickle.dumps(frame) # 发送图像数据到客户端 client_socket.sendall(data) # 关闭连接和摄像头 client_socket.close() cap.release() ``` 客户端代码: ```python import cv2 import socket import pickle import struct # 创建Socket连接 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 8000)) data = b'' # 存储接收到的图像数据 payload_size = struct.calcsize("L") # 图像数据的大小 while True: # 接收图像数据 while len(data) < payload_size: data += client_socket.recv(4096) packed_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("L", packed_size)[0] while len(data) < msg_size: data += client_socket.recv(4096) frame_data = data[:msg_size] data = data[msg_size:] # 解码图像数据 frame = pickle.loads(frame_data) # 显示图像 cv2.imshow('Video', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # 关闭连接 client_socket.close() cv2.destroyAllWindows() ``` 请注意,此示例仅介绍了基本的图像传输功能,并没有处理图像传输中的丢包和延迟等问题。在实际应用中,还需要考虑网络稳定性和性能优化等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值