Does anyone have experience using OpenCV in Lazarus? lazarus / 39-Graphics ---------------------------------------------------------------------- xiyi0616 · 2025-07-15 07:52 I'm using Lazarus 3.9 on Ubuntu 22.04.5 LTS. I installed OpenCV version 4.5.4 using apt-get install libopencv-dev. The code is as simple as: unit OpenCVDisplayMain; interface uses   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, LCLType,   ctypes, LCLIntf, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)     Image1: TImage;     procedure FormCreate(Sender: TObject);   private     { private declarations }   public     { public declarations }   end;   TSize = record     width, height: Integer;   end;   PSize = ^TSize; var   Form1: TForm1; implementation {$R *.lfm} function cv_imread(filename: PAnsiChar; flags: Integer): Pointer; cdecl; external 'libopencv_imgcodecs.so.4.5.4d'; function cv_GetSize(img: Pointer): PSize; cdecl; external 'libopencv_core.so.4.5'; procedure cv_releaseImage(img: PPointer); cdecl; external 'libopencv_core.so.4.5'; / function cvCvtColor(src, dst: Pointer; code: Integer): Integer; cdecl; external 'libopencv_imgproc.so.4.5'; function cvCreateImage(size: PSize; depth: Integer; channels: Integer): Pointer; cdecl; external 'libopencv_core.so.4.5'; { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var   OpenCVImage, ConvertedImage: Pointer;   Size: PSize;   Filename: string;   OpenCVImagePtr: PPointer;   Bitmap: TBitmap; begin   Filename := 'test.jpg';   OpenCVImage := cv_imread(PAnsiChar(AnsiString(Filename)), 1);   if OpenCVImage <> nil then   begin     Size := cv_GetSize(OpenCVImage);     ConvertedImage := cvCreateImage(Size, 8, 3); // 8 bits per channel, 3 channels (BGR)     cvCvtColor(OpenCVImage, ConvertedImage, 6); // COLOR_BGR2BGR = 6     Bitmap := TBitmap.Create;     try       Bitmap.PixelFormat := pf24bit;       Bitmap.Width := Size^.width;       Bitmap.Height := Size^.height;       Move(Pointer(ConvertedImage)^, Bitmap.ScanLine[0]^, Bitmap.Width * Bitmap.Height * 3);       Image1.Picture.Assign(Bitmap);     finally       Bitmap.Free;     end;     OpenCVImagePtr := @OpenCVImage;     cv_releaseImage(OpenCVImagePtr);     OpenCVImagePtr := @ConvertedImage;     cv_releaseImage(OpenCVImagePtr);   end else     ShowMessage('Failed to load image: ' + Filename); end; end. However, I keep getting the following compile-time error: Error: openc vdisplaymain.pas:(.text.n_opencvdisplaymain$_$tform1_$__$$_formcreate$ tobject+0x7e): undefined reference to \cv_imread'`. I've already tried asking AI for help, but haven't been able to resolve the issue. Does anyone have experience with this? 『 ls /usr/lib/x86_64-linux-gnu/ | grep libopencv_imgcodecs libopencv_imgcodecs.a libopencv_imgcodecs.so libopencv_imgcodecs.so.4.5.4d libopencv_imgcodecs.so.4.5d 』 ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-15 12:23 Hey xiyi0616, Not trying to answer your question, just providing a better display of your code. It's better on the eyes and will probably capture the attention of more people, Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit OpenCVDisplayMain; interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, LCLType,  ctypes, LCLIntf, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)    Image1: TImage;    procedure FormCreate(Sender: TObject);  private    { private declarations }  public    { public declarations }  end;   TSize = record    width, height: Integer;  end;  PSize = ^TSize; var  Form1: TForm1; implementation {$R *.lfm} function cv_imread(filename: PAnsiChar; flags: Integer): Pointer; cdecl; external 'libopencv_imgcodecs.so.4.5.4d';function cv_GetSize(img: Pointer): PSize; cdecl; external 'libopencv_core.so.4.5';procedure cv_releaseImage(img: PPointer); cdecl; external 'libopencv_core.so.4.5'; /function cvCvtColor(src, dst: Pointer; code: Integer): Integer; cdecl; external 'libopencv_imgproc.so.4.5';function cvCreateImage(size: PSize; depth: Integer; channels: Integer): Pointer; cdecl; external 'libopencv_core.so.4.5';  { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var  OpenCVImage, ConvertedImage: Pointer;  Size: PSize;  Filename: string;  OpenCVImagePtr: PPointer;  Bitmap: TBitmap;begin  Filename := 'test.jpg';   OpenCVImage := cv_imread(PAnsiChar(AnsiString(Filename)), 1);   if OpenCVImage <> nil then  begin    Size := cv_GetSize(OpenCVImage);     ConvertedImage := cvCreateImage(Size, 8, 3); // 8 bits per channel, 3 channels (BGR)   cvCvtColor(OpenCVImage, ConvertedImage, 6); // COLOR_BGR2BGR = 6     Bitmap := TBitmap.Create;    try      Bitmap.PixelFormat := pf24bit;    Bitmap.Width := Size^.width;      Bitmap.Height := Size^.height;     Move(Pointer(ConvertedImage)^, Bitmap.ScanLine[0]^, Bitmap.Width * Bitmap.Height * 3);       Image1.Picture.Assign(Bitmap);     finally    Bitmap.Free;    end;     OpenCVImagePtr := @OpenCVImage;    cv_releaseImage(OpenCVImagePtr);     OpenCVImagePtr := @ConvertedImage;    cv_releaseImage(OpenCVImagePtr);   end else    ShowMessage('Failed to load image: ' + Filename);end; end. Cheers, Gus ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-15 12:41 Hey xiyi0616, Now that I had a look at your code, can I suggest that you use: libopencv_core.so instead of libopencv_core.so.4.5libopencv_imgcodecs.so instead of libopencv_imgcodecs.so.4.5.4dlibopencv_imgproc.so instead of libopencv_imgproc.so.4.5 Usually the .so is a symlink to the correct versioned file. Please confirm what it points at. It's also future proof that you use the .so, since after future updates of the package, it will point to the correct versioned one. From the little that I could perceive from the error, it looks like you're linking to the incorrect library and you're trying to use definitions that don't exist in the lib that you're linking to. Maybe using the .so instead of the versioned one might solve the issue. If not, please confirm that the functions that you need are exported. You can use objdump, readelf or nm to confirm that: Example on using objdump, readelf: https://www.baeldung.com/linux/shared-library-exported- functionsExample on using nm: https://stackoverflow.com/questions/4514745/how-do-i-view-the-list-of- functions-a-linux-shared-library-is-exporting Give it a try and then report back please. Cheers, Gus ---------------------------------------------------------------------- gidesa · 2025-07-15 12:52 Hello, you are using the C API of Opencv, it's abandoned and deprecated from Opencv version 2.4, although retained until now. And it expose only a fraction of Opencv functions/classes (it's written in C++). You can use ocvWrapper46 for Opencv version 4.6, that exposes all C++ classes. For FPC and Delphi, on Windows, Linux, Macos. https://github.com/gidesa/ocvWrapper46 ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-15 13:02 Hey Gidesa, Quote from: gidesa on July 15, 2025, 02:52:41 pmyou are using the C API of Opencv, it's abandoned and deprecated from Opencv version 2.4, although retained until now. And it expose only a fraction of Opencv functions/classes (it's written in C++). You can use ocvWrapper46 for Opencv version 4.6, that exposes all C++ classes. For FPC and Delphi, on Windows, Linux, Macos. https://github.com/gidesa/ocvWrapper46 This is valuable information indeed!!! Thanks for that!! EDIT And thanks for the monumental effort in producing the C wrapper and the Object Pascal ones !!! I'm gonna guess that if he used the tools to search for the functions, they would not return what he expected !! Cheers, Gus ---------------------------------------------------------------------- gidesa · 2025-07-15 13:26 Using ocvWrapper46, the code is as simple as this: (Note that Opencv 4.6 is required, so first you have to remove Opencv 4.5, and then install Opencv 4.6 and ocvWrapper 46 using the instructions for Linux) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit frmtxocvimage; {$mode Delphi}{$H+}interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,  unOCVImage; type   { TForm1 }   TForm1 = class(TForm)    btStart: TButton;    Image1: TImage;    procedure btStartClick(Sender: TObject);  private   public   end;  var  Form1: TForm1; implementation {$R *.lfm} procedure testOcvImage();var  ocvimg: TOCVImage;  filename: string;begin  filename:='xxx.jpg';  ocvimg:=TOCVImage.Create(filename);  ocvimg.showInImage(form1.image1);   ocvimg.Free; end;  { TForm1 } procedure TForm1.btStartClick(Sender: TObject);begin  testOcvImage();end; end. ---------------------------------------------------------------------- xiyi0616 · 2025-07-15 14:31 Hey, Gustavo 'Gus' Carreno First, thank you for your suggestion regarding the code demonstration. It seems you're right, and I'm not very proficient in that area. The reason I need to use OpenCV is that the current version of Lazarus's built-in controls are not good at decoding Tiff Group 4 format. Additionally, I need to analyze lines in images. I'm not very familiar with unOCVImage, and I'm unsure if it can perform these functions, but I will give it a try. Thank you for your advice. ---------------------------------------------------------------------- xiyi0616 · 2025-07-15 14:34 Hello gidesa, thank you for your suggestion,  I will give it a try. ---------------------------------------------------------------------- xiyi0616 · 2025-07-15 14:40 Also, I initially used libopencv_core.so, and then, based on AI's suggestion, I tried libopencv_core.so.4.5. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-15 15:06 Hey xiyi0616, Quote from: xiyi0616 on July 15, 2025, 04:31:49 pmHey, Gustavo 'Gus' Carreno Please just call me Gus Quote from: xiyi0616 on July 15, 2025, 04:31:49 pmFirst, thank you for your suggestion regarding the code demonstration. It seems you're right, and I'm not very proficient in that area. The reason I need to use OpenCV is that the current version of Lazarus's built-in controls are not good at decoding Tiff Group 4 format. Additionally, I need to analyze lines in images. I'm not very familiar with unOCVImage, and I'm unsure if it can perform these functions, but I will give it a try. Thank you for your advice. Welp, in the end, it looks like @gidesa is the REAL expert in this, so it's awesome he dropped his pearls of wisdom!! Cheers, Gus ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-15 15:10 Hey xiyi0616, Quote from: xiyi0616 on July 15, 2025, 04:40:57 pmAlso, I initially used libopencv_core.so, and then, based on AI's suggestion, I tried libopencv_core.so.4.5. Yeah... The bots sometimes have some hallucinations Like I said: The .so is usually a symlink to the versioned file. So best use that, cuz if and when you upgrade your package from the repo, there could be a new versioned file and then your program won't work. But now, with @gidesa's wrapper, you don't have to care about any of that, as long as you update the wrapper from @gidesa's repo !! All the luck in your project!! Cheers, Gus ---------------------------------------------------------------------- gidesa · 2025-07-15 15:38 Hello xiyi0616, here a code adapted for your task, reading a TIFF image. For display, there is a conversion from BGRA format (4 channels) to the 3 channels format required by TImage. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit frmtxocvimage; {$mode Delphi}{$H+}interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,  unOCVImage,  OPENCVWrapper; type   { TForm1 }   TForm1 = class(TForm)    btStart: TButton;    Image1: TImage;    procedure btStartClick(Sender: TObject);  private   public   end;  var  Form1: TForm1; implementation {$R *.lfm}  procedure testOcvImage();var  ocvimg: TOCVImage;  ocvimg2: TOCVImage;  filename: string;begin  filename:='..\..\Sample-Tiff-File.tif';  ocvimg:=TOCVImage.Create(filename);  if ocvimg.nchannels>3 then  begin       ocvimg2:=TOCVImage.Create(ocvimg.width, ocvimg.height, 3);       pCvcvtColor(ocvimg.PCvMatPtr, ocvimg2.PCvMatPtr, ord(COLOR_BGRA2BGR));  end else      ocvimg2:= ocvimg.clone();  ocvimg2.showInImage(form1.image1);   ocvimg2.Free;  ocvimg.Free;end;  { TForm1 } procedure TForm1.btStartClick(Sender: TObject);begin  testOcvImage();end; end. ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 01:05 Okay, Gus. With Lazarus's version upgrades, it feels better and better to use. I'm happy to see this trend. Cheers, xiyi0616 ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 01:18 Hello gidesa Thank you for your time. I believe unOCVImage is not included in the standard Lazarus installation. I will need to research, install, and familiarize myself with it. In the meantime, I'm temporarily using libtiff for reading images., which seems to be working. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        LibHandle := LoadLibrary('libtiff.so');        if LibHandle = NilHandle then          raise Exception.Create('Failed to load libtiff');        Pointer(TIFFOpen) := GetProcAddress(LibHandle, 'TIFFOpen');       Pointer(TIFFClose) := GetProcAddress(LibHandle, 'TIFFClose');       Pointer(TIFFGetField) := GetProcAddress(LibHandle, 'TIFFGetField');  Cheers, xiyi0616 ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-16 01:23 Hey Y'All, Ermmm, isn't TIFF one of the image formats supported natively by Lazarus?! I was under the impression it was, but again, most of the times my assumptions end with me inserting foot in mouth... So... dunno... Cheers, Gus ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-16 01:32 Hey Y'All, Was not inserting foot in mouth: https://wiki.freepascal.org/fcl-image Package fcl-image gives you TIFF... Not sure if 100% supported, cuz there's a section dedicated to https://wiki.freepascal.org/fcl-image that I did not fully read... But the table does list the units to use for https://wiki.freepascal.org/fcl-image... So, yeah... There's that Cheers, Gus ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 01:38 Hey Gus If you have time, you could try it out. I've attached the TIFF file. [Why aren't attachments directly supported, specifically TIFF files? ] Cheers xiyi0616 ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 01:58 Hey Gus Okay, I see that fcl-image has TIFF handling capabilities, I'll give it a try. Cheers, xiyi0616 ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2025-07-16 02:05 Hey xiyi0616, Quote from: xiyi0616 on July 16, 2025, 03:58:05 amOkay, I see that fcl-image has TIFF handling capabilities, I'll give it a try. AWESOME SAUCE!! Go for it!! Cheers, Gus ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 02:38 Hey Y'All I used the example from https://wiki.freepascal.org/fcl-image, but it seems to have a problem. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  uses   ...fpImage, fpReadJpeg, fpReadBMP, fpReadPNG, fpReadGIF, fpReadPCX, fpReadTIFF... ...... function GetImageSize(const AFileName: String; out ASize: TPoint): Boolean;var  stream: TStream;  readerClass: TFPCustomImageReaderClass;begin  Result := false;  ASize := Point(-1, -1);  stream := TFileStream.Create(AFileName, fmOpenRead);  try    readerClass := TFPCustomImage.FindReaderFromStream(stream);    if readerClass <> nil then    begin      ASize := readerClass.ImageSize(stream);      Result := true;    end;  finally  stream.Free;  end;end;   ...... procedure TForm1.BitBtn2Click(Sender: TObject);var   asv: TPoint;begin  if GetImageSize('/media/xiy0616/Data /xyLazarusPrj/Test/DisplayPicture/000001.tif', asv) then    Memo1.Lines.Add(IntToStr(asv.X) + ',' + IntToStr(asv.Y));end; ......   I get -1, -1 in memo1. It shouldn't be returning -1, should it? Does anyone have experience using TIFFs with fcl-image? ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 06:57 Okay, I'm a bit slow. https://github.com/gidesa/ocvWrapper46 @gidesa thanks for replay from gidesa cheers xiyi0616 ---------------------------------------------------------------------- gidesa · 2025-07-16 10:03 Quote from: xiyi0616 on July 16, 2025, 04:38:35 amDoes anyone have experience using TIFFs with fcl-image? I you want to use fcl-image, instead that Opencv (with or without the wrapper), I suggest you to open a new thread. Regards ---------------------------------------------------------------------- wp · 2025-07-16 12:32 Quote from: xiyi0616 on July 16, 2025, 04:38:35 amHey Y'All I used the example from https://wiki.freepascal.org/fcl-image, but it seems to have a problem. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  uses   ...fpImage, fpReadJpeg, fpReadBMP, fpReadPNG, fpReadGIF, fpReadPCX, fpReadTIFF... ...... function GetImageSize(const AFileName: String; out ASize: TPoint): Boolean;var  stream: TStream;  readerClass: TFPCustomImageReaderClass;begin  Result := false;  ASize := Point(-1, -1);  stream := TFileStream.Create(AFileName, fmOpenRead);  try    readerClass := TFPCustomImage.FindReaderFromStream(stream);    if readerClass <> nil then    begin      ASize := readerClass.ImageSize(stream);      Result := true;    end;  finally  stream.Free;  end;end;   ...... procedure TForm1.BitBtn2Click(Sender: TObject);var   asv: TPoint;begin  if GetImageSize('/media/xiy0616/Data /xyLazarusPrj/Test/DisplayPicture/000001.tif', asv) then    Memo1.Lines.Add(IntToStr(asv.X) + ',' + IntToStr(asv.Y));end; ......   I get -1, -1 in memo1. It shouldn't be returning -1, should it? Does anyone have experience using TIFFs with fcl-image? The problem in this particular issue is that fcl-image does not implement the required class method InternalSize for every reader class. This was added to the bmp and gif readers of FPC 3.3.1, but for the tiff reader it is still missing (maybe because a tif image can contain several images at various sizes, and there is no way to tell which image should be analyzed). But nothing's lost: Use subclassing to override the readers and implement the missing method. Give the new classes the same name as the originals, unregister the old readers and register the new ones. Put everything into a separate unit so that you can reuse the solution. The only thing to remember is to put this unit at the end of the uses clause (at least after the fcl readers). I am attaching such a "fix" unit for the bmp, gif and tiff format (tiff only looking at the 1st image in the file), as well as a little demo application. If you happen to use fpc3.3.1 I noticed that probably some bugs were introduced when the code was extended for the BigTIFF specification; it seems to me that reading of big-endian tif images ('MM' in header) is broken. But I'll have to investigate it in more detail. ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 13:32 Hello, wp Thank you for you time. I will use your examples to learn and understand fcl-image. Tks. Regards xiyi0616 ---------------------------------------------------------------------- xiyi0616 · 2025-07-16 13:47 Yes, gidesa Absolutely new thread. Next, I'm going to learn how to use ocvWrapper as a beginner, just like you mentioned earlier that the other library, lazarusOpenCV, stopped at version 2.4. Thank you very much. Regards xiyi0616 ---------------------------------------------------------------------- marcov · 2025-07-16 14:07 Note also that not all TIFF subtypes  are supported, most notably https://gitlab.com/freepascal.org/fpc/source/-/issues/21871 Another, less relevant TIFF bugreport: https://gitlab.com/freepascal.org/fpc/source/-/issues/41032 ---------------------------------------------------------------------- xiyi0616 · 2025-07-17 00:31 Hello, marcov Thks for Note xiyi0616 ---------------------------------------------------------------------- marcov · 2025-07-17 09:05 000001.tif: TIFF image data, little-endian, direntries=16, height=2400, bps=1, compression=bi-level group 4, PhotometricIntepretation=WhiteIsZero, orientation=upper-left, width=1600 ---------------------------------------------------------------------- xiyi0616 · 2025-07-17 11:51 Yes marcov LibTiff ? Cheers, xiyi0616 ---------------------------------------------------------------------- marcov · 2025-07-17 11:58 Maybe, I have no experience. I never used TIFF much after the FAX era. I happen to know about the unsupported format because of the bugreport. ---------------------------------------------------------------------- xiyi0616 · 2025-07-17 12:05 Group 4 TIFF images don't seem to be supported by the current Lazarus standard libraries and controls. ---------------------------------------------------------------------- gues1 · 2025-07-17 12:09 If you run under Windows, you can use the WICImage (aka Microsoft Windows Imaging Component). It  supports BMP, GIF, ICO, JPEG, PNG, TIFF, and Windows Media Photo. I used it for a long time (still use somtimes) untill I switched to professional imaging libraries. In Delphi is incapsultaed under TWICImage class (Graphics unit), in Lazarus I don't know but I think should be. I use only tiff files for analisys and I never had any issues with it. ---------------------------------------------------------------------- xiyi0616 · 2025-07-17 12:15 Thank you , gues1 Unfortunately, my target environment is Linux, although I can use Windows for development.  cheers, xiyi0616 ---------------------------------------------------------------------- gues1 · 2025-07-17 12:31 Many years ago I used Vampyre library, now here: https://imaginglib.sourceforge.io/index.php?page=down , hope it is the same, and it is compatible with FPC (with source). It worked with tiff. ---------------------------------------------------------------------- xiyi0616 · 2025-07-17 12:54 Thanks again gues1, I will try it.  I think this is useful; for solving a single objective problem, this should be quite concise. xiyi0616. ---------------------------------------------------------------------- xiyi0616 · 2025-07-18 09:35 Hey, gues1  The library from [https://imaginglib.sourceforge.io/index.php?page=down] can decode Tiff Group 4 file. And it's very convenient; for a Linux environment, there's no need to install extra libraries. xiyi0616 ---------------------------------------------------------------------- gues1 · 2025-07-18 13:50 Quote from: xiyi0616 on July 18, 2025, 11:35:27 amHey, gues1  The library from [https://imaginglib.sourceforge.io/index.php?page=down] can decode Tiff Group 4 file. And it's very convenient; for a Linux environment, there's no need to install extra libraries. xiyi0616 I'm very glad I could help you.