1

I am trying to send out Mat image by TCP. Firstly the Mat has been transferred into uchar and then into char format. The whole image in char format will be send out buffer by buffer whose size is 1024 byte. The following is my code.

Mat decodeImg = imdecode(Mat(bufferFrame), 1);

uchar *transferImg = decodeImg.data;
char* charImg = (char*) transferImg;
int length = strlen(charImg);
int offset = 0;
while (true)
{
    bzero(bufferSend, BUFFER_SIZE);

    if (offset + BUFFER_SIZE <= length)
    {
        for (int i = 0; i < BUFFER_SIZE; i++)
        {
            bufferSend[i] = charImg[i + offset];
        }
        //          memcpy(charImg+offset, bufferSend,BUFFER_SIZE);
        if (send(sockfd, bufferSend, sizeof(bufferSend), 0) < 0)
        {
            printf("Send FIle Failed,total length is%d,failed offset is%d\n",
                   length,
                   offset);
            break;
        }
    }
    else
    {
        for (int i = 0; i < length - offset; i++)
        {
            bufferSend[i] = charImg[i + offset];
        }
        if (send(sockfd, bufferSend, sizeof(bufferSend), 0) < 0)
        {
            printf("Send FIle Failed,total length is%d,failed offset is%d\n",
                   length,
                   offset);
            break;
        }
        break;
    }
    offset += BUFFER_SIZE;
}

The output of the code shows : send file failed, total length is 251035, failed offset is 182272.

I am really appreciated on your help. Thank you in advance!

user4581301
  • 33,082
  • 7
  • 33
  • 54
wuyang
  • 73
  • 8
  • Probably you need to [encode base64](http://stackoverflow.com/questions/28003981/opencv-cvmat-to-stdifstream-for-base64-encoding) – Miki Sep 18 '15 at 18:10
  • If that is the case the only problem should be the server can not recognize image. However, the current problem is this client just fails to send out the whole buffers. – wuyang Sep 18 '15 at 18:17
  • what is `bufferFrame`? shouldn't you send out the `imencode`d char buffer? – Miki Sep 18 '15 at 18:25
  • System calls always fail for a reason you can query: `errno`. Either use `strerror(errno)` or `perror`. You should read the documentation for them. – edmz Sep 18 '15 at 18:56
  • Be really helpful to you and everyone else if you got the error code. [WSAGetLastError](https://msdn.microsoft.com/en-ca/library/windows/desktop/ms741580(v=vs.85).aspx) under windows and [errno](http://man7.org/linux/man-pages/man3/errno.3.html) pretty much everywhere else. For all you know, the transmission hasn't failed, you've just filled up the TCP send buffer and can't send any more until the other side does more receiving. – user4581301 Sep 18 '15 at 18:56
  • 1
    @black weird how two people can make essentially the same post at the same time an hour after the question was asked. – user4581301 Sep 18 '15 at 18:59
  • By the way, `int length = strlen(charImg);` might not be the right way to get the length. I don't know opencv, but unless `imdecode` serializes the data as an ascii string, odds are pretty good `strlen` will trip over a null in the data and stop early. And the alternative is it stops late and you try to send too much data. Depending on what the client does with excess data, that could be your problem. – user4581301 Sep 18 '15 at 19:05
  • @MiKi Yes, I just find this problem, now I am looking for a way to transfer Mat into jpg and then sent it out. – wuyang Sep 18 '15 at 19:36
  • @black Thank you, I will check the perror to see what is the problem and post it latter – wuyang Sep 18 '15 at 19:37
  • @black, user4581301, perror shows : Connection reset by peer. – wuyang Sep 18 '15 at 19:49
  • @user4581301 It must have been Jon Skeet's will :O – edmz Sep 18 '15 at 19:51
  • That means the other side sent a RST packet and killed the connection without shutting it down. Usually used to signal a fatal error, no one listening on the requested port, or a $%! off and die message from the other side. Make sure the data you sent didn't crash the receiver. – user4581301 Sep 18 '15 at 19:54
  • @user4581301 I am checking immediately the content of data with the correct size of Mat you mentioned. – wuyang Sep 18 '15 at 19:57
  • @wuyang my 2 cents: you can easily send jpeg data using `imencode` on the sender and `imdecode` on the receiver. If you use base64 encoding you avoid the problem of having invalid values in the stream. Also, if you send raw bgr data, you need also to send at least image width and height information in the stream, or the receiver won't know the actual size of the image. The latter can be avoided using jpeg data. – Miki Sep 18 '15 at 20:05
  • @Miki Thank you for the advice! Previously what I did was to store frames captured by web camera into .jpg file and sent it out to server which works well. Thus I believe imencode you mentioned is good enough in this case. – wuyang Sep 18 '15 at 20:11
  • You don't need to save the frames into jpeg. You can directly encode your frame as jpeg – Miki Sep 18 '15 at 20:13
  • @Miki I have another question. If I encode Mat into jpg stored in a char array it is correct to get the size of it by using strlent()? – wuyang Sep 18 '15 at 20:24
  • you can simply do: `vector buf; imencode(".jpg", img, buf); size_t len = buf.size();` – Miki Sep 18 '15 at 20:27
  • you send `buf` through the socket. If you need the pointer you simply do: `uchar* pbuf = buf.data();`. And then you read the image again as: `Mat img2 = imdecode(buf, IMREAD_UNCHANGED);` – Miki Sep 18 '15 at 20:34
  • @Miki Thank you for the detailed instruction. But to reduce the work revising the current code I decide transfer vector buf to char bufferFrame[ ] and send char out. It that works? – wuyang Sep 18 '15 at 20:43
  • I'd say no, but show me the relevant lines of code. – Miki Sep 18 '15 at 20:49
  • Suppose we put encoded jpg data in vector< uchar> bufferFrame. Then char * frameSend; for( int i = 0; i< bufferFrame.size(); i++) { frameSend [i] = bufferFrame.at(i);} then send out his frameSend char array – wuyang Sep 18 '15 at 20:53
  • ok, that'll work. But I don't understand why you want to copy everything. Just send `char* p = (char*)buf.data();` – Miki Sep 18 '15 at 21:17
  • I test the change but the result shows server can not recognize received image. I doubt whether I send out the complete image. – wuyang Sep 18 '15 at 22:05

1 Answers1

2

Pulling out the crystal ball here. This might be OP's problem, but if it isn't, this is certainly a problem that needs to be addressed.

Mat decodeImg = imdecode(Mat(bufferFrame), 1);
uchar *transferImg = decodeImg.data;

Get data. Not a bad idea if that's what you need to send.

char* charImg = (char*) transferImg;

Take the array of bytes from above and treat it as an array of characters.

int length = strlen(charImg);

And Boom. Matrix data is not ascii formated data, a string, so it should not be treated like a string.

strlen counts data until it reaches a null character, a character with the numerical value 0, which does not exist in the normal alpha numeric world and thus can be used as a canary value to signal the end of a string. The count is the number of characters before the first null character in the string.

In this case we don't have a string. We have a blob of binary numbers, any one of which could bee 0. There could be a null value anywhere. Could be right at the beginning. Could be a hundred bytes in. There might not be a null value in the until long after all of the valid image data has been read.

Anyway, strlen will almost certainly return the wrong value. Too few bytes and the receiver doesn't get all of the image data and I have no idea what it does. That code's not available to us. It probably gets upset and discards the result. Maybe it crashes. There's no way to know. If there is too much information, we also don't know what happens. Maybe it processes the file happily and ignores the extra crap that's sent. Maybe it crashes.

But what if it closes the TCP/IP connection when it has enough bytes? That leaves the sender trying to write a handful of unsent and unwanted bytes into a closed socket. send will fail and set the error code to socket closed.

Solution:

Get the right size of the data.

What I'm reading from the openCV documentation is inside a Mat is Mat::elemSize which will give you the size of each item in the matrix and Mat::size which returns a Size object containing the rows and columns. Multiply rows * columns * elemSize and you should have the number of bytes to send.

EDIT

This looks to be a better way to get the size.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Yup. Should have googled first. Somebody had to have had this problem before. And it turns out my answer is a long-winded dupe of http://stackoverflow.com/questions/22849790/opencv-mat-object-get-data-length – user4581301 Sep 18 '15 at 19:49
  • well, not bad for someone who doesn't know OpenCV! Actually, I've always seen sending base64 encoded data, but you seems to know way more than me in this kind of stuff... – Miki Sep 18 '15 at 19:52
  • Thank you for pointing out this problem that I never realized. My current idea is it that possible to transfer Mat into jpg format and send jpg out? Since my original code is send out a jpg file, which however cost more time to read the file from the disk, what I am doing now is to send results in Mat format stored in memory directly out to a client. – wuyang Sep 18 '15 at 19:55
  • @Miki Half of my life seems to have been spent opening sockets and sending varying types of data. – user4581301 Sep 18 '15 at 19:56
  • @wuyang You should be able to encode a jpg to a memory buffer and then write the memory buffer to the socket. Should be a lot faster than sending the uncompressed mat data, but if fidelity is a concern, jpg compression will slightly damage the data. – user4581301 Sep 18 '15 at 19:59
  • @user4581301 I am working on this. But I realize a problem that previously I encode Mat image into jpg file which is a binary, however, if the result of imencode function which is uchar jpg file is different from the content of a binary file, then I have to further change server code. I am not sure whether their content are equal. – wuyang Sep 18 '15 at 20:29
  • @wuyang the content of the buffer after `imencode` is exactly the content of the file.jpg. – Miki Sep 18 '15 at 20:37