WikiFilters
Advertisement

How to create a Filters plugin in Delphi[]

To see how to create a FiltersPlugin, we will create a new one ! This new Plugin will be very basic : it adds noise on a input image.



1 - Create a new Delphi project :

    a/ choose the type 'DLL'
    b/ save it with the name 'FiltersPlugin_Noise.dpr'


2 - Copy and add this files in your project :

    FiltersTutorial/FiltersPlugin_/Delphi/dllInterface.pas
    FiltersTutorial/FiltersPlugin_/Delphi/main.pas
    FiltersTutorial/FiltersPlugin_/Delphi/image.pas

(all this files are not necessary to create a FilterPlugin, but it can help a lot !)



3 - In the project source (the unit with 'library' at the top', add this lines : After "{$R *.res}"

 exports
   getVersion,
   createFilter, deleteFilter,
   run, runCommand,
   getParametersCount, getParameterName, getParameterHelp,
   setParameterInteger, setParameterFloat,
   setParameterBoolean, setParameterString,
   setParameterImage, setParameterPointer,
   setParameterImagesCount, setParameterImagesImageAtIndex,
   getOutputsCount, getOutputName,
   getOutputImage, getOutputImagesCount, getOutputImagesImageAtIndex,
   getOutputInteger, getOutputFloat,
   getOutputArrayPointersCount, getOutputArrayPointersPointerAtIndex,
   setRegionOfInterest, unsetRegionOfInterest;
    ->It is the only functions exported by our DLL


4 - Change the project options to set the destination directory to the location of Filters

    ->Example : set the destination path to 'C:\FiltersTutorial\Bin' 


5 - Build the project

    ->Actually the new Plugin do nothing, but we can already test it in a Delphi project !
      (for a final example, you can have a look on the project 'testplugin')


6 - Now we will add 2 parameters of our plugin :

    The parameter 'inImage' : the input image
    The parameter 'outImage' : the image where we have to draw the result
    ->it's always a good practice to provide output images as parameters 
        (of course, when the size of output images can't be known, the filter must create it and provide it as a 'Output')
    a/ Well, in the unit 'main.pas', add this protected variable :

...

 protected
   _inImageParameter : PBitmap32;
   _outImageParameter : PBitmap32;

...

    b/ Set it to nil in the constructor :

... constructor TFiltersPlugin.Create; begin

 _inImageParameter := nil;
 _outImageParameter := nil;
 unsetRegionOfInterest();

end; ...

    c/ Our Plugin has to declare this 2 parameters:

... function TFiltersPlugin.getParametersCount() : Integer; begin

 Result := 2;

end;

procedure TFiltersPlugin.getParameterName( const aIndex : Integer; var aName : String ); begin

 case aIndex of
 0 : aName := 'inImage';
 1 : aName := 'outImage';
 end;

end;

procedure TFiltersPlugin.getParameterHelp( const aIndex : Integer; var aHelp : String ); begin

 case aIndex of
 0 : aHelp := 'the input image';
 1 : aHelp := 'the output image (must be of the same size than [inImage])';
 end;

end;

procedure TFiltersPlugin.setParameterImage( const aName : String; const aImage : PFBitmap32 ); begin

 if aName='inImage' then _inImageParameter := aImage
 else if aName='outImage' then _outImageParameter := aImage;

end; ...



7 - Now we do the real job of our plugin : add noise ! ... // It's a scholar example, and not a good and fast method ! procedure TFiltersPlugin.run(); var

 x, xMin, xMax, y, yMin, yMax : Integer;
 pDest : PColor32Array;
 roi : TFRect;
 r : Integer;

begin

 // if we have input images
 if (_inImageParameter<>nil) and (_outImageParameter<>nil) then begin
   // both input images must be of the same size
   if image.isSameSize( _inImageParameter, _outImageParameter )=True then begin
     // we start by copy the [inImage] to [outImage]
     image.copyImageToImage( _inImageParameter, _outImageParameter );
     // we get the ROI (if ROI=(-1,-1)(-1,-1), then getValidROI return the full image)
     roi := image.getValidROI( _inImageParameter, _roi );
     // for each pixel in the ROI
     xMin := Round( roi.Left );
     xMax := Round( roi.Right );
     yMin := Round( roi.Top );
     yMax := Round( roi.Bottom );
     pDest := _outImageParameter.Bits;
     for y:=yMin to yMax do begin
       for x:=xMin to xMax do begin
         // sometime we add salt and pepper noise
         r := Random(2*100);
         if r=0 then begin
           pDest^[0] := clBlack32;
         end else if r=1 then begin
           pDest^[0] := clWhite32;
         end;
         Inc( pDest );
       end;
     end;
   end;
 end;

end; ...



8 - We can add a parameter to add more or less noise.

    a/ We add the parameter 'scale'

...

 protected
   _scale : Integer;

...

    b/ Set it to a default value in the constructor :

... constructor TFiltersPlugin.Create; begin

 _inImageParameter := nil;
 _outImageParameter := nil;
 _scale := 100;
 unsetRegionOfInterest();

end; ...

    c/ Our Plugin has now to declare 3 parameters:

... function TFiltersPlugin.getParametersCount() : Integer; begin

 Result := 3;

end;

procedure TFiltersPlugin.getParameterName( const aIndex : Integer; var aName : String ); begin

 case aIndex of
 0 : aName := 'inImage';
 1 : aName := 'outImage';
 2 : aName := 'scale';
 end;

end;

procedure TFiltersPlugin.getParameterHelp( const aIndex : Integer; var aHelp : String ); begin

 case aIndex of
 0 : aHelp := 'the input image';
 1 : aHelp := 'the output image (must be of the same size than [inImage])';
 2 : aHelp := 'if scale=100, then for each pixel, there is 1/scale chance to have noise';
 end;

end;

procedure TFiltersPlugin.setParameterInteger( const aName : String; const aValue : Int64 ); begin

 if aName='scale' then _scale := aValue;

end; ...

    d/ And we use it in our process

... procedure TFiltersPlugin.run();

 ...
         r := Random(2*_scale);
 ...

end; ...



by edurand ->for any question : filters@edurand.com

the final code[]

unit main;

interface
uses
  image;

type
  TFiltersPlugin = class(TObject)
  protected
    _inImageParameter : PBitmap32;
    _outImageParameter : PBitmap32;
    _scale : Integer;
    // Region Of Interest
    _roi : TFRect;
  public
    constructor Create;
    destructor Destroy;

    procedure run();
    procedure runCommand( const aCommand : String);

    function getParametersCount() : Integer;
    procedure getParameterName( const aIndex : Integer; var aName : String );
    procedure getParameterHelp( const aIndex : Integer; var aHelp : String );
    procedure setParameterBoolean( const aName : String;  const aValue : Boolean );
    procedure setParameterInteger( const aName : String; const aValue : Int64 );
    procedure setParameterFloat( const aName : String; const aValue : Single );
    procedure setParameterString( const aName : String; const aValue : String );
    procedure setParameterImage( const aName : String; const aImage : PBitmap32 );
    procedure setParameterImagesCount( const aName : String; const aCount : Integer );
    procedure setParameterImagesImageAtIndex( const aName : String; const aImage : PBitmap32; const aIndex : Integer );
    procedure setParameterPointer( const aName : String; const aPointer : Pointer );

    function getOutputsCount() :  Integer;
    procedure getOutputName( const aIndex : Integer; var aName : String );
    function getOutputImage( const aName : String ) : PFBitmap32;
    function getOutputImages( const aName : String ) : PArrayOfPFBitmap32;
    function getOutputInteger( const aName : String ) : Integer;
    function getOutputFloat( const aName : String ) : Single;
    function getOutputArrayPointers( const aName : String ) : PArrayOfPointers;

    procedure setRegionOfInterest( const roi : PFRect );
    procedure unsetRegionOfInterest( );

  end;

var
  FiltersPlugin_Version : String = 'V20061204';


implementation
uses
  SysUtils, Math;

constructor TFiltersPlugin.Create;
begin
  _inImageParameter := nil;
  _outImageParameter := nil;
  _scale := 100;
  unsetRegionOfInterest();
  Randomize();
end;

destructor TFiltersPlugin.Destroy;
begin
end;

// It's a scholar example, and not a good and fast method !
procedure TFiltersPlugin.run();
var
  x, xMin, xMax, y, yMin, yMax : Integer;
  pDest : PColor32Array;
  roi : TFRect;
  r : Integer;
begin
  // if we have input images
  if (_inImageParameter<>nil) and (_outImageParameter<>nil) then begin
    // both input images must be of the same size
    if image.isSameSize( _inImageParameter, _outImageParameter )=True then begin
      // we start by copy the [inImage] to [outImage]
      image.copyImageToImage( _inImageParameter, _outImageParameter );
      // we get the ROI (if ROI=(-1,-1)(-1,-1), then getValidROI return the full image)
      roi := image.getValidROI( _inImageParameter, _roi );
      // for each pixel in the ROI
      xMin := Round( roi.Left );
      xMax := Round( roi.Right );
      yMin := Round( roi.Top );
      yMax := Round( roi.Bottom );
      pDest := _outImageParameter.Bits;
      for y:=yMin to yMax do begin
        for x:=xMin to xMax do begin
          // sometime we add salt and pepper noise
          r := Random(2*_scale);
          if r=0 then begin
            pDest^[0] := clBlack32;
          end else if r=1 then begin
            pDest^[0] := clWhite32;
          end;
          Inc( pDest );
        end;
      end;
    end;
  end;
end;

procedure TFiltersPlugin.runCommand( const aCommand : String );
begin
  run();
end;

function TFiltersPlugin.getParametersCount() : Integer;
begin
  Result := 2;
end;

procedure TFiltersPlugin.getParameterName( const aIndex : Integer; var aName : String );
begin
  case aIndex of
  0 : aName := 'inImage';
  1 : aName := 'outImage';
  2 : aName := 'scale';
  end;
end;

procedure TFiltersPlugin.getParameterHelp( const aIndex : Integer; var aHelp : String );
begin
  case aIndex of
  0 : aHelp := 'the input image';
  1 : aHelp := 'the output image (must be of the same size than [inImage])';
  2 : aHelp := 'if scale=100, then for each pixel, there is 1/scale chance to have noise';
  end;
end;

procedure TFiltersPlugin.setParameterBoolean( const aName : String;  const aValue : Boolean );
begin
end;

procedure TFiltersPlugin.setParameterInteger( const aName : String; const aValue : Int64 );
begin
  if aName='scale' then _scale := aValue;
end;

procedure TFiltersPlugin.setParameterFloat( const aName : String; const aValue : Single );
begin
end;

procedure TFiltersPlugin.setParameterString( const aName : String; const aValue : String );
begin
end;

procedure TFiltersPlugin.setParameterImage( const aName : String; const aImage : PFBitmap32 );
begin
  if aName='inImage' then _inImageParameter := aImage
  else if aName='outImage' then _outImageParameter := aImage;
end;

procedure TFiltersPlugin.setParameterImagesCount( const aName : String; const aCount : Integer );
begin
end;

procedure TFiltersPlugin.setParameterImagesImageAtIndex( const aName : String; const aImage : PBitmap32; const aIndex : Integer );
begin
end;

procedure TFiltersPlugin.setParameterPointer( const aName : String; const aPointer : Pointer );
begin
end;

function TFiltersPlugin.getOutputsCount() :  Integer;
begin
  Result := 0;
end;

procedure TFiltersPlugin.getOutputName( const aIndex : Integer; var aName : String );
begin
end;

function TFiltersPlugin.getOutputImage( const aName : String ) : PFBitmap32;
begin
end;

function TFiltersPlugin.getOutputImages( const aName : String ) : PArrayOfPFBitmap32;
begin
end;

function TFiltersPlugin.getOutputInteger( const aName : String ) : Integer;
begin
end;

function TFiltersPlugin.getOutputFloat( const aName : String ) : Single;
begin
end;

function TFiltersPlugin.getOutputArrayPointers( const aName : String ) : PArrayOfPointers;
begin
end;

procedure TFiltersPlugin.setRegionOfInterest( const roi : PFRect );
begin
  _roi := roi^;
end;

procedure TFiltersPlugin.unsetRegionOfInterest();
begin
  _roi.Left := -1;
  _roi.Top := -1;
  _roi.Right := -1;
  _roi.Bottom := -1;
end;


end.

See also[]

Advertisement