将OpenCV :: Mat图像发送到websocket Java客户端

时间:2014-02-02 19:09:57

标签: android c++ opencv websocket

我有一个c ++ websocket服务器,我想将一个openCV图像(cv :: Mat)发送到我的Android客户端。

我明白我应该使用base64字符串,但是我无法从openCV框架中找到它。

我不知道如何将cv :: Mat转换为bytearray。

谢谢

3 个答案:

答案 0 :(得分:1)

您好以下代码可以使用以下代码

C ++客户端

  • 这里我们将通过访问Mat数据指针将BGR原始字节发送到套接字。
  • 发送前请确保Mat继续播放,否则继续播放。

     int sendImage(Mat frame){
     int  imgSize = frame.total()*frame.elemSize();
     int  bytes=0;
     int clientSock;
     const char*        server_ip=ANDROID_IP;
     int        server_port=2000;
     struct  sockaddr_in serverAddr;
     socklen_t  serverAddrLen = sizeof(serverAddr);
    
        if ((clientSock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
            printf("\n--> socket() failed.");
            return -1;
        }
    
        serverAddr.sin_family = PF_INET;
        serverAddr.sin_addr.s_addr = inet_addr(server_ip);
        serverAddr.sin_port = htons(server_port);
    
        if (connect(clientSock, (sockaddr*)&serverAddr, serverAddrLen) < 0) {
                printf("\n--> connect() failed.");
                return -1;
        }
    
        frame = (frame.reshape(0,1)); // to make it continuous
    
        /* start sending images */
        if ((bytes = send(clientSock, frame.data, imgSize, 0)) < 0){
            printf("\n--> send() failed");
            return -1;
         }
    
        /* if something went wrong, restart the connection */
        if (bytes != imgSize) {
          cout << "\n-->  Connection closed " << endl;
          close(clientSock);
          return -1;
         }
    
    return 0;
    

    }

Java Server

  • 您应该知道要接收的图像大小。
  • 从套接字接收流并转换为字节数组。
  • 转换字节数组BGR并创建位图。

从C ++服务器接收字节数组的代码

    public static byte imageByte[];
    int imageSize=921600;//expected image size 640X480X3

    InputStream in = server.getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte buffer[] = new byte[1024];
    int remainingBytes = imageSize; //
    while (remainingBytes > 0) {
    int bytesRead = in.read(buffer);
     if (bytesRead < 0) {
     throw new IOException("Unexpected end of data");
     }
     baos.write(buffer, 0, bytesRead);

    remainingBytes -= bytesRead;

    }
    in.close();


    imageByte = baos.toByteArray();   
    baos.close();

将字节数组转换为RGB位图图像的代码

    int nrOfPixels = imageByte.length / 3; // Three bytes per pixel.
            int pixels[] = new int[nrOfPixels];
            for(int i = 0; i < nrOfPixels; i++) {
               int r = imageByte[3*i];
               int g = imageByte[3*i + 1];
               int b = imageByte[3*i + 2];

               if (r < 0) 
                  r = r + 256; //Convert to positive

               if (g < 0) 
                  g = g + 256; //Convert to positive

               if (b < 0) 
                  b = b + 256; //Convert to positive

               pixels[i] = Color.rgb(b,g,r);
            }
         Bitmap bitmap = Bitmap.createBitmap(pixels, 640, 480, itmap.Config.ARGB_8888);

答案 1 :(得分:0)

检查问题Serializing OpenCV Mat_中的这个答案。如果使用boost不是问题,它可以解决您的问题。可能你会在客户端需要一些额外的JNI魔法。

答案 2 :(得分:0)

您可以考虑哪些数据对您很重要:cols(列数),行(列数),数据(包含像素信息),类型(数据类型和通道编号)。< / p>

你必须对矩阵进行矢量化,因为它不是连续的并且考虑到存储器中像素大小的变化。

假设:

cv::Mat m;

然后分配:

int depth; // measured in bytes
switch (m.depth())
{
     // ... you might check for all of the possibilities
     case CV_16U:
          depth = 2;
}
char *array = new char[4 + 4 + 4 + m.cols * m.rows * m.channels() * depth]; // rows + cols + type + data

然后写下标题信息:

int *rows = array;
int *cols = &array[4];
int *type = &array[8];

*rows = m.rows;
*cols = m.cols;
*type = m.type;

最后是数据:

char *mPtr;
for (int i = 0; i < m.rows; i++)
{
    mPtr = m.ptr<char>(i); // data type doesn't matter
    for (int j = 0; j < m.cols; j++)
    {
         array[i * rows + j + 3 * 4] = mPtr[j];
    }
}

希望代码中没有错误。