Jump to content

shineworld

Members
  • Content Count

    337
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by shineworld

  1. shineworld

    XML DOM

    Usually, I use osMemento with BDS2006 (which is IDENTICAL to Delphi7) and Sydney. MSXML DOM is also very fast. With latest software, however, I'm migrating my settings files to JSON so I can open them in Python, where I've another implementation of Memento very close to Delphi version but for JSON.
  2. shineworld

    XML DOM

    CreateChild creates a new child empty node overwriting the eventual existent node. CreateChildSmart at first check if the child already exists and return it, maintaining contents otherwise it creates a new one. PS: I've missed a unit in git: osExceptionUtils.pas osExceptionsUtils add a new fast Abort (AbortFast) that I use often, but in source, you can replace any AbortFast with a native Abort.
  3. shineworld

    XML DOM

    If compile for Windows you can use MSXML directly to load/get/set/DOM and save. Here you can find how I use MSXML with Delphi implementing a light version of the Memento pattern: https://github.com/shineworld/memento Example of use in a system to load/save recently opened files: unit osMRUManager; interface uses osIMemento; type TMRUManager = class private FBackupPath: string; FCount: Integer; FItems: array of string; FMaxItems: Integer; private function GetItems(Index: Integer): string; procedure SetMaxItems(Value: Integer); public procedure Clear; procedure Delete(Index: Integer); function LoadFromFile(const FileName: string): Boolean; function LoadFromMemento(Memento: IMemento): Boolean; procedure Push(const Item: string); function SaveToFile(const FileName: string): Boolean; function SaveToMemento(Memento: IMemento): Boolean; procedure ValidateItems; public constructor Create; public property BackupPath: string read FBackupPath write FBackupPath; property Count: Integer read FCount; property Items[Index: Integer]: string read GetItems; property MaxItems: Integer read FMaxItems write SetMaxItems; end; implementation uses System.SysUtils, osIPersistable, osXMLMemento, osExceptionUtils; const DEF_MAX_ITEMS = 8; constructor TMRUManager.Create; begin // sets default members values FBackupPath := ''; FCount := 0; FItems := nil; FMaxItems := 0; // sets initial max items MaxItems := DEF_MAX_ITEMS; end; procedure TMRUManager.Delete(Index: Integer); var I: Integer; begin if (Index < 0) or (Index >= FMaxItems) then Exit; if (Index >= FCount) then Exit; for I := Index to FCount - 2 do FItems[I] := FItems[I + 1]; FItems[FCount - 1] := ''; Dec(FCount); end; procedure TMRUManager.Clear; begin FCount := 0; end; function TMRUManager.GetItems(Index: Integer): string; begin if (Index < 0) or (Index >= Count) then Result := '' else Result := FItems[Index]; end; function TMRUManager.LoadFromFile(const FileName: string): Boolean; var Memento: IMemento; BackupFileName: string; function GetBackupFileName: string; begin try if FBackupPath = '' then AbortFast; if not DirectoryExists(FBackupPath) then AbortFast; Result := FBackupPath + ExtractFileName(FileName); except Result := ''; end; end; function InternalLoadFromFile(const FileName: string): Boolean; begin try Memento := CreateReadRoot(FileName); if Memento = nil then AbortFast; if Memento.GetName <> 'mru_root' then AbortFast; if not LoadFromMemento(Memento) then AbortFast; Result := True; except Result := False; end; end; begin Clear; try BackupFileName := GetBackupFileName; Result := InternalLoadFromFile(FileName); if Result then begin if BackupFileName <> '' then SaveToFile(BackupFileName); Exit; end; Result := InternalLoadFromFile(BackupFileName); if not Result then AbortFast; SaveToFile(FileName); Result := True; except Clear; Result := False; end; end; function TMRUManager.LoadFromMemento(Memento: IMemento): Boolean; var I: Integer; W: TXMLString; MainNode: IMemento; FileNodes: IMementoArray; begin Clear; try MainNode := Memento.GetChild('mru'); if MainNode = nil then AbortFast; FileNodes := MainNode.GetChildren('file'); if FileNodes = nil then AbortFast; if Length(FileNodes) > MaxItems then AbortFast; FCount := Length(FileNodes); for I := 0 to FCount - 1 do begin if not FileNodes[I].GetString('name', W) then AbortFast; FItems[I] := W; end; Result := True; except Clear; Result := False; end; end; procedure TMRUManager.Push(const Item: string); var I: Integer; J: Integer; begin for I := 0 to FCount - 1 do begin if FItems[I] = Item then begin if I = 0 then Exit; for J := I downto 1 do FItems[J] := FItems[J - 1]; FItems[0] := Item; Exit; end; end; if FCount < FMaxItems then Inc(FCount); for I := FCount - 1 downto 1 do FItems[I] := FItems[I - 1]; FItems[0] := Item; end; function TMRUManager.SaveToFile(const FileName: string): Boolean; var Memento: IMemento; BackupFileName: string; function GetBackupFileName: string; begin try if FBackupPath = '' then AbortFast; if not DirectoryExists(FBackupPath) then AbortFast; Result := FBackupPath + ExtractFileName(FileName); except Result := ''; end; end; function InternalSaveToFile(const FileName: string): Boolean; begin try Memento := CreateWriteRoot('mru_root'); if not SaveToMemento(Memento) then AbortFast; if not (Memento as IPersistable).SaveToFile(FileName, nrmd_UTF8, False) then AbortFast; Result := True; except Result := False; end; end; begin try BackupFileName := GetBackupFileName; if not InternalSaveToFile(FileName) then AbortFast; if BackupFileName <> '' then InternalSaveToFile(BackupFileName); Result := True; except Result := False; end; end; function TMRUManager.SaveToMemento(Memento: IMemento): Boolean; var I: Integer; Node: IMemento; MainNode: IMemento; begin try MainNode := Memento.CreateChildSmart('mru'); for I := 0 to Count - 1 do begin Node := MainNode.CreateChild('file'); Node.PutString('name', FItems[I]); end; Result := True; except Result := False; end; end; procedure TMRUManager.SetMaxItems(Value: Integer); var I: Integer; begin if FMaxItems = Value then Exit; SetLength(FItems, Value); for I := FMaxItems to Value - 1 do FItems[I] := ''; FMaxItems := Value; if FCount > FMaxItems then FCount := FMaxItems; end; procedure TMRUManager.ValidateItems; var I: Integer; begin I := FCount - 1; while I >= 0 do begin if not FileExists(FItems[I]) then Delete(I); Dec(I); end; end; end.
  4. To simplify Python + DelphiVCL + owner Delphi PYD modules for our customer I would like to use the embedded version of Python. When the customer installs our software it installs also an embedded version of Python in the known path so do not touch customer versions or virtual environments. So I can have a customer with a full install of Python 3.10.1 in: C:\Users\silverio.di.QEMSRL\AppData\Local\Programs\Python\Python310\ and our embedded Python 3.10.4 with pre-installed custom modules at: D:\x\develop\qem\cnc_vision_1\python\ The Embedded Python version has PIP and all related modules as well as DelphiVCL, Skia, OpenCV, etc. When I run the embedded Python version I can import delphivcl, skia, cv2, etc without issue BUT not our PYD made with Delphi. However, the same module, called cnc_vision_ext.cp310-win_amd64.pyd, is loaded without issue with the full Python version... Could be that the embedded python distro is missing some lib or basic module required to load it? I've captured the CMD window reported below. Any suggestion? D:\x\develop\qem\cnc_vision_1\python>dir Il volume nell'unitΓ  D Γ¨ Volume Numero di serie del volume: 48BE-3E0C Directory di D:\x\develop\qem\cnc_vision_1\python 04/05/2022 18:09 <DIR> . 04/05/2022 18:09 <DIR> .. 03/05/2022 16:58 5.347.328 cnc_vision_ext.cp310-win_amd64.pyd 22/10/2021 18:30 2.159.352 get-pip.py 04/05/2022 18:05 <DIR> Lib 23/03/2022 23:22 3.439.512 libcrypto-1_1.dll 23/03/2022 23:22 32.792 libffi-7.dll 23/03/2022 23:22 698.784 libssl-1_1.dll 23/03/2022 23:22 32.763 LICENSE.txt 23/03/2022 23:22 194.000 pyexpat.pyd 23/03/2022 23:22 589.053 python.cat 23/03/2022 23:22 99.280 python.exe 23/03/2022 23:22 62.416 python3.dll 23/03/2022 23:22 4.445.648 python310.dll 23/03/2022 23:23 2.638.493 python310.zip 04/05/2022 18:04 79 python310._pth 23/03/2022 23:22 97.744 pythonw.exe 04/05/2022 18:06 302 requirements.txt 04/05/2022 18:06 <DIR> Scripts 23/03/2022 23:22 26.064 select.pyd 23/03/2022 23:22 1.476.048 sqlite3.dll 23/03/2022 23:22 1.118.672 unicodedata.pyd 23/03/2022 23:22 98.224 vcruntime140.dll 23/03/2022 23:22 37.256 vcruntime140_1.dll 23/03/2022 23:22 27.088 winsound.pyd 23/03/2022 23:22 61.392 _asyncio.pyd 23/03/2022 23:22 79.824 _bz2.pyd 23/03/2022 23:22 119.760 _ctypes.pyd 23/03/2022 23:22 248.272 _decimal.pyd 23/03/2022 23:22 124.368 _elementtree.pyd 23/03/2022 23:22 60.880 _hashlib.pyd 23/03/2022 23:22 154.064 _lzma.pyd 23/03/2022 23:22 40.912 _msi.pyd 23/03/2022 23:22 30.672 _multiprocessing.pyd 23/03/2022 23:22 46.032 _overlapped.pyd 23/03/2022 23:22 27.600 _queue.pyd 23/03/2022 23:22 75.216 _socket.pyd 23/03/2022 23:22 94.672 _sqlite3.pyd 23/03/2022 23:22 156.624 _ssl.pyd 23/03/2022 23:22 21.456 _uuid.pyd 23/03/2022 23:22 40.912 _zoneinfo.pyd 04/05/2022 18:04 <DIR> __archive__ 37 File 24.003.554 byte 5 Directory 206.815.965.184 byte disponibili D:\x\develop\qem\cnc_vision_1\python>C:\Users\silverio.di.QEMSRL\AppData\Local\Programs\Python\Python310\Python.exe Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import delphivcl as vcl >>> import cnc_vision_ext as ext >>> quit() D:\x\develop\qem\cnc_vision_1\python>.\python.exe Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import delphivcl as vcl >>> import cnc_vision_ext as ext Traceback (most recent call last): File "<stdin>", line 1, in <module> SystemError: initialization of cnc_vision_ext did not return an extension module >>> quit() D:\x\develop\qem\cnc_vision_1\python>
  5. Could be interesting, to have time to write something about.... Natively the Delphi project is around 10 million lines and with the introduction of expandability via Python I don't know where it will end πŸ™‚ Fortunately, in an I7, Delphi is so fast that it takes just over 3 minutes to compile the whole project. In another language, I could go for a quick lunch.
  6. I work in a company that makes control boards for CNC and related control environments on PC, but I don't physically own a CNC πŸ™‚ However, we also drive 5-axis CNCs and more. The PC control part has always been done with Delphi and I couldn't be happier. I have abandoned other development environments and find that as fast and productive as Delphi there is no other, at least for this sector. I work in software/firmware development for embedded boards and proprietary real-time OS but in recent years most of my time is spent with my nose in Delphi pascal πŸ™‚ I'm starting to get old to still work with assembler and C...
  7. However, in my case, Python + OpenCV + DelphiVCL is very very very fast in a big range of cases. Previously UI was TkInter, followed by PsSimpleGUI but very limited in UI things.
  8. Very interesting the vision lab project.
  9. To communicate between Delphi pure UI process and Python process I've implemented an API Server, based on TCP/IP + JSON encrypted messages. A Python package (cnc-api-client-core in PyPi) implements the same protocol (API Client). CNC Board covers any type of CNC (plasma, laser, mill, etc, till 9-Axis in EtherCAT Drivers or 6-Axis Step/DIR Drivers). With Python API Client interface I can do anything on CNC Control Software and CNC Board, exposing CNC features to any Python UI interface. Here an old example of Python process which use API Client and PySimpleGUI UI to interact with CNC: Now UI was moved to DelphiFMX to be used in Windows and Linux OS.
  10. A moment I've tried to create a simple framework package for Python language. The goal is to add vision features such as finding two printer markes to rotate and scale a CAD/CAM toolpath before running in a CNC. UI main program is a pure Delphi program. The called external program is a Python + delphivcl + opencv + skia and more other packages.
  11. I have a lot, pretty much everything, to learn about Python, importing and building modules and packages. I had NEVER used Python or had never been interested in Python before the appearance and knowledge of Python4Delphi, some months ago. Since Embarcadero made DelphiVCL and Python4Delphi available, I have thrown myself headlong into bringing code that normally runs on native Delphi programs but standalone on Delphi modules and extensions for Python so that customers can make their own customizations via Python. Now, looking at how DelphiVCL initializes the Python engine I found that I have misunderstood a lot of things. Solve the problem is based on changing: ExtensionManager.FEngine.UseLastKnownVersion := True; ExtensionManager.FEngine.OpenDll(''); to ExtensionManager.FEngine.UseLastKnownVersion := True; ExtensionManager.FEngine.LoadDllInExtensionModule(); Obviously, in the end, I will collect any PYD (actually 32 Pyds) in one PyPi wheel install package so all Pyds will be in the Lib\ite-packages folder like Embarcadero does with DelphiVCL. The resulting framework will use opencv to capture, filter, and evaluate images to find specific objects, measure sizes, etc. At moment I don't use any form of AI to do that to remain fast and simple.
  12. shineworld

    A question for thread reference

    Following your suggestion, I've solved using PyBytes_FromStringAndSize... very very fast!!! 1] I've created a VideoCapture as native Delphi component TCncVisionCapturePxc. This can be used for standard Delphi programs or wrapped in an expansion module pyd to be used in Python. In this class, I can't use python objects, obviously as return values but the dynamic array of bytes for a frame. 2] I wrapped the class to export in pyd adding an extra method to get fastly the frame with PyBytes_FromStringAndSize: uses ... osCncVideoCapturePxc; type TPyCncVisionVideoCapturePxc_Wrapper = class(TPyDelphiObject) private constructor Create(APythonType: TPythonType); override; constructor CreateWith(PythonType: TPythonType; args: PPyObject); override; function Repr: PPyObject; override; class function DelphiObjectClass: TClass; override; class procedure RegisterMethods(PythonType: TPythonType); override; function GrabbedFrameEx(pself, args: PPyObject): PPyObject; cdecl; end; ... { TPyCncVisionVideoCapturePxc_Wrapper } constructor TPyCncVisionVideoCapturePxc_Wrapper.Create(APythonType: TPythonType); begin inherited; DelphiObject := TCncVisionVideoCapturePxc.Create; Owned := False; end; constructor TPyCncVisionVideoCapturePxc_Wrapper.CreateWith(PythonType: TPythonType; args: PPyObject); begin inherited; //### end; class function TPyCncVisionVideoCapturePxc_Wrapper.DelphiObjectClass: TClass; begin Result := TCncVisionVideoCapturePxc; end; function TPyCncVisionVideoCapturePxc_Wrapper.Repr: PPyObject; begin Result := GetPythonEngine.PyUnicodeFromString('none to show at moment'); end; class procedure TPyCncVisionVideoCapturePxc_Wrapper.RegisterMethods(PythonType: TPythonType); begin inherited; with PythonType do begin AddMethod('grabbed_frame_ex', @TPyCncVisionVideoCapturePxc_Wrapper.GrabbedFrameEx, 'get grabbed frame as string' ); end; end; function TPyCncVisionVideoCapturePxc_Wrapper.GrabbedFrameEx(pself, args: PPyObject): PPyObject; cdecl; var S: AnsiString; FrameSize: Integer; Frame: TByteDynArray; VideoCapture: TCncVisionVideoCapturePxc; begin Adjust(@Self); VideoCapture := TCncVisionVideoCapturePxc(DelphiObject); Frame := VideoCapture.grabbed_frame; FrameSize := Length(Frame); if FrameSize = 0 then Exit(GetPythonEngine.ReturnNone); SetLength(S, FrameSize); CopyMemory(@S[1], Frame, FrameSize); Result := GetPythonEngine.PyBytes_FromStringAndSize(@S[1], FrameSize); end; Adjust(@Self) was a nightmare because I don't know about that and without the self access to DelphiObject is always invalid. Now from 80ms to transfer an image from Delphi to Python is moved to 128uS. I'm happy.
  13. shineworld

    A question for thread reference

    When I can I move thread things to Delphi Thread in an expansion module but this has a limited range of operations, you have to use only Delphi libraries, no Python code there. For example, I'm banging my head on a very odd problem without a solution. 1] In a Delphi extension module I get frames from a proprietary camera that can't be accessed with OpenCV VideoCapture, for a lot of reasons. 2] A Python thread gets the frame data from the Delphi extension module as a property to TByteDynArray data. TByteDynArray is converted to List by PythonWrapper and the inner system copies any byte of the array in a VariantArray which takes a big amount of time. To get back from the Delphi module 48000 image bytes take 0.080 (80ms) which is too much, slowing down a lot the FPS. A classical bottleneck..... I've tried to change the FrameData returned from TByteDynArray to AnsiString and data movement is very very fast (0.001ms) but AnsiString with Frame Data is encoded to Unicode before sending it back to python and str.encode(frame_data) in Python is not applicable.... So my question? What is the best way to get an array of bytes from the Delphi extension module (pyd) back to python? Have I to enter in the HELL of array pointers shared between Delphi to Python ? Delphi extension module is able to capture till 60fps, but the bottleneck of frame retrieve from PYD to Python fall down my FPS to 6FPS...
  14. shineworld

    A question for thread reference

    I'm not a Win guru but Windows has owner rules on how much time is left to a process and related task. Usually, it does not permit to use of more than 40/50% of the time to a process/thread depending on many factors. GIL Lock system however limits a lot of threading performances in Python, is not permit a true Threading programming as like as in other languages . When possibile I move python math code in delphi extension module native threads or I use Cython to improve moudule performances. To improve a little the performances of time.Sleep() and timers and so of GIL I've tried to change the precision timer of Windows with: from os_utils import os_improve_timings ... .. . def main(): """Main entry point.""" ... .. . # MAIN entry point when module is called if __name__ == '__main__': # improve os timings and run main with os_improve_timings(): main() os_utils.py
  15. shineworld

    Data exchange between Delphi and SciKit Learn

    Do you have tried the tutorials from Webinar II? Perhaps they cover your question. https://github.com/pyscripter/python4delphi/tree/master/Tutorials/Webinar II
  16. shineworld

    Python DLL Init question

    There are many ways to "define" what Pythonxxx.DLL will be used by PythonEngine used in the Delphi application or in a PYD extension module made with Delphi. You can set "MyEngine.UseLaskKnownVersion := True" so the Engine search for 3.10, then 3.9, ... till the oldest version is supported. You can also "fix" a version leaving it to PythonEngine to search for the path. This is done thanks to fact that Python "stores" any installed Python version path in Windows Registry. {** * TAKE CARE * ========= * PYD modules need to be build for a specific Python version using below defines. * The defines MUST be mutually exclusive. * If not defined the "Use Last Known Version" will be used. * **} {$DEFINE USE_PYTHON_39} {.DEFINE USE_PYTHON_310} {$IF Defined(USE_PYTHON_39) and Defined(USE_PYTHON_310)} {$Message Fatal 'Only one Python version can be set.'} {$IFEND} { module import functions } function PyInit_cnc_vision_ext: PPyObject; begin Result := nil; try ExtensionManager.FEngine := TPythonEngine.Create(nil); ExtensionManager.FEngine.AutoFinalize := False; {$IF Defined(USE_PYTHON_39)} ExtensionManager.FEngine.DLLName := 'python39.dll'; ExtensionManager.FEngine.UseLastKnownVersion := False; ExtensionManager.FEngine.OpenDll(ExtensionManager.FEngine.DLLName); {$ELSEIF Defined(USE_PYTHON_310)} ExtensionManager.FEngine.DLLName := 'python310.dll'; ExtensionManager.FEngine.UseLastKnownVersion := False; ExtensionManager.FEngine.OpenDll(ExtensionManager.FEngine.DLLName); {$ELSE} ExtensionManager.FEngine.UseLastKnownVersion := True; ExtensionManager.FEngine.OpenDll(''); {$IFEND} ExtensionManager.FModule := TPythonModule.Create(nil); ExtensionManager.FModule.Engine := ExtensionManager.FEngine; ExtensionManager.FModule.ModuleName := 'cnc_vision_ext'; ExtensionManager.FWrapper := TPyDelphiWrapper.Create(nil); ExtensionManager.FWrapper.Engine := ExtensionManager.FEngine; ExtensionManager.FWrapper.Module := ExtensionManager.FModule; ExtensionManager.FModule.Initialize; ExtensionManager.FWrapper.OnInitialization := ExtensionManager.WrapperInitializationEvent; ExtensionManager.FWrapper.Initialize; Result := ExtensionManager.FModule.Module; except end; end; This is a part of my extension module in which I can define if the module is built for 3.9, 3.10, or looking for the last known version. OpenDLL internally searches in Windows Registry where the requested python engine path is. Take a look at file: PythonVersions.pas GetRegisteredPythonVersion() function there is also a good description of system. https://github.com/pyscripter/python4delphi/wiki/FindingPython I don't know how works with Anaconda envs or embedded python distros.
  17. shineworld

    Transferring TBitmap to Python and back

    The way to manage FPU exceptions in DELPHI is not the same on Python so you have to add this in your Delphi unit: initialization MaskFPUExceptions(True); PS: Actually I've moved from PIL to SKIA in image management. Skia offers more features than Pillow. import skia ... . ... # frame_inp is a numpy containing RGB image # convert numpy image from RGB to RGBA (add AlphaBlend layer) skia_frame = cv2.cvtColor(frame_inp, cv2.COLOR_RGB2RGBA) # create a skia image from numpy RGBA array skia_image = skia.Image.fromarray(skia_frame) # sample of image resize with skia image_ratio = 1.0 image_width = skia_image.width() image_height = skia_image.height() camera_image_width = self.CameraImage.Width camera_image_height = self.CameraImage.Height r_w = image_width / camera_image_width r_h = image_height / camera_image_height if r_w > 1.0 or r_h > 1.0: image_ratio = max(r_w, r_h) image_width = int(image_width / image_ratio) image_height = int(image_height / image_ratio) skia_image = skia_image.resize(image_width, image_height, skia.FilterQuality.kLow_FilterQuality) skia_frame = skia_image.toarray() # sample of antialiasing drawings on skia paint = skia.Paint(AntiAlias=True, Color=skia.ColorRED) canvas = skia.Canvas(skia_frame) canvas.drawLine(0, int(image_height / 2), image_width, int(image_height / 2), paint) canvas.drawLine(int(image_width / 2), 0, int(image_width / 2), image_height, paint) # back skia image to numpy array RGB skia_frame = cv2.cvtColor(skia_frame, cv2.COLOR_RGBA2RGB) # draw of numpy array RGB to delphi Image ext.update_image_from_bytes( self.CameraImage, skia_frame.tobytes(), skia_frame.shape[1], skia_frame.shape[0], 3 if len(skia_frame.shape) == 3 else 1 ) self.CameraImage.Repaint()
  18. shineworld

    delphivcl and PyLint

    Hi all, there is a way to inform PyLint about delphivcl types ? I've tried to add it to .pylintrc without results: [MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-allow-list= # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. (This is an alternative name to extension-pkg-allow-list # for backward compatibility.) extension-pkg-whitelist=cv2,delphivcl # Return non-zero exit code if any of these messages/categories are detected, # even if score is above --fail-under value. Syntax same as enable. Messages # specified are enabled, while categories only check already-enabled messages. fail-on= ... .. .
  19. shineworld

    Transferring TBitmap to Python and back

    I've left only the upon described code in my extension so you can evaluate the code to check if meets your needs. cnc_vision_video_ext.7z
  20. shineworld

    Transferring TBitmap to Python and back

    Delphi Extension way vs Pillow using time.time_perf: # delphi module extension way t1 = time.perf_counter() ext.update_image_from_bytes( self.CameraImage, frame_inp.tobytes(), frame_inp.shape[1], frame_inp.shape[0], 3 if len(frame_inp.shape) == 3 else 1) self.CameraImage.Repaint() t2 = time.perf_counter() # pillow way t3 = time.perf_counter() rgb_im: PIL_Image.Image = PIL_Image.fromarray(np.uint8(frame_inp[...,[2,1,0]].copy())).convert('RGB') self.CameraImage.Picture.Bitmap.SetSize(rgb_im.width, rgb_im.height) dib = PIL_ImageWin.Dib(rgb_im) dib.expose(self.CameraImage.Picture.Bitmap.Canvas.Handle) self.CameraImage.Repaint() t4 = time.perf_counter() # timings report self.Caption = 'EXT = {:7.3f} ms - PILLOW {:7.3f}'.format(t2 - t1, t4 - t3) Delphi way take half time in this case πŸ™‚
  21. shineworld

    Transferring TBitmap to Python and back

    To fastly send an image in NumPy array to a delphivcl.Image component, without use Pillow and DIB way, you can create a new python extension module with Delphi where you wrap a update_image_from_bytes(image: Image(), data: bytes, width: int, height: int, channels: int) -> bool { generic functions wrappers } function CncVisionUpdateImageFromBytesArray_Wrapper(pself, args: PPyObject): PPyObject; cdecl; var Image: TImage; Width: Integer; Height: Integer; Channels: Integer; Bytes: TByteArray; BytesPyObj: PPyObject; ImagePyObj: PPyObject; function PyBytesAsBytes(Obj: PPyObject): TByteArray; var Size: NativeInt; Buffer: PAnsiChar; begin Result := nil; with GetPythonEngine do begin if not PyBytes_Check(Obj) then Exit; PyBytes_AsStringAndSize(Obj, Buffer, Size); if Size = 0 then Exit; SetLength(Result, Size); CopyMemory(Result, Buffer, Size); end; end; begin with GetPythonEngine do begin try if PyArg_ParseTuple(args, 'OOiii:update_image_from_bytes', @ImagePyObj, @BytesPyObj, @Width, @Height, @Channels) <> 0 then begin if ImagePyObj.ob_type.tp_name <> 'Image' then AbortFast; Image := TPyDelphiImage(TPyObject(PAnsiChar(ImagePyObj) + SizeOf(PyObject))).DelphiObject; if Image = nil then AbortFast; if BytesPyObj.ob_type.tp_name <> 'bytes' then AbortFast; Bytes := PyBytesAsBytes(BytesPyObj); if Bytes = nil then AbortFast; if Length(Bytes) <> (Width * Height * Channels) then AbortFast; if not CncVisionUpdateImageFromBytesArray(Image, Bytes, Width, Height, Channels) then AbortFast; Result := ReturnTrue; end else Result := ReturnFalse; except Result := ReturnFalse; end; end; end; ... . ... procedure TPyExtensionManager.WrapperInitializationEvent(Sender: TObject); begin FWrapper.RegisterFunction ( PAnsiChar('update_image_from_bytes'), CncVisionUpdateImageFromBytesArray_Wrapper, PAnsiChar('update delphivcl Image object from bytes array with width, height & channels') ); end; Then the pascal byte array to Image is: function CncVisionUpdateImageFromBytesArray(Image: TImage; Bytes: osCncVisionTypes.TByteArray; Width, Height, Channels: Integer): Boolean; type TRGBBitmapInfoHeader = record Header: TBitmapInfoHeader; ColorTable: array[0..255] of TRGBQuad; end; PBitmapInfoHeader = ^TBitmapInfoHeader; var I: Integer; Bitmap: TBitmap; IsGray: Boolean; Buffer: TRGBBitmapInfoHeader; BmpInfoHeader: PBitmapInfoHeader; var BmpInfoBuffer: TBitmapInfo absolute Buffer; begin try if Length(Bytes) = 0 then Exit(False); if Length(Bytes) <> (Width * Height * Channels) then Exit(False); if not Channels in [1, 3] then Exit(False); if Image.Picture.Bitmap = nil then Image.Picture.Bitmap := TBitmap.Create; Bitmap := Image.Picture.Bitmap; Bitmap.Width := Width; Bitmap.Height := Height; BmpInfoHeader := PBitmapInfoHeader(@Buffer); BmpInfoHeader^.biSize := SizeOf(TBitmapInfoHeader); BmpInfoHeader^.biWidth := Width; BmpInfoHeader^.biHeight := -Height; BmpInfoHeader^.biPlanes := 1; BmpInfoHeader^.biBitCount := 8 * Channels; BmpInfoHeader^.biCompression := BI_RGB; BmpInfoHeader^.biSizeImage := 0; BmpInfoHeader^.biXPelsPerMeter := 0; BmpInfoHeader^.biYPelsPerMeter := 0; BmpInfoHeader^.biClrUsed := 0; BmpInfoHeader^.biClrImportant := 0; // if Bytes array is for monochrome image (channels = 1) normalizes bitmap color table // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader // // The BITMAPINFOHEADER structure may be followed by an array of palette entries or color masks. // The rules depend on the value of biCompression. // // - If biCompression equals BI_RGB and the bitmap uses 8 bpp or less, the bitmap has a color table immediately // following the BITMAPINFOHEADER structure. The color table consists of an array of RGBQUAD values. The size // of the array is given by the biClrUsed member. If biClrUsed is zero, the array contains the maximum number // of colors for the given bitdepth; that is, 2^biBitCount colors. if Channels = 1 then begin for I := 0 to 255 do begin Buffer.ColorTable[I].rgbBlue := I; Buffer.ColorTable[I].rgbGreen := I; Buffer.ColorTable[I].rgbRed := I; end; end; LockWindowUpdate(Bitmap.Canvas.Handle); try Result := SetDIBitsToDevice ( Bitmap.Canvas.Handle, // handle to device context 0, // x-coordinate of upper-left corner of 0, // y-coordinate of upper-left corner of Width, // source rectangle width Height, // source rectangle height 0, // x-coordinate of Lower-left corner of 0, // y-coordinate of Lower-left corner of 0, // first scan line in array Height, // number of scan lines Bytes, // address of array with DIB bits BmpInfoBuffer, // address of structure with bitmap info DIB_RGB_COLORS // RGB or palette indexes ) > 0; finally LockWindowUpdate(0) end; except Result := False; end; end; CncVisionUpdateImageFromBytesArray permits RGB or Monochrome Bytes array. In python the code to update image is simple: import cnc_vision_ext as ext # this is only my delphi extension module for python where extra features for delphivcl are placed # for monochrome frames to CameraImage (delphivcl.Image object) frame = get_frame_image_from_somewhere() frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) ext.update_image_from_bytes( self.CameraImage, frame_inp.tobytes(), frame_inp.shape[1], frame_inp.shape[0], 3 if len(frame_inp.shape) == 3 else 1) self.CameraImage.Invalidate() # for color frames to CameraImage (delphivcl.Image object) frame = get_frame_image_from_somewhere() ext.update_image_from_bytes( self.CameraImage, frame_inp.tobytes(), frame_inp.shape[1], frame_inp.shape[0], 3 if len(frame_inp.shape) == 3 else 1) self.CameraImage.Invalidate()
  22. Hi all, I'm using DelphiVCL + PyScripter to develop a Python windows application.I've created and "pyd" extension module in which perform some critical time operations or add support functions missing in DelphiVCL. - In python script I create an Image - now I would like to send a bytes array to cnc_vision_ext module (made with Delphi): import delphivcl import cnc_vision_ext as ext .... my_Image = delphivcl.Image(Form1) ext.update_image_from_bytes(my_image, 1024, 768, 3) Now in the wrapper CncVisionUpdateImageFromBytesArray_Wrapper I need to extract the TImage instance contained in PPyObject of args. I was not able to find the right way.... { generic functions wrappers } function CncVisionUpdateImageFromBytesArray_Wrapper(pself, args: PPyObject): PPyObject; cdecl; var Image: TImage; Width: Integer; Height: Integer; Channels: Integer; Bytes: TByteArray; ImagePyObj: PPyObject; begin with GetPythonEngine do begin if PyArg_ParseTuple(args, 'Oiii:update_image_from_bytes', @ImagePyObj, @Width, @Height, @Channels) <> 0 then begin // ??? HOW TO GET BACK wrapped TImage from Image() object created with my_image = delphivcl.Image(owner) ??? Image := TImage((PythonToDelphi(ImagePyObj) as TPyDelphiObject).DelphiObject); Result := PyUnicodeFromString ( Format('%s %d %d %d', [Image.Name, Width, Height, Channels]) ); end else Result := nil; end; end; { TPyExtensionManager } procedure TPyExtensionManager.WrapperInitializationEvent(Sender: TObject); begin FWrapper.RegisterDelphiWrapper(TPyCncVisionVideoCapturePxc_Wrapper); FWrapper.RegisterFunction ( PAnsiChar('update_image_from_bytes'), CncVisionUpdateImageFromBytesArray_Wrapper, PAnsiChar('update delphivcl Image object from bytes array with width, height & channels') ); FWrapper.RegisterFunction ( PAnsiChar('get_usb_camera_device_list'), CncVisionGetUSBCameraDeviceList_Wrapper, PAnsiChar('get list of available usb camera devices') ); end; Thanks in advance for the suggestions.... Best Regards Silverio
  23. shineworld

    get back a Image() object created from Python

    Seems this works but is hard to say OK, at moment, for me: { A B C +-------------------++------------------------------------------------------+ | PyObject header || TPyObject class | +----------+--------++-----------------+------------+----------+------------+ |ob_refcnt |ob_type ||hidden Class Ptr |PythonType |IsSubType |PythonAlloc | |integer |pointer ||pointer |TPythonType |Boolean |Boolean | |4 bytes |4 bytes ||4 bytes |4 bytes |1 byte |1 byte | +----------+--------++-----------------+------------+----------+------------+ ^ ^ | | ptr returned ptr returned by Adjust by GetSelf - a Python object must start at A. - a Delphi class class must start at B - TPyObject.InstanceSize will return C-B - Sizeof(TPyObject) will return C-B - The total memory allocated for a TPyObject instance will be C-A, even if its InstanceSize is C-B. - When turning a Python object pointer into a Delphi instance pointer, PythonToDelphi will offset the pointer from A to B. - When turning a Delphi instance into a Python object pointer, GetSelf will offset Self from B to A. - Properties ob_refcnt and ob_type will call GetSelf to access their data. } function CncVisionUpdateImageFromBytesArray_Wrapper(pself, args: PPyObject): PPyObject; cdecl; var Image: TImage; Width: Integer; Height: Integer; Channels: Integer; Bytes: TByteArray; ImagePyObj: PPyObject; begin with GetPythonEngine do begin if PyArg_ParseTuple(args, 'Oiii:update_image_from_bytes', @ImagePyObj, @Width, @Height, @Channels) <> 0 then begin Image := TPyDelphiImage(TPyObject(PAnsiChar(ImagePyObj)+Sizeof(PyObject))).DelphiObject; Result := PyUnicodeFromString ( Format('%s %d %d %d', [Image.Name, Width, Height, Channels]) ); end else Result := nil; end; end;
  24. shineworld

    Transferring TBitmap to Python and back

    TVideoCapture is managed as a record, not a class, with class members so do not requires a TVideoCapture.Create It is defined in videoio.inc. Never tried if this structure permits more than one instance. I've checked the demos and copied/pasted the minimal code to try it. My actual implementation is yet on Python + delphivcl + opencv. It's a very big project and I'm yet in the writting phase. When finished I will try to recreate my vision python framework directly in Delphi code + DelphiPythonVCL.
  25. shineworld

    Transferring TBitmap to Python and back

    In the dropbox link, I can't attach files bigger than 4.8Mb here, you can find a very simple Delphi Sydney 10.4.1 project where the OpenCV get frames from a USB camera (VideoCapture device 0) and with the trackbar, you can apply Canny filter thresholds 1 & 2. The required DLLs are in Win64\Debug & Release folders BUT can also be placed one time for always in Windows OS folders. Just my first test with Delphi-OpenCV. ONLY 64 bit applications are supported by Delphi-OpenCV class. https://www.dropbox.com/s/iqzlnfwttj20pnr/cnc_vision_2.7z?dl=0 PS: I don't know if there are other MS dependencies because I've Microsoft Visual Studio installed and some DLL could be already available for MSVC packages. During run-in IDE these are modules loaded: Module Load: cnc_vision_2. No Debug Info. Base Address: $0000000000400000. Process cnc_vision_2.exe (14340) Module Load: ntdll.dll. No Debug Info. Base Address: $00007FFD371B0000. Process cnc_vision_2.exe (14340) Module Load: KERNEL32.dll. No Debug Info. Base Address: $00007FFD36870000. Process cnc_vision_2.exe (14340) Module Load: KERNELBASE.dll. No Debug Info. Base Address: $00007FFD34BA0000. Process cnc_vision_2.exe (14340) Module Load: WINSPOOL.DRV. No Debug Info. Base Address: $00007FFD2AF90000. Process cnc_vision_2.exe (14340) Module Load: SHELL32.dll. No Debug Info. Base Address: $00007FFD36930000. Process cnc_vision_2.exe (14340) Module Load: WINMM.dll. No Debug Info. Base Address: $00007FFD2B2A0000. Process cnc_vision_2.exe (14340) Module Load: msvcp_win.dll. No Debug Info. Base Address: $00007FFD34FC0000. Process cnc_vision_2.exe (14340) Module Load: COMCTL32.dll. No Debug Info. Base Address: $00007FFD26F50000. Process cnc_vision_2.exe (14340) Module Load: msvcrt.dll. No Debug Info. Base Address: $00007FFD35B40000. Process cnc_vision_2.exe (14340) Module Load: ucrtbase.dll. No Debug Info. Base Address: $00007FFD348D0000. Process cnc_vision_2.exe (14340) Module Load: msvcrt.dll. No Debug Info. Base Address: $0000000000D50000. Process cnc_vision_2.exe (14340) Module Unload: msvcrt.dll. Process cnc_vision_2.exe (14340) Module Load: msvcrt.dll. No Debug Info. Base Address: $0000000000DF0000. Process cnc_vision_2.exe (14340) Module Unload: msvcrt.dll. Process cnc_vision_2.exe (14340) Module Load: USER32.dll. No Debug Info. Base Address: $00007FFD35BE0000. Process cnc_vision_2.exe (14340) Module Load: GDI32.dll. No Debug Info. Base Address: $00007FFD370E0000. Process cnc_vision_2.exe (14340) Module Load: win32u.dll. No Debug Info. Base Address: $00007FFD34F20000. Process cnc_vision_2.exe (14340) Module Load: win32u.dll. No Debug Info. Base Address: $00000000001A0000. Process cnc_vision_2.exe (14340) Module Unload: win32u.dll. Process cnc_vision_2.exe (14340) Module Load: OLEAUT32.dll. No Debug Info. Base Address: $00007FFD35390000. Process cnc_vision_2.exe (14340) Module Load: gdi32full.dll. No Debug Info. Base Address: $00007FFD34A00000. Process cnc_vision_2.exe (14340) Module Load: VERSION.dll. No Debug Info. Base Address: $00007FFD2DB50000. Process cnc_vision_2.exe (14340) Module Load: combase.dll. No Debug Info. Base Address: $00007FFD36460000. Process cnc_vision_2.exe (14340) Module Load: RPCRT4.dll. No Debug Info. Base Address: $00007FFD35540000. Process cnc_vision_2.exe (14340) Module Load: ADVAPI32.dll. No Debug Info. Base Address: $00007FFD36140000. Process cnc_vision_2.exe (14340) Module Load: SECHOST.dll. No Debug Info. Base Address: $00007FFD36290000. Process cnc_vision_2.exe (14340) Module Load: ole32.dll. No Debug Info. Base Address: $00007FFD36330000. Process cnc_vision_2.exe (14340) Module Load: NETAPI32.dll. No Debug Info. Base Address: $00007FFD21B00000. Process cnc_vision_2.exe (14340) Module Load: netutils.dll. No Debug Info. Base Address: $00007FFD33E40000. Process cnc_vision_2.exe (14340) Module Load: IMM32.dll. No Debug Info. Base Address: $00007FFD356A0000. Process cnc_vision_2.exe (14340) Module Load: MSCTF.dll. No Debug Info. Base Address: $00007FFD35210000. Process cnc_vision_2.exe (14340) Module Load: UxTheme.dll. No Debug Info. Base Address: $00007FFD32280000. Process cnc_vision_2.exe (14340) Module Load: AppCore.dll. No Debug Info. Base Address: $00007FFD32800000. Process cnc_vision_2.exe (14340) Module Load: bcryptPrimitives.dll. No Debug Info. Base Address: $00007FFD34B10000. Process cnc_vision_2.exe (14340) Module Load: WTSAPI32.dll. No Debug Info. Base Address: $00007FFD2F7C0000. Process cnc_vision_2.exe (14340) Module Load: WINSTA.dll. No Debug Info. Base Address: $00007FFD33640000. Process cnc_vision_2.exe (14340) Module Load: opencv_world455.dll. No Debug Info. Base Address: $00007FFCE7660000. Process cnc_vision_2.exe (14340) Module Load: WS2_32.dll. No Debug Info. Base Address: $00007FFD35D80000. Process cnc_vision_2.exe (14340) Module Load: COMDLG32.dll. No Debug Info. Base Address: $00007FFD35460000. Process cnc_vision_2.exe (14340) Module Load: SHCORE.dll. No Debug Info. Base Address: $00007FFD367C0000. Process cnc_vision_2.exe (14340) Module Load: SHLWAPI.dll. No Debug Info. Base Address: $00007FFD35330000. Process cnc_vision_2.exe (14340) Module Load: VCRUNTIME140.dll. No Debug Info. Base Address: $00007FFD21D40000. Process cnc_vision_2.exe (14340) Module Load: CONCRT140.dll. No Debug Info. Base Address: $00007FFD231C0000. Process cnc_vision_2.exe (14340) Module Load: MSVCP140.dll. No Debug Info. Base Address: $00007FFD14770000. Process cnc_vision_2.exe (14340) Module Load: VCRUNTIME140_1.dll. No Debug Info. Base Address: $0000000000830000. Process cnc_vision_2.exe (14340) Module Unload: VCRUNTIME140_1.dll. Process cnc_vision_2.exe (14340) Module Load: VCRUNTIME140_1.dll. No Debug Info. Base Address: $00007FFD2F5D0000. Process cnc_vision_2.exe (14340) Module Load: opencv_videoio_msmf455_64.dll. No Debug Info. Base Address: $00007FFD22EB0000. Process cnc_vision_2.exe (14340) Module Load: MF.dll. No Debug Info. Base Address: $00007FFD20830000. Process cnc_vision_2.exe (14340) Module Load: MFReadWrite.dll. No Debug Info. Base Address: $00007FFD1F890000. Process cnc_vision_2.exe (14340) Module Load: dxgi.dll. No Debug Info. Base Address: $00007FFD33210000. Process cnc_vision_2.exe (14340) Module Load: MFPlat.DLL. No Debug Info. Base Address: $00007FFD060C0000. Process cnc_vision_2.exe (14340) Module Load: CFGMGR32.dll. No Debug Info. Base Address: $00007FFD351C0000. Process cnc_vision_2.exe (14340) Module Load: d3d11.dll. No Debug Info. Base Address: $00007FFD300B0000. Process cnc_vision_2.exe (14340) Module Load: MFCORE.dll. No Debug Info. Base Address: $00007FFCE71D0000. Process cnc_vision_2.exe (14340) Module Load: CRYPT32.dll. No Debug Info. Base Address: $00007FFD35060000. Process cnc_vision_2.exe (14340) Module Load: bcrypt.dll. No Debug Info. Base Address: $00007FFD349D0000. Process cnc_vision_2.exe (14340) Module Load: POWRPROF.dll. No Debug Info. Base Address: $00007FFD33EA0000. Process cnc_vision_2.exe (14340) Module Load: ksuser.dll. No Debug Info. Base Address: $00007FFD32120000. Process cnc_vision_2.exe (14340) Module Load: CRYPTBASE.dll. No Debug Info. Base Address: $00007FFD342A0000. Process cnc_vision_2.exe (14340) Module Load: RTWorkQ.DLL. No Debug Info. Base Address: $00007FFD1D060000. Process cnc_vision_2.exe (14340) Module Load: UMPDC.dll. No Debug Info. Base Address: $00007FFD33D10000. Process cnc_vision_2.exe (14340) Module Load: CLBCatQ.DLL. No Debug Info. Base Address: $00007FFD36010000. Process cnc_vision_2.exe (14340) Module Load: DEVENUM.DLL. No Debug Info. Base Address: $00007FFD252A0000. Process cnc_vision_2.exe (14340) Module Load: SETUPAPI.dll. No Debug Info. Base Address: $00007FFD356D0000. Process cnc_vision_2.exe (14340) Module Load: NTMARTA.dll. No Debug Info. Base Address: $00007FFD335A0000. Process cnc_vision_2.exe (14340) Module Load: DEVOBJ.dll. No Debug Info. Base Address: $00007FFD34670000. Process cnc_vision_2.exe (14340) Module Load: WINTRUST.dll. No Debug Info. Base Address: $00007FFD34F50000. Process cnc_vision_2.exe (14340) Module Load: MSASN1.dll. No Debug Info. Base Address: $00007FFD344B0000. Process cnc_vision_2.exe (14340) Module Load: msdmo.dll. No Debug Info. Base Address: $00007FFD2C5B0000. Process cnc_vision_2.exe (14340) Module Load: QCap.dll. No Debug Info. Base Address: $00007FFD16770000. Process cnc_vision_2.exe (14340) Module Load: QUARTZ.dll. No Debug Info. Base Address: $00007FFD145A0000. Process cnc_vision_2.exe (14340) Module Load: Windows.Storage.dll. No Debug Info. Base Address: $00007FFD32A00000. Process cnc_vision_2.exe (14340) Module Load: Wldp.dll. No Debug Info. Base Address: $00007FFD34330000. Process cnc_vision_2.exe (14340) Module Load: Source.dll. No Debug Info. Base Address: $00007FFD166B0000. Process cnc_vision_2.exe (14340) Module Load: ATL.DLL. No Debug Info. Base Address: $00007FFD24C60000. Process cnc_vision_2.exe (14340) Module Load: MFSENSORGROUP.dll. No Debug Info. Base Address: $00007FFD15110000. Process cnc_vision_2.exe (14340) Module Load: ksproxy.ax. No Debug Info. Base Address: $00007FFD14550000. Process cnc_vision_2.exe (14340) Module Load: d3d9.dll. No Debug Info. Base Address: $00007FFD2CF10000. Process cnc_vision_2.exe (14340) Module Load: dwmapi.dll. No Debug Info. Base Address: $00007FFD32510000. Process cnc_vision_2.exe (14340) Module Load: policymanager.dll. No Debug Info. Base Address: $00007FFD2F4A0000. Process cnc_vision_2.exe (14340) Module Load: msvcp110_win.dll. No Debug Info. Base Address: $00007FFD33A30000. Process cnc_vision_2.exe (14340) Module Load: vidcap.dll. No Debug Info. Base Address: $00007FFD24C50000. Process cnc_vision_2.exe (14340) Module Load: kswdmcap.dll. No Debug Info. Base Address: $00007FFD23190000. Process cnc_vision_2.exe (14340) Module Load: MFC42.dll. No Debug Info. Base Address: $00007FFCF43E0000. Process cnc_vision_2.exe (14340) Module Load: QEdit.dll. No Debug Info. Base Address: $00007FFD144A0000. Process cnc_vision_2.exe (14340) Module Load: gdiplus.dll. No Debug Info. Base Address: $00007FFD2B040000. Process cnc_vision_2.exe (14340) Module Load: MSVFW32.dll. No Debug Info. Base Address: $00007FFD1F210000. Process cnc_vision_2.exe (14340) Module Load: DDRAW.dll. No Debug Info. Base Address: $00007FFCFC5D0000. Process cnc_vision_2.exe (14340) Module Load: DCIMAN32.dll. No Debug Info. Base Address: $00007FFD238F0000. Process cnc_vision_2.exe (14340) Module Load: nvldumdx.dll. No Debug Info. Base Address: $00007FFD2ADB0000. Process cnc_vision_2.exe (14340) Module Load: imagehlp.dll. No Debug Info. Base Address: $00007FFD35670000. Process cnc_vision_2.exe (14340) Module Load: CRYPTSP.dll. No Debug Info. Base Address: $00007FFD34280000. Process cnc_vision_2.exe (14340) Module Load: RSAENH.dll. No Debug Info. Base Address: $00007FFD339A0000. Process cnc_vision_2.exe (14340) Module Load: NVD3DUMX.dll. No Debug Info. Base Address: $00007FFCC5A50000. Process cnc_vision_2.exe (14340) Module Load: nvspcap64.dll. No Debug Info. Base Address: $00007FFD09D00000. Process cnc_vision_2.exe (14340) Module Load: profapi.dll. No Debug Info. Base Address: $00007FFD34810000. Process cnc_vision_2.exe (14340) Module Load: NvCameraWhitelisting64.dll. No Debug Info. Base Address: $00007FFD14410000. Process cnc_vision_2.exe (14340) Module Unload: NvCameraWhitelisting64.dll. Process cnc_vision_2.exe (14340) Module Load: dxcore.dll. No Debug Info. Base Address: $00007FFD2B680000. Process cnc_vision_2.exe (14340) Module Unload: NVD3DUMX.dll. Process cnc_vision_2.exe (14340) Module Unload: nvldumdx.dll. Process cnc_vision_2.exe (14340) Module Load: nvldumdx.dll. No Debug Info. Base Address: $00007FFD2ADB0000. Process cnc_vision_2.exe (14340) Module Load: NVD3DUMX.dll. No Debug Info. Base Address: $00007FFCC5A50000. Process cnc_vision_2.exe (14340) Module Load: NvCameraWhitelisting64.dll. No Debug Info. Base Address: $00007FFD14410000. Process cnc_vision_2.exe (14340) Module Unload: NvCameraWhitelisting64.dll. Process cnc_vision_2.exe (14340) Module Unload: NVD3DUMX.dll. Process cnc_vision_2.exe (14340) Module Unload: nvldumdx.dll. Process cnc_vision_2.exe (14340) Module Load: nvldumdx.dll. No Debug Info. Base Address: $00007FFD2ADB0000. Process cnc_vision_2.exe (14340) Module Load: NVD3DUMX.dll. No Debug Info. Base Address: $00007FFCC5A50000. Process cnc_vision_2.exe (14340) Module Load: NvCameraWhitelisting64.dll. No Debug Info. Base Address: $00007FFD14410000. Process cnc_vision_2.exe (14340) Module Unload: NvCameraWhitelisting64.dll. Process cnc_vision_2.exe (14340) Module Unload: NVD3DUMX.dll. Process cnc_vision_2.exe (14340) Module Unload: nvldumdx.dll. Process cnc_vision_2.exe (14340) Module Load: WINMMBASE.dll. No Debug Info. Base Address: $00007FFD22CE0000. Process cnc_vision_2.exe (14340) Module Load: MSYUV.dll. No Debug Info. Base Address: $00007FFD238E0000. Process cnc_vision_2.exe (14340) Module Unload: MSYUV.dll. Process cnc_vision_2.exe (14340) Module Load: TextInputFramework.dll. No Debug Info. Base Address: $00007FFD2B430000. Process cnc_vision_2.exe (14340) Module Load: CoreUIComponents.dll. No Debug Info. Base Address: $00007FFD31640000. Process cnc_vision_2.exe (14340) Module Load: CoreMessaging.dll. No Debug Info. Base Address: $00007FFD319A0000. Process cnc_vision_2.exe (14340) Module Load: WinTypes.dll. No Debug Info. Base Address: $0000000007A20000. Process cnc_vision_2.exe (14340) Module Load: WinTypes.dll. No Debug Info. Base Address: $0000000007B80000. Process cnc_vision_2.exe (14340) Module Unload: WinTypes.dll. Process cnc_vision_2.exe (14340) Module Unload: WinTypes.dll. Process cnc_vision_2.exe (14340) Module Load: WinTypes.dll. No Debug Info. Base Address: $00007FFD30ED0000. Process cnc_vision_2.exe (14340) Module Load: OLEACC.dll. No Debug Info. Base Address: $00007FFD2AF20000. Process cnc_vision_2.exe (14340)
Γ—