Jump to content

RegiStax

Members
  • Content Count

    9
  • Joined

  • Last visited

Community Reputation

0 Neutral
  1. Hi, I found out that my routine above is working as planned, but its important to use the same mainModule.variable names 🙂 . Sorry for the confusion, hope the code helps someone. Cor
  2. Hi, I have some questions on how to use the Pybuffer method to change data inside the python environment. Currently I have two routines: This routine loads a dataset from python that consists of a flexible array of width*height*channel arraycells. procedure Tform1.LoadPythonUint16Arr_Memory_image(transfer:variant; c, w, h:integer); var k: integer; j: integer; i: integer; sum: int64; PyBuffer: Py_buffer; np_arr: PPyObject; np:variant; p:Tfpcolor; begin np := Import('numpy') ; np_arr:=ExtractPythonObjectFrom(transfer); Memo2.lines.add('np_arr extracted'); Memory_Image.setsize(h,w); sum:=0; PythonEngine1.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); PythonEngine1.CheckError; Memo2.lines.add('conversion to memoryimage'); try for I := 0 to w- 1 do for J := 0 to h- 1 do begin p:=Memory_Image.colors[j,i]; p.red:=PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c+2]; p.green:=PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c+1]; p.blue:=PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c]; Memory_Image.colors[j,i]:=p; sum:=sum+p.green+p.red+p.blue; end; finally PythonEngine1.PyBuffer_Release(@PyBuffer); end; Memo2.lines.add('MemoryImage ready'); end; This works perfect and allows me to download a large 16bit RGB image in a few ms instead of a few 100ms. When I try to change that same dataset on the Pythonside I however do not see those changes in the dataset. Where do I go wrong ? The Tfpcolor consists of 3 uint16 values and the buffered array also. When I run this ... I dont see any traceable change when I check on the python side. procedure Tform1.StorePythonUint16Arr_Memory_image(transfer:variant; c, w, h:integer); var k: integer; j: integer; i: integer; sum: int64; PyBuffer: Py_buffer; np_arr: PPyObject; np:variant; p:Tfpcolor; count:integer=0; begin np := Import('numpy') ; np_arr:=ExtractPythonObjectFrom(transfer); sum:=0; PythonEngine1.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); PythonEngine1.CheckError; try for I := 0 to w- 1 do for J := 0 to h- 1 do begin p:=Memory_Image.colors[j,i]; PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c+2]:=(p.red); PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c+1]:=(p.green); PUint16PythonArray(PyBuffer.buf)^[(I*h+J)*c+0]:=(p.blue); end; finally end; PythonEngine1.PyBuffer_Release(@PyBuffer); Memo2.lines.add('MemoryImage stored ready'); end;
  3. Thanks. The delphi doc is clearer on this !
  4. OK. Thanks, can you point to the documentation that states this ? I have moved over the code into my application to find out I dont need all the trouble ... Just call: np_arr:=ExtractPythonObjectFrom(MainModule.weights); PythonEngine1.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); That provides a direct link to the data of the weights variable in my python section, from that moment on its "easy".
  5. Next iteration. This does work, not very elegant as I read the PyBuffer indexed { TBufferProtocol } procedure TBufferProtocol.DoRun; var SW: TStopwatch; Sum: double; np: Variant; arr: Variant; np_arr: PPyObject; PyBuffer: Py_buffer; V: Variant; I,J: Integer; Count: Integer; ArrItem: Variant; arrItem1:Variant; s:variant; begin try CreatePyEngine; try // Import numpy and create an array np := Import('numpy'); //arr := np.&array(BuiltinModule.range(N), np.float64); arr := np.&ones(VarPythonCreate([N, N]), np.float64); writeln(VarPythonToVariant(arr.Length)); // This is the slow way to iterate the array WriteLn('Lazy but slow:'); SW := TStopwatch.StartNew; Sum := 0; Count := VarPythonToVariant(arr.Length); writeln(count); for I := 0 to Count - 1 do begin ArrItem := arr.GetItem(I); for J := 0 to Count - 1 do begin ArrItem1:= BuiltinModule.float(arrItem.GetItem(J)); Sum := Sum + double(VarPythonToVariant(ArrItem1)); end; end; SW.Stop; WriteLn(Format('Sum from 0 to %d = %04.3f', [N, Sum])); WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); WriteLn; WriteLn('Using Py_Buffer:'); SW := TStopwatch.StartNew; np_arr := ExtractPythonObjectFrom(arr); PyEngine.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); PyEngine.CheckError; try Sum := 0; for I := 0 to N- 1 do for J := 0 to N- 1 do Sum := Sum + PDoubleArray(PyBuffer.buf)^[I*N+J]; WriteLn(Format('Sum from 0 to %d = %04.3f', [N, Sum])); finally PyEngine.PyBuffer_Release(@PyBuffer); end; SW.Stop; WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); WriteLn; // test write access PDoubleArray(PyBuffer.buf)^[0] := 999; ArrItem1:= arr.GetItem(0); if VarPythonToVariant(BuiltinModule.float(arrItem1.GetItem(0))) = 999 then WriteLn('Successfully modified the numpy array using Py_buffer'); finally DestroyEngine; end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; // stop program loop Terminate; end;
  6. Ive changed the builtin functions and also the single/double parts. The output is as expected. I however cannot create a 2d array I am stuck at this point arr := np.&array(BuiltinModule.range(N), np.float64); You would expect that (Ive not found any documentation on this thusfar) that you can use arr := np.&zeros((N,N) , np.float64); But that logically fails at the (N,N) declaration, with just N overthere I get an array of N slots with zero's. Its unclear how I can insert shapes etc. BTW I wont complain on the lack of "deeper" documentation for this, I also produce "freeware" and documentation is the least fun in my view. EDIT: this seems to at least declare the array arr := np.&ones(VarPythonCreate([N, N]), np.float64); Cor
  7. Hi pyscripter, Thanks for the additional advice on Builtin etc. I will see how far I get that. Regarding the "Place image in Timage", that was mainly using DIB structures which are pure windows. As I am working on a Linux system thats currently not an option. If I manage to get this working I will share the code. cheers Cor
  8. I have adapted the code from DEMO35 to be used with 64bit floating (see below). However this is still a 1D array. Redefinition of the array type inside pascal and rewrite of the DoRun method. Tested and working as expected. type PIntArray = ^TIntArray; TIntArray = array[0..N - 1] of Double; { TBufferProtocol } procedure TBufferProtocol.DoRun; var SW: TStopwatch; Sum: single; np: Variant; arr: Variant; np_arr: PPyObject; PyBuffer: Py_buffer; V: Variant; I: Integer; Count: Integer; ArrItem: Variant; begin try CreatePyEngine; try // Import numpy and create an array np := Import('numpy'); arr := np.&array(BuiltinModule.range(N), np.float64); writeln(VarPythonToVariant(arr.Length)); // This is the slow way to iterate the array WriteLn('Lazy but slow:'); SW := TStopwatch.StartNew; Sum := 0; Count := VarPythonToVariant(arr.Length); writeln(count); for I := 0 to Count - 1 do begin ArrItem := BuiltinModule.int(arr.GetItem(I)); Sum := Sum + single(VarPythonToVariant(ArrItem)); end; SW.Stop; WriteLn(Format('Sum from 0 to %d = %04.3f', [N, Sum])); WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); WriteLn; WriteLn('Using Py_Buffer:'); SW := TStopwatch.StartNew; np_arr := ExtractPythonObjectFrom(arr); PyEngine.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); PyEngine.CheckError; try Sum := 0; for I := 0 to N- 1 do Sum := Sum + PIntArray(PyBuffer.buf)^[I]; WriteLn(Format('Sum from 0 to %d = %04.3f', [N, Sum])); finally PyEngine.PyBuffer_Release(@PyBuffer); end; SW.Stop; WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); WriteLn; // test write access PIntArray(PyBuffer.buf)^[0] := 999; if VarPythonToVariant(BuiltinModule.int(arr.GetItem(0))) = 999 then WriteLn('Successfully modified the numpy array using Py_buffer'); finally DestroyEngine; end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; // stop program loop Terminate; end;
  9. Hi (as suggested by Pyscripter I move this discussion into this support-forum), Ive studied many of the demo's and had the idea that Demo29 was the best point to start looking for a good entrypoint to exchange image-data (16bit so not bitmap) using python4delphi. I am using P4D in my project to use a set of opencv procedures on a large set of stored images. The reading of the files is done in python. The result of this calculation is a floatingpoint array that I need to push back to the Pascal side. Thusfar I am doing this by simply saving a 16bit representation of that array in python as a png and then loading that back in Lazarus. This works but has he disadvantage of : A) write/load the image over IO isnt looking "optimized" for speed B) the floating point becomes a 16bit image loosing quality. As stated I studied Demo29 as I had the idea I could overcome disadvantage A. I implemented a stream (as shown in the example) that wrote 16 bit data to python and received 16 bit back using that same stream-approach. This is however a slower than simply writeing/reading a PNG. So I am searching for a "better" solution but have not seen an example where a 3channel 2D-floating point array gets exchanged between python/pascal. EDIT: Pyscripter suggested to use DEMO35 as a baseline. And although I have tested that before I still have no clue how to declare a multidimensional array of floating point using that example. But my request also mainly asks if anybody has done this and is willing to share some basic code. Otherwise I will have to find that out myself, nothing wrong with that ! cheers Cor waveSharp Free Image sharpen Software https://github.com/CorBer/waveSharp TeensyBat Bat Detector https://github.com/CorBer/teensy_batdetector RegiStax Free Image Processing Software http://www.astronomie.be/registax
×