As I was playing with QR codes (see previous post on scanning QR codes with CoreImage), I figured out how to use the VisionKit to rapidly detect pretty much any barcode, QR codes included.
Since it took me a while to figure things out, I thought I'd share it here in the hoped it is helpful for someone. At least it is a good reference for myself 😊
This is a super small project that detects multiple barcodes and QR codes very fast.
The form is simple: a TButton, a TImage, a TMemo and a TOpenDialog.
It allows you to select a picture file (for example a JPG or PNG) and uses VisionKit to detect the barcodes.
The found results will be listed in the TMemo.
Notes:
- this may require macOS 13 (VisionKit)
- you may need to set the compiler option "-WM11.0" or even "-WM13.0"
- in my example image it detected 9 out of 12 barcodes, not sure if 9 is the max it can detect in one image or if the missing 3 formats are not supported.
unit Unit1;
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$modeswitch objectivec2}
{$modeswitch cvar}
{$modeswitch cblocks}
{$packrecords c}
{$linkframework vision}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls
, CocoaAll, CocoaUtils;
type
{ TForm1 }
TForm1 = class(TForm)
btnDetectBarcode: TButton;
Image1: TImage;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
procedure btnDetectBarcodeClick(Sender: TObject);
private
public
end;
type
VNRequest = objcclass external (NSObject)
end;
VNDetectBarcodesRequest = objcclass external (VNRequest)
function init: id; message 'init';
function results: NSArray; message 'results';
end;
VNBarcodeObservation = objcclass external (NSObject)
function payloadStringValue: NSString; message 'payloadStringValue';
end;
VNImageRequestHandler = objcclass external (NSObject)
function initWithURL(url: NSURL; options: NSDictionary): id; message 'initWithURL:options:';
function performRequests(requests: NSArray; error: NSErrorPtr): boolean; message 'performRequests:error:';
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.btnDetectBarcodeClick(Sender: TObject);
var
ImagePath: NSString;
ImageURL: NSURL;
Request: VNDetectBarcodesRequest;
Handler: VNImageRequestHandler;
RequestArray: NSArray;
Error: NSError;
Results: NSArray;
Barcode: VNBarcodeObservation;
i: Integer;
Filename: string;
begin
if OpenDialog1.Execute then
begin
Filename := OpenDialog1.FileName;
Image1.Picture.LoadFromFile(Filename);
ImageURL := NSURL.fileURLWithPath(NSSTR(Filename));
ImagePath := NSSTR(Filename);
ImageURL := NSURL.fileURLWithPath(ImagePath);
Request := VNDetectBarcodesRequest.alloc.init;
RequestArray := NSArray.arrayWithObject(Request);
Handler := VNImageRequestHandler.alloc.initWithURL(ImageURL, nil);
if Handler.performRequests(RequestArray, @Error) then
begin
Results := Request.results;
Memo1.Clear;
for i := 0 to Results.count - 1 do
begin
Barcode := VNBarcodeObservation(Results.objectAtIndex(i));
Memo1.Append('Barcode: '+NSStringToString(Barcode.payloadStringValue));
end;
end
else
memo1.Append('Vision request failed: '+NSStringToString(Error.localizedDescription));
end;
end;
end.
As you can see I did a minimal interface definition to VisionKit as the SDK headers for Lazarus/MacOS are very outdated and do not include VisonKit (yet).
This topic was modified 3 weeks ago by
Hans