BennieC 0 Posted August 11, 2022 Hi, I have a Delphi application that calls OpenCV via Python4Delphi. It returns a tuple of floating point values in Python. However when I return the tuple to Delphi I get a string variable. Is there a way to force the conversion to maintain the floating point values. I managed to parse the string list in Delphi into a floating point array but the application should be in real time so this is an unnecessary step. In Python In Delphi Regards Share this post Link to post
KoRiF 1 Posted August 11, 2022 Note, Python arrays support Buffer Protocol https://docs.python.org/3/library/array.html#array.array.buffer_info this is a workaround, but you could use, say, SharedMemory to work directly with the binary representation on the Python data on the Delphi side Share this post Link to post
BennieC 0 Posted September 9, 2022 Thank you for this - it does seem to be the right way to go as my current string parsing is far too slow. However I have no idea how to use either of the two options. In the Buffer protocol, how do I return my result which seems to be a list of arrays. at present the return value is just the tuple which in Python looks like this: Name: layerOutputs Type: tuple Value: (array([[0.09, 0.03, 0.34...0.]]. dtype=float32), array([[0.06, 0.05, 0.67...0.]]. dtype=float32)) Currently this is just returned as a value with name layerOutputs, but Delphi sees this as a character string In the MemShare solution - how do I determine the memory position in Python and how do I determine the memory structure to use the binary representation. Are there any resources you can point me to as I am at a complete loss/ Share this post Link to post
SwiftExpat 65 Posted September 9, 2022 On 8/11/2022 at 6:28 AM, BennieC said: the application should be in real time so this is an unnecessary step. I can see you want to optimize this, but where is the real bottleneck that prevents you doing this in real time? What part is slow that is visible to the user? On 8/11/2022 at 6:28 AM, BennieC said: I managed to parse the string list Post this code, some people might give you some optimizations. Always a minimal working sample to discuss will help you get better answers. Share this post Link to post
pyscripter 689 Posted September 9, 2022 (edited) 2 hours ago, BennieC said: Value: (array([[0.09, 0.03, 0.34...0.]]. dtype=float32), array([[0.06, 0.05, 0.67...0.]]. dtype=float32)) Currently this is just returned as a value with name layerOutputs, but Delphi sees this as a character string No it does not. You get a tuple containing arrays of floating type values. Are you using VarPyth? Is layerOutputs a Variant? If yes then you can use: var arr:Variant := layerOutputs.GetItem(0); // the first item of the tupple (array). var value:Variant := arr.GetItem(0); //the first floating value of the array Edited September 9, 2022 by pyscripter Share this post Link to post
BennieC 0 Posted September 12, 2022 @SwiftExpat Thanks for the response. Regarding the bottleneck , the processing is requires the parsing of 507 + 2028 (and possibly an additional 8000) items, each consisting of 41 values (Yolo output) This has to happen in less than 10ms in order to stay within real time, or as close to that as possible. Regarding the code - my current attempt looks as follows (It does get the correct values out but takes about 500ms) aRectItmStr := aRectList.GetItem(rectCnt); // Get a rect , should have 41 values // It looks like this is a single string // Remove unnecessary spaces, linefeeds and brackets // Some records have long spaces while containstext(aRectItmStr, ' ') do aRectItmStr := StringReplace(aRectItmStr, ' ', ' ', [rfReplaceAll]); // Repeat until only single spaces exist aRectItmStr := StringReplace(aRectItmStr, '[', '', [rfReplaceAll]); aRectItmStr := StringReplace(aRectItmStr, ']', '', [rfReplaceAll]); aRectItmStr := StringReplace(aRectItmStr, #$A, '', [rfReplaceAll]); // #=numerical code, $=Hexdecimal aListArray := aRectItmStr.Split([' ', '''']); for i := 0 to MIN(length(aListArray), 41)-1 do aRectItmVals := strtofloatdef(aListArray, 0.0); I know this is probably inefficient but it would help a lot if i can just read the items as a n array of float values. Kind regards Share this post Link to post
BennieC 0 Posted September 12, 2022 @pyscripter Thank you. Indeed the layerOutputs is a variant and I am using VarPyth. However, using your syntax I seem to have made progress. Could you please explain the syntax as I am not familiar with that. Also, how do I declare a variable in a loop using the inline var statement? Kind regards Share this post Link to post
BennieC 0 Posted September 12, 2022 @pyscripter I have used your structure but still Delphi insist on giving me strings instead of floating point values. Can I somehow force the variant conversion to take this as a float? I have tried to assign the variant to single variable but have no luck. Regards Share this post Link to post
pyscripter 689 Posted September 12, 2022 2 hours ago, BennieC said: @pyscripter I have used your structure but still Delphi insist on giving me strings instead of floating point values. Can I somehow force the variant conversion to take this as a float? I have tried to assign the variant to single variable but have no luck. Regards Variants are converted to strings when shown in the debugger. It does not mean that they contain strings. Share this post Link to post
BennieC 0 Posted September 13, 2022 @pyscripter I have used your structure but still Delphi insist on giving me strings instead of floating point values. Can I somehow force the variant conversion to take this as a float? I have tried to assign the variant to single variable but have no luck. Regards I have tried assigning the variant to a single but get no joy. What does work is if I convert it to a single. var ConfValue:variant := aRectItm.GetItem(classCnt); ConfSingle := strtofloat(ConfValue); Share this post Link to post
KoRiF 1 Posted September 16, 2022 On 9/9/2022 at 12:51 PM, BennieC said: Thank you for this - it does seem to be the right way to go as my current string parsing is far too slow. However I have no idea how to use either of the two options. I'm not sure which solution will be faster and more stable for you, but given the large amount of data, you are quite able to notice the difference. Generally speaking, these are not two different options, but two sides of the same coin. Buffer Protocol obliges to place data in memory deterministically and sequentially (that is, in the spirit of the buffer of a C language). Python builds some of its objects around such a buffer Shared Memory is an operating system level concept that allows transferring access to such a buffer from one process to another https://docs.python.org/3/library/multiprocessing.shared_memory.html On 9/9/2022 at 12:51 PM, BennieC said: how do I return my result which seems to be a list of arrays. at present the return value is just the tuple Support for the buffer protocol means exactly that your data displayed as a tuple is actually placed in memory in a serial buffer https://numpy.org/doc/stable/reference/generated/numpy.ndarray.data.html On 9/9/2022 at 12:51 PM, BennieC said: In the MemShare solution - how do I determine the memory position in Python and how do I determine the memory structure to use the binary representation. https://docs.python.org/3/library/array.html#array.array.buffer_info Determining the address of the buffer in memory would be too tricky, but it is not required at all. You have to create a shared buffer using an arbitrary string name and all you need to do is pass this identifier between Delphi and Python (and maybe convert to numpy https://jakevdp.github.io/blog/2014/05/05/introduction-to-the-python-buffer-protocol/#:~:text=¶,manipulate large arrays of data.) here is shown example to pass data from TStringGrid to share on the Python side but common idea could be the same: https://github.com/KoRiF/MultyPy4Delphi/blob/master/UnitGridDataPy.pas#L608 https://github.com/KoRiF/MultyPy4Delphi/blob/master/UnitGridDataPy.pas#L561 https://github.com/KoRiF/MultyPy4Delphi/blob/master/UnitGridDataPy.pas#L333 https://github.com/KoRiF/MultyPy4Delphi/blob/master/UnitGridDataPy.pas#L666 On 9/9/2022 at 12:51 PM, BennieC said: Are there any resources you can point me to as I am at a complete loss/ https://helpful.knobs-dials.com/index.php/Python_usage_notes_-_struct,_buffer,_array,_bytes,_memoryview https://docs.python.org/3/library/multiprocessing.shared_memory.html https://docs.python.org/3/c-api/memoryview.html https://mingze-gao.com/posts/python-shared-memory-in-multiprocessing/#test-code Hope, this helps Share this post Link to post