Search code examples
c#c++opencvipcnamed-pipes

Send Image Frames from C++ Server to C# Client using Named Pipe


I am noobie in IPC. I am trying to send the Image Frame from my C++ Server to C# Client. I have start learning about that and make a small Client and Server that In which my C++ Server sends Hello. I saw a related question and someone told to first convert the Image into Byte Array and then send that in same way as Hello Message but I am not able to do that.

My Basic Client Server Code

C++ Code:

    Mat image = imread("IMG_0_10_34_45_2018_1.bmp");
uchar buffer[500][500];
for (int i = 0; i < image.rows; i++)
{
    for (int j = 0; j < image.cols; j++)
    {
        buffer[i][j] = image.at<unsigned char>(i, j);
    }
}
cout << "Server Creating Pipe\n";
HANDLE hPipe = ::CreateNamedPipe(_T("\\\\.\\pipe\\HyperPipe"),
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
    PIPE_UNLIMITED_INSTANCES,
    4096,
    4096,
    0,
    NULL);

cout << "Server Created Succesfully";
ConnectNamedPipe(hPipe, NULL);

cout << "Sending Message to Client";
DWORD bytesWritten = 0;
WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
CloseHandle(hPipe);
return 0;

And C# Code:

static void Main(string[] args)
{
    Console.WriteLine("Creating Client Pipe");
    NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
    Console.WriteLine("Pipe Created Successfully, Connecting to Server");
    pipe.Connect();
    Console.WriteLine("Successfully, Connected to Server");
    using (StreamReader rdr = new StreamReader(pipe, Encoding.Unicode))
    {
        System.Console.WriteLine("Message from Server: " + rdr.ReadToEnd());
    }

    Console.ReadKey();
}

I also noticed that in my C++ Server I have to change the PIPE_TYPE to BYTE and also READMODE to BYTE. I am using OpenCV library for Image Processing so I can easily make Byte Array no issue with that.

So, Can Anyone Please tell me how to send that Byte Array from C++ to C#. Or if possible that anyone can provide me the code for that

Thanks in Advance

Update: No error is coming but at the client side i.e C# Side the the output of Message from Server is ????? .


Solution

  • To Send the Byte Array from Server to Client i.e the buffer just small changes in the WriteFile function is required.

    WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
    

    This method will send whole Byte Array to the Client And also changing the buffer

    int _count = 0;
    UINT8 _imageBuffer[110592];
    for (int _imageRow = 0; _imageRow < _image.rows; _imageRow++)
    {
        for (int _imageCol = 0; _imageCol < _image.cols; _imageCol++)
        {
            buffer[_count] = image.at<uchar>(_imageRow, _imageCol);
            _count++;
        }
    }
    

    I have hardCode the buffer Array because I known that my camera will only send 110592 byte to create one frame.

    And On the Client Side just use Read function.

                int _imageRowSize = 288;
                int _imageColSize = 384;
                int _count = 0;
                byte[] buffer = new byte[_imageColSize * _imageRowSize];
                Image<Gray, UInt16> image = new Image<Gray, UInt16>(_imageColSize,_imageRowSize);
                Console.WriteLine("Creating Client Pipe");
                NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
                Console.WriteLine("Pipe Created Successfully, Connecting to Server");
                pipe.Connect();
                Console.WriteLine("Successfully, Connected to Server");
                using (MemoryStream ms = new MemoryStream())
                {
                    while (true)
                    {
                        _count = 0;      
                        int read = pipe.Read(buffer, 0, buffer.Length);
                        for (int _imageRow = 0; _imageRow < 288; _imageRow++)
                        {
                            for (int _imageCol = 0; _imageCol < 384; _imageCol++)
                            {
                                try
                                {
                                    image.Data[_imageRow, _imageCol, 0] = (UInt16)(buffer[_count] * 255);
                                }catch(Exception exception)
                                {
                                    Console.WriteLine(exception);
                                }
                                _count++;
                            }
                        }
                        if (read <= 0)
                            break;
                        ms.Write(buffer, 0, read);
                    }
                }           
                CvInvoke.Imshow("Image", image);
            }