Search code examples
csocketspointershalconhdevelop

Halcon/HDevelop socket send generic image data


Halcon Progress 20 provides sockets for different protocols (HALCON, UDP, TCP) and the send_data(Socket, Format, Data, To) procedure to send arbitrary data using generic socket communication. How can this procedure be used to send an image from hdevelop to another connected socket?

The Halcon Solution Guide on Programmed Visualization states the following:

Sometimes it might be necessary not to apply the standard HALCON visualization operators, but to use a selfprogrammed version. This can be achieved by using the access functions provided for all data types. Examples for these are get_image_pointer1, get_region_runs, or get_contour_xld. Operators like these allow full access to all internal data types. Furthermore, they provide the data in various forms (e.g., runlength encoding, points, or contours) to make further processing easier. Based on this data, a self programmed visualization can be developed easily.

Here is a basic example of how I think this should work:

read_image (Image, 'printer_chip/printer_chip_01')

* Send image via socket
Protocol := 'TCP4'
Timeout := 5.0
* Open a socket connection
open_socket_connect ('127.0.0.1', 5000, ['protocol','timeout'], [Protocol,Timeout], Socket)
* To is only used with protocol HALCON or UDP (empty for bound TCP connections)
To := []
* The following send_data is working, the connected socket receives this message
send_data (Socket, 'z', ['Generic sockets are great!'], To)

* Make sure we have only one channel
rgb1_to_gray (Image, GrayImage)
get_image_pointer1 (GrayImage, Pointer, Type, Width, Height)

* get_image_pointer returns pointer of type 'byte' -> use a byte format specifier for socket
* c: one byte = 8 bit, signed
* Append the type specifier with a number for a repeat count, e.g. 'c5' means 'ccccc'
Format := 'c' + Width*Height
* Format := 'c'
* How to cast the raw pointer correctly to send the data it points to?
send_data (Socket, Format, [Pointer], [])

The final line send_data (Socket, Format, [Pointer], []) throws an exception:

Unhandled program exception:

HALCON operator error while calling 'send_data' in procedure 'main' line: 78.

Format specification does not match the data (HALCON error code: 5628)

Obviously the Pointer is the address pointing to where the image is in memory and not the actual data which probably leads to the error.

Is there a way to cast the raw pointer correctly in HDevelop to send it via the socket? Or can this only be done in an external C/C++/C# application using the Halcon libraries?

The Halcon documentation on gen_image_pointer1 provids only this C example:

Hobject  Image;
char     typ[128];
Hlong     width,height;
unsigned char *ptr;

read_image(&Image,"fabrik");
get_image_pointer1(Image,(Hlong*)&ptr,typ,&width,&height);

I would like to use the features of HDevelop and not use the sockets in C/C++/C# (although this would be another way). The only thing missing is to actually send the image from within HDevelp to receiving sockets.


Solution

  • Here the code I hope can help you. It serializes the data and sends them.

    * Send image via socket
    Protocol := 'TCP4'
    Timeout := 5.0
    * Open a socket connection
    open_socket_connect ('127.0.0.1', 5000, ['protocol','timeout'], [Protocol,Timeout], Socket)
    get_socket_param (Socket, 'address_info', Address)
    * 
    * To is not evaluated for TCP and connected UDP sockets
    To := []
    
    * Make sure we have only one channel
    rgb1_to_gray (Image, GrayImage)
    get_image_pointer1 (GrayImage, _, _, Width, Height)    
    
    RowIndexes := []
    for j:=0 to Height-1 by 1
        tuple_gen_const (Width, j, TempIndexes)
        RowIndexes := [RowIndexes,TempIndexes]
    endfor
    
    ColIndexes := []
    tuple_gen_sequence (0, Width-1, 1, Sequence)
    for i:=0 to Height-1 by 1
        ColIndexes := [ColIndexes,Sequence]
    endfor
    
    * get pixel values
    get_grayval (GrayImage, RowIndexes, ColIndexes, Data)
    
    * C: one byte = 8 bit, Unsigned
    Format := 'C' + Width*Height
    
    send_data (Socket, Format, Data, To)
    

    [Edit2]

    It's possible to optimize the part of code that produce the RowIndexes and the ColIndexes using this code:

    tuple_gen_const (Width*Height, 0, RowIndexes)
    tuple_gen_const (Width, 0, Const)
    tuple_gen_sequence (0, Width-1, 1, Sequence)
    for j:=1 to Height-1 by 1    
        IndexSequence:= Sequence+j*Width    
        RowIndexes[IndexSequence] := Const+j
    endfor    
    
    tuple_gen_const (Width*Height, 0, ColIndexes)
    for i:=0 to Height-1 by 1
        IndexSequence:= Sequence+i*Width 
        ColIndexes[IndexSequence] := Sequence
    endfor