unit filterBlobGrouping;
(* ***** BEGIN LICENSE BLOCK *****
* Copyright (C) 2004 Durand Emmanuel
* Copyright (C) 2004 Burgel Eric
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact :
* filters@edurand.com
* filters@burgel.com
*
* ***** END LICENSE BLOCK ***** *)
{
edurand (filters@edurand.com)
}
interface
uses
filter, fparameters, image, filterBlobExplorer;
type
TFilterBlobGrouping = class(TFilter)
public
constructor Create; override;
procedure Run(); override;
private
parameterImageIn, parameterImageOut : TParameterImage;
parameterIntensityPrecision : TParameterInteger;
parameterFilterBlobExplorer : TParameterPointer;
_imgIn, _imgOut : PBitmap32;
_imageBlobRealIndex : PBitmap32;
_filterBlobExplorer : TFilter;
_blobCount : Integer;
_blobsPixelCount : array of Integer;
_blobsIntensityMean : array of Integer;
_blobs : ArrayOfPointers;
_blobsGroupIndex : array of Integer;
_groupIntensityMean : array of Integer;
procedure _run();
procedure calculBlobsIntensityMean();
procedure showBlobsIntensityMean();
procedure groupBlobsByColor();
procedure calculGroupIntensityMean();
procedure showBlobsGroup();
end;
implementation
uses
imageIO, Math, SysUtils;
constructor TFilterBlobGrouping.Create;
begin
inherited;
parameterImageIn := addParameterImage('inImage', 'input image to BlobGrouping');
parameterImageOut := addParameterImage('outImage', 'result image of BlobGroupingion');
parameterFilterBlobExplorer := addParameterPointer('filterBlobExplorer','a pointer on the filterBlobExplorer');
parameterIntensityPrecision := addParameterInteger('intensityPrecision','blobs of intensity +-intensityPrecision are of the same group',0,255,5);
end;
procedure TFilterBlobGrouping.Run();
begin
_imgIn := parameterImageIn.Image;
_imgOut := parameterImageOut.Image;
_filterBlobExplorer := TFilter(parameterFilterBlobExplorer.Value);
if (_imgIn<>nil) and (_imgOut<>nil) and (_filterBlobExplorer<>nil) then begin
_imageBlobRealIndex := _filterBlobExplorer.getOutputParameterImage( 'imageBlobIndex' ).Image;
if image.isSameSize( _imageBlobRealIndex, _imgIn )=true then begin
_blobs := ArrayOfPointers(_filterBlobExplorer.getOutputParameterArrayPointers('blobs').Pointers);
_blobCount := Length(_blobs);
image.eraseImage( _imgOut );
_run();
end;
end;
end;
procedure TFilterBlobGrouping._run();
begin
calculBlobsIntensityMean();
//showBlobsIntensityMean();
groupBlobsByColor();
calculGroupIntensityMean();
showBlobsGroup();
end;
procedure TFilterBlobGrouping.calculBlobsIntensityMean();
var
srcImageBlobColor, srcImageBlobIndex : PColor32Array;
p, max : Integer;
pixelColor : TColor32;
pixelIntensity : Integer;
blobIndex : Integer;
begin
SetLength( _blobsIntensityMean, 0 );
SetLength( _blobsIntensityMean, _blobCount );
SetLength( _blobsPixelCount, 0 );
SetLength( _blobsPixelCount, _blobCount );
// calcul blobs mean color
max := _imgIn.Height*_imgIn.Width-1;
srcImageBlobColor := _imgIn.Bits;
srcImageBlobIndex := _imageBlobRealIndex.Bits;
for p:= 0 to max do begin
blobIndex := srcImageBlobIndex^[0];
if (blobIndex>=0) and (blobIndex<_blobCount) then begin
pixelColor := srcImageBlobColor^[0];
pixelIntensity := image.Intensity( pixelColor );
Inc( _blobsIntensityMean[blobIndex], pixelIntensity );
Inc( _blobsPixelCount[blobIndex] );
end;
Inc( srcImageBlobColor );
Inc( srcImageBlobIndex );
end;
for blobIndex:=0 to _blobCount-1 do begin
if _blobsPixelCount[blobIndex]>0 then begin
_blobsIntensityMean[blobIndex] := _blobsIntensityMean[blobIndex] div _blobsPixelCount[blobIndex];
end;
end;
end;
procedure TFilterBlobGrouping.showBlobsIntensityMean();
var
srcImageBlobIndex, dest : PColor32Array;
p, max : Integer;
blobIntensityMean : Integer;
blobIndex : Integer;
begin
// show blob mean color
dest := _imgOut.Bits;
srcImageBlobIndex := _imageBlobRealIndex.Bits;
max := _imgIn.Height*_imgIn.Width-1;
for p:= 0 to max do begin
blobIndex := srcImageBlobIndex^[0];
if (blobIndex>=0) and (blobIndex<_blobCount) then begin
blobIntensityMean := _blobsIntensityMean[blobIndex];
// we set this pixel to the mean color of this blob
dest^[0] := image.Gray32( blobIntensityMean );
end;
Inc( dest );
Inc( srcImageBlobIndex );
end;
end;
procedure TFilterBlobGrouping.groupBlobsByColor;
var
blob1Index, blob2Index, blobCount, b : Integer;
deltaIntensity, deltaIntensityMax : Integer;
groupOfBlob1, groupOfBlob2 : Integer;
lastGroup : Integer;
begin
deltaIntensityMax := parameterIntensityPrecision.Value;
lastGroup := 0;
blobCount := Length(_blobs);
SetLength( _blobsGroupIndex, 0 );
SetLength( _blobsGroupIndex, blobCount );
// we compare all blob with each others
for blob1Index:=0 to blobCount-2 do begin
for blob2Index:=blob1Index+1 to blobCount-1 do begin
deltaIntensity := Abs( _blobsIntensityMean[blob1Index] - _blobsIntensityMean[blob2Index]);
// if 2 blobs have the same intensity (+- a delta)
if deltaIntensity < deltaIntensityMax then begin
// then we group this 2 blobs
// but we have to manage 3 cases for to create this link
groupOfBlob1 := _blobsGroupIndex[blob1Index];
groupOfBlob2 := _blobsGroupIndex[blob2Index];
// case 1 : none of this 2 blobs is part of a group, so we create a new group
if (groupOfBlob1=0) and (groupOfBlob2=0) then begin
Inc( lastGroup );
_blobsGroupIndex[blob1Index] := lastGroup;
_blobsGroupIndex[blob2Index] := lastGroup;
end else
// case 2 : one blob is part of a group, so we set the other blob
if (groupOfBlob1=0) and (groupOfBlob2<>0) then begin
_blobsGroupIndex[blob1Index] := groupOfBlob2;
end else
if (groupOfBlob1<>0) and (groupOfBlob2=0) then begin
_blobsGroupIndex[blob2Index] := groupOfBlob1;
end else
// case 3 : both blobs are part of different group
if (groupOfBlob1<>0) and (groupOfBlob2<>0) and (groupOfBlob1<>groupOfBlob2) then begin
// we create a new group
Inc( lastGroup );
// and link all blobs concerned
for b:=0 to blobCount-1 do begin
if _blobsGroupIndex[b]=groupOfBlob1 then _blobsGroupIndex[b] := lastGroup
else if _blobsGroupIndex[b]=groupOfBlob2 then _blobsGroupIndex[b] := lastGroup;
end;
end;
end;
end;
// if we have not found any other blob like this one, then we create a group for it
if _blobsGroupIndex[blob1Index]=0 then begin
Inc( lastGroup );
_blobsGroupIndex[blob1Index] := lastGroup;
end;
end;
end;
procedure TFilterBlobGrouping.calculGroupIntensityMean;
var
blobCount, b : Integer;
groupIndex, groupIndexMax : Integer;
//groupsBlobCount : array of Integer;
groupsPixelCount : array of Integer;
g, gMax : Integer;
weightOfThisBlob : Single;
groupIntensity : Integer;
begin
blobCount := Length(_blobs);
// calcul number of groups
groupIndexMax := 0;
for b:=0 to blobCount-1 do begin
groupIndex := _blobsGroupIndex[b];
if groupIndex>groupIndexMax then groupIndexMax := groupIndex;
end;
SetLength( _groupIntensityMean, 0 );
SetLength( _groupIntensityMean, groupIndexMax+1 );
//SetLength( groupsBlobCount, groupIndexMax+1 );
SetLength( groupsPixelCount, groupIndexMax+1 );
// the intensity of a group is the weighted mean of intensity of it's blobs
// (weighted by number of pixels of each blobs)
for b:=0 to blobCount-1 do begin
groupIndex := _blobsGroupIndex[b];
Inc( groupsPixelCount[groupIndex], _blobsPixelCount[b] );
end;
for b:=0 to blobCount-1 do begin
groupIndex := _blobsGroupIndex[b];
weightOfThisBlob := _blobsPixelCount[b] / groupsPixelCount[groupIndex];
groupIntensity := Floor( _blobsIntensityMean[b] * weightOfThisBlob );
Inc( _groupIntensityMean[groupIndex], groupIntensity );
end;
end;
procedure TFilterBlobGrouping.showBlobsGroup;
var
srcImageBlobIndex, dest : PColor32Array;
p, max : Integer;
groupIntensityMean : Integer;
blobIndex : Integer;
groupIndex : Integer;
begin
// show group mean color
dest := _imgOut.Bits;
srcImageBlobIndex := _imageBlobRealIndex.Bits;
max := _imgIn.Height*_imgIn.Width-1;
for p:= 0 to max do begin
blobIndex := srcImageBlobIndex^[0];
if (blobIndex>=0) and (blobIndex<_blobCount) then begin
groupIndex := _blobsGroupIndex[blobIndex];
groupIntensityMean := _groupIntensityMean[groupIndex];
// we set this pixel to the mean color of this blob
dest^[0] := image.Gray32( groupIntensityMean );
end;
Inc( dest );
Inc( srcImageBlobIndex );
end;
end;
end.