Raspbian-Windows openCV视频流之间的套接字

时间:2018-08-23 16:28:47

标签: python c++ sockets opencv

这是我第一次在这里问问题,但是我一直在寻找解决方案很久了,但一直找不到,所以我将尝试解决此问题,如果有更多人遇到同样的问题,请寻求帮助那些有这个线程的人。希望它不会完全重复!

我在Windows7,C ++,Visual Studio 2015中有一个服务器,在其中我有一些在openCV中运行的例程。我将其中一些任务从计算机中带到远程Raspberry Pi 3中,因此我在Python 3中也编程了一个使用套接字的客户端。

在发送诸如“ Hello World!”之类的字符串时,服务器(C ++)和客户端(Python)均可正常工作。还有那个东西。我开始发送二进制数据时出现了问题。

我在openCV(客户端python端)中有一个图像,并且使用了imencode函数:

data = cv2.imencode(".jpg", image, [int(cv2.IMWRITE_JPEG_QUALITY), 90])[1].tostring()

然后我有一个缓冲区,用于存储要发送的信息,因此我将该数据添加到缓冲区:

buffer.append(data)

然后,当填充缓冲区时,我通过套接字客户端发送了第一张图像:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("some_address and some port")
sock.send(data)
sock.close()

同时,在服务器端(C ++)中,我初始化了Windows套接字,解析了地址,创建了一个监听套接字,将监听套接字链接到服务器地址,然后等待客户端连接到监听套接字。当客户端连接时,监听套接字被关闭,我调用以开始接收方法:

do {
    iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
    if (iResult > 0) {
        totalBytes += iResult;
        std::cout << recvbuf << std::endl;
        ss << recvbuf;

        std::cout << ss.str() << std::endl;
        std::cout << "Bytes received: " << iResult << std::endl;

        // Echo the buffer back to the sender
        iSendResult = send(ClientSocket, recvbuf, iResult, 0);
        if (iSendResult == SOCKET_ERROR) {
            std::cout << "send failed with error: " << WSAGetLastError() << std::endl;
            closesocket(ClientSocket);
            WSACleanup();
            break;
        }
        std::cout << "Bytes sent: " << iSendResult << std::endl;
    }
    else if (iResult == 0) {
        std::cout << "Connection closing..." << std::endl;
    } else {
        std::cout << "recv failed with error: " << WSAGetLastError() << std::endl;
        closesocket(ClientSocket);
        WSACleanup();
        break;
    }
} while (iResult > 0);
addData(ss.str());

然后,addData将收到的信息推回队列缓冲区(在互斥锁区域内),并转换为uint8:

std::vector<uint8_t> v(data.begin(), data.end());
lck.lock();
buffer.push(v);
lck.unlock();

在程序的另一部分,我正在读取(以及在互斥锁区域内)队列中最古老的元素

std::vector<uint8_t> & ImageServer::getNextImage()
{
    lck.lock();
    if (buffer.size() > 0)
    {
        frameJPG = buffer.front();
        buffer.pop();
    }

    lck.unlock();
    return frameJPG;
}

然后我尝试再次使用openCV函数对其进行解码:

try {
    vec = is->getNextImage();
    img = cv::imdecode(vec, CV_LOAD_IMAGE_UNCHANGED);

    if (img.data == NULL)
        std::cout << "Image in buffer couldn't be properly decoded" << std::endl;
    else
        std::cout << "IMAGE RECOVERED!" << std::endl;
} catch (...) {
    std::cout << "AN UNKNOWN ERROR OCURRED" << std::endl;
}

它总是进入img.data == NULL。这意味着没有足够的数据(不是这种情况)或无法正确格式化数据。为什么?当将其作为第一个缓冲区存储到字符串流中以收集整个数据流时,我搞砸了吗?它被分成1024个字节的包...

我已检查:

  1. 服务器中接收到的数据大小等于客户端中的数据大小。
  2. b“ Hello World!”字符串已正确发送和接收。
  3. Raspbian和Windows 7都是小端的
  4. 两个OpenCV安装都是openCV3.x

在使用不同的转换进行1000次不同的测试后,我陷入了同一点:我无法解析的二进制流。 OpenCV在Windows和Python中的行为方式是否不同,因此无法在C ++中解码在Python中编码的内容?套接字接收未分类的信息吗?套接字是否添加了一些必须以某种方式修剪的标头?是由OS体系结构(x86与x64)引起的吗?

非常感谢您。

如果您需要更多代码,我也可以发布它,但我想保持干净!

关于, 麦杰

2 个答案:

答案 0 :(得分:2)

我认为您的字节被ss << recvbuf;剪切了,因为<<recvbuf视为以空字符结尾的字符串。而是应将其视为包含iResult个字节的缓冲区。这意味着它不是以空值结尾的,它的最后一个字节可以是任何东西,并且中间可能有空值。

我建议丢弃该ss,而不是直接从std::vector<uint8_t>中收到的作品中构建一个recvbuf

您可以像这样将recvbuf的所有内容插入向量v的末尾:

v.insert(v.end(), recvbuf, recvbuf + iResult);

答案 1 :(得分:1)

是的,ÖöTiib,就是这样。上周五,我对此表示怀疑,你是对的。今天早上,我对其进行了更改,使其工作顺利,没有对代码进行任何其他修改,但在add和get data方法中进行了任何修改! (以适应新的数据结构)。

所以这就是我在第一个测试中所做的:

std::vector<uint8_t> v;
// Receive until the peer shuts down the connection
do {
    iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
    if (iResult > 0) {
        totalBytes += iResult;
        for (auto i = 0; i < iResult; ++i)
            v.push_back(recvbuf[i]);
    //some more lines unreleated to the answer

有没有更有效的方法来填充向量v? 预先非常感谢您对此提供的非常感谢的帮助!

PS:很抱歉,由于我没有声誉,因此我无法对您的回答进行投票:-(