PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/ICL-Feature-Units/ICLFeatureUnit.pas

http://my-units.googlecode.com/
Pascal | 2842 lines | 2053 code | 730 blank | 59 comment | 276 complexity | c8bb39436d866d0e4dfeb86d188a269c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. unit ICLFeatureUnit;
  2. (*$define _Debug_Matching_Details*)
  3. interface
  4. uses
  5. CollectionUnit, GeometryUnit, {HashUnit,}
  6. ComponentsUnit, SysUtils, MyTypes,
  7. StreamUnit;
  8. const
  9. WeightArrayLen= 11;
  10. CONST_ICL_MIN_COMPONENT_SIZE = 2;
  11. CONST_USE_REGION_LABELS_FOR_DEBUG = False;
  12. type
  13. EInvalidComponent= class (Exception);
  14. TWeightArray= array of Extended;
  15. EInvalidFreemanFeatureRow= class (Exception);
  16. TARowOfFreemanFeature= TLongWordCollection;
  17. TICLMode= (iclUp= 1, iclRight= 2, iclDown= 4,
  18. iclLeft= 8, iclBlackPixInFreeman= 16,
  19. iclHole= 0);
  20. TICLNeighberhoodDirection= (iclnUp= 1);
  21. TICLLabel= Byte;
  22. TICLFeatureComponent= class (TObject)
  23. private
  24. FPercentageOfPointsInComp: Integer;
  25. FPointCollection: TPointCollection;
  26. HashedData: THash;
  27. FCenterOfMass: TPoint;
  28. FICLLabel: TICLLabel;
  29. FID: Integer;
  30. FMinPoint, FMaxPoint: TPoint;
  31. function GetMaxPoint: TPoint;
  32. function GetMinPoint: TPoint;
  33. public
  34. property ID: Integer read FID;
  35. property ICLLabel: TICLLabel read FICLLabel;
  36. property PointsInComponent: TPointCollection read FPointCollection;
  37. property CenterOfMass: TPoint read FCenterOfMass;
  38. property MinPoint: TPoint read GetMinPoint;
  39. property MaxPoint: TPoint read GetMaxPoint;
  40. procedure AddPoint (Point: TPoint); overload;
  41. procedure AddPoint (r, c: Integer); overload;
  42. constructor Create (CompID: Integer; ICRLabel: TICLLabel); overload;
  43. constructor Create (ICLLabel: TICLLabel); overload;
  44. destructor Destroy; override;
  45. procedure Merge (AnotherComponent: TICLFeatureComponent);
  46. function GetNumberOfPointBetweenLines (MinY, MaxY: Integer;
  47. MinX, MaxX: Integer): Integer;
  48. end;
  49. TICLFeatureComponentCollection= class (TBaseCollection)
  50. private
  51. function GetComponent(Index: Integer): TICLFeatureComponent;
  52. public
  53. property Component [Index: Integer]: TICLFeatureComponent read GetComponent;
  54. constructor Create;
  55. procedure AddComponent (NewComponent: TICLFeatureComponent);
  56. procedure SetComponent (Index: Integer; NewComponent: TICLFeatureComponent);
  57. end;
  58. TICLNeighborRegion= class (TObject)
  59. private
  60. public
  61. constructor Create (RegionID: Integer;
  62. Direction: TICLNeighberhoodDirection);
  63. destructor Destroy; override;
  64. end;
  65. TICLNeighborRegionCollection= class (TBaseCollection)
  66. private
  67. function GetICLNeighbor(Index: Integer): TICLNeighborRegion;
  68. public
  69. property ICLNeighbor [Index: Integer]: TICLNeighborRegion read GetICLNeighbor;
  70. procedure AddICLNeighbor (NewICLNeighbor: TICLNeighborRegion);
  71. end;
  72. TMomentums= record
  73. momentum11,
  74. momentum20,
  75. momentum02:Double;
  76. end;
  77. TElongation= record
  78. Epsilon ,
  79. Phi ,
  80. x, y :Double;
  81. end;
  82. TICLDescriptor= class (TObject)
  83. private
  84. FCompAreaRegardingImArea: Integer;// Multiplied by 100
  85. FCOMCordRegardingImage: TPoint;// Multiplied by 100
  86. FLabel: TICLLabel;
  87. FPointsInRegion: Integer;
  88. FComponentHeightRegImHeight,
  89. FComponentWidthRegImWidth: Extended;
  90. FElongation: TElongation;
  91. constructor Create; overload;
  92. public
  93. property CompAreaRegardingImArea: Integer
  94. read FCompAreaRegardingImArea;
  95. property COMCordRegardingImage: TPoint
  96. read FCOMCordRegardingImage;
  97. property PointsInRegion: Integer read FPointsInRegion;
  98. property ComponentHeightRegardingImageHeight: Extended read FComponentHeightRegImHeight;
  99. property ComponentWidthRegardingImageWidth: Extended read FComponentWidthRegImWidth;
  100. property ICLLabel: TICLLabel read FLabel;
  101. constructor Create (ICLRegion: TICLFeatureComponent;
  102. ImageHeigth, ImageWidth: Integer); overload;
  103. destructor Destroy; override;
  104. function FindDistance (AnotherICLDescriptor: TICLDescriptor;
  105. WeightedArray: TWeightArray): Extended;
  106. function ToString: String;
  107. function IsMatchable (AnotherICLDescriptor: TICLDescriptor): Boolean;
  108. function CalculateMomentum (ICLRegion: TICLFeatureComponent):TMomentums;
  109. procedure SaveToFile (var OutputFile: TextFile);
  110. procedure SaveToStream (var OutputStream: TMyFileStream);
  111. procedure FstSaveToFile(var OutputFile: TextFile;
  112. Selected : array of Boolean; CountOfSubWordParams: Integer; ConstInc: Double;
  113. RegionCoef: array of Integer); procedure LoadFromFile (var InputFile: TextFile);
  114. end;
  115. TDistanceInfo= record
  116. Value: Extended;
  117. Mapped: array of Integer;
  118. ScoreForMap: array of Extended;
  119. end;
  120. TRelPosInfo = class
  121. public
  122. x,y : Double;
  123. function ToString: string;
  124. constructor Create; overload;
  125. constructor Create (Str: String);overload;
  126. end;
  127. TICLDescriptorCollection= class (TBaseCollection)
  128. private
  129. FImageWidth: Integer;
  130. FImageHeight: Integer;
  131. FImageBlackPixDensity: Double;//In percent
  132. // FRelImageWidth: Double;//In percent
  133. FRelImageHeight: Double;//In percent
  134. FBlackPercOnBaseLine: Double;//In percent
  135. FBlackPercUpperBaseLine: Double;//In percent
  136. FBlackPercBelowBaseLine: Double;//In percent
  137. FCOMRelPos: TRelPosInfo;
  138. function GetICLDescriptor (Index: Integer): TICLDescriptor;
  139. public
  140. property ICLDescriptor [Index: Integer]: TICLDescriptor read GetICLDescriptor;
  141. property ImageWidth: Integer read FImageWidth;
  142. property ImageHeight: Integer read FImageHeight;
  143. property BlackPercOnBaseLine: Double read FBlackPercOnBaseLine;
  144. property COMRelPos: TRelPosInfo read FCOMRelPos;
  145. constructor Create;
  146. destructor Destroy; override;
  147. function FindDistanceDetailed (AnotherICLDescCol: TICLDescriptorCollection
  148. ;WeightArray: TWeightArray): TDistanceInfo;
  149. function FindDistance (AnotherICLDescCol: TICLDescriptorCollection;
  150. WeightArray: TWeightArray): Extended;
  151. procedure AddICLDescriptor (NewICLDescriptor: TICLDescriptor);
  152. function ToString: String;
  153. procedure SaveToFile (var OutputFile: TextFile);
  154. procedure SaveToStream (OutputStream: TMyFileStream);
  155. procedure LoadFromStream (InputStream: TMyFileStream);
  156. procedure LoadFromFile (var InputFile: TextFile);
  157. procedure FstSaveToFile (var OutputFile: TextFile; Selected:array of Boolean;
  158. CountOfSubWordParams, MissingValue: Integer; ConstInc: Double;
  159. SubWordCoef, RegionCoef: array of Integer);
  160. end;
  161. TICLClassDefinition= class (TBaseCollection)
  162. private
  163. FClassName: String;
  164. FWeightArray: TWeightArray;
  165. function GetICLDescriptorCollection(
  166. Index: Integer): TICLDescriptorCollection;
  167. public
  168. property ClassName: String read FClassName;
  169. property ICLDescriptorCollection [Index: Integer]: TICLDescriptorCollection
  170. read GetICLDescriptorCollection;
  171. constructor Create; overload;
  172. constructor Create (ClassName: String; WeightArray: array of Extended); overload;
  173. procedure LoadFromFile (FileName: String); overload;
  174. procedure LoadFromFile (var InputFile: TextFile); overload;
  175. procedure SaveToFile (FileName: String); overload;
  176. procedure SaveToFile (var OutputFile: TextFile); overload;
  177. procedure AddICLDescriptorCollection (NewICLDescriptorCollection:
  178. TICLDescriptorCollection);
  179. function Evaluate (Query: TICLDescriptorCollection;
  180. WeightArray: TWeightArray): Extended;
  181. end;
  182. TICLClassDefinitionCollection= class (TBaseCollection)
  183. private
  184. function GetICLClassDefiniont (Index: Integer): TICLClassDefinition;
  185. public
  186. property ICLClassDefinition [Index: Integer]: TICLClassDefinition
  187. read GetICLClassDefiniont;
  188. constructor Create;
  189. procedure AddClassDefinition (NewICLClassDefinition: TICLClassDefinition);
  190. function FindClass (AQuery: TICLDescriptorCollection;
  191. WeightArray: TWeightArray): Integer;
  192. procedure SaveToFile (FileName: String);
  193. procedure LoadFromFile (FileName: String);
  194. end;
  195. TSubwordInfo= class (TObject)
  196. private
  197. FBaseLineHeightCoef: Integer;
  198. FBaseLineWidthCoef: Integer;
  199. FBaseLineHeight: Integer;
  200. FThickness: Integer;
  201. public
  202. property BaseLineHeightCoef: Integer read FBaseLineHeightCoef write FBaseLineHeightCoef;
  203. property BaseLineWidthCoef: Integer read FBaseLineWidthCoef write FBaseLineWidthCoef;
  204. property BaseLineHeight: Integer read FBaseLineHeight write FBaseLineHeight;
  205. property Thickness: Integer read FThickness write FThickness;
  206. constructor Create;
  207. destructor Destroy; override;
  208. procedure LoadFromFile (Filename: String);
  209. end;
  210. TFreemanFeature= class (TBaseCollection)
  211. private
  212. FColumns, FRows: Integer;
  213. FImageBlackPixDensity: Integer;
  214. FComponents: TICLFeatureComponentCollection;
  215. function GetARowofFreemanFeature(
  216. Index: Integer): TARowOfFreemanFeature;
  217. public
  218. property ARowofFreemanFeature [Index: Integer]: TARowOfFreemanFeature
  219. read GetARowofFreemanFeature;
  220. property Components: TICLFeatureComponentCollection read
  221. FComponents;
  222. procedure AddNextRowOfFreemanFeature
  223. (ARowOfFreemanFeature: TARowOfFreemanFeature);
  224. constructor Create (Row, Colum, BlackPixDensity: Integer);
  225. destructor Destroy; override;
  226. procedure FindComponents;
  227. function DescribeAllComponents (SubwordInfo: TSubwordInfo;
  228. ImageCoM: TPoint): TICLDescriptorCollection;
  229. function DescribeAllFeatures: String;
  230. end;
  231. implementation
  232. uses Math, ExceptionUnit, VarUtils, Classes;
  233. type
  234. TBoolGraph= array of array of Boolean;
  235. function HaveCompleteMatching (Graph: TBoolGraph): Boolean;
  236. var
  237. RightMatchedWith,
  238. LeftMatchedWith: array of Integer;
  239. Visited: array of Boolean;
  240. i: Integer;
  241. LeftSideSize, RightSideSize: Integer;
  242. function DFS (LeftNodeIndex: Integer): Boolean;
  243. var
  244. i: Integer;
  245. begin
  246. for i:= 0 to RightSideSize- 1 do
  247. if (not Visited [i]) and (Graph [LeftNodeIndex, i]) then
  248. begin
  249. Visited [i]:= True;
  250. if RightMatchedWith [i]= -1 then
  251. begin
  252. RightMatchedWith [i]:= LeftNodeIndex;
  253. LeftMatchedWith [LeftNodeIndex]:= i;
  254. Result:= True;
  255. Exit;
  256. end
  257. else if DFS (RightMatchedWith [i]) then
  258. begin
  259. RightMatchedWith [i]:= LeftNodeIndex;
  260. LeftMatchedWith [LeftNodeIndex]:= i;
  261. Result:= True;
  262. Exit;
  263. end;
  264. end;
  265. Result:= False;
  266. end;
  267. begin
  268. LeftSideSize:= Length (Graph);
  269. RightSideSize:= Length (Graph [0]);
  270. Result:= True;
  271. SetLength (RightMatchedWith, RightSideSize);
  272. SetLength (LeftMatchedWith, LeftSideSize);
  273. FillChar (RightMatchedWith [0], RightSideSize* SizeOf (Integer), 255);
  274. FillChar (LeftMatchedWith [0], LeftSideSize* SizeOf (Integer), 255);
  275. SetLength (Visited, RightSideSize);
  276. for i:= 0 to LeftSideSize- 1 do
  277. begin
  278. FillChar (Visited [0], RightSideSize* SizeOf (Boolean), 0);
  279. if not DFS (i) then
  280. begin
  281. Result:= False;
  282. Break;
  283. end;
  284. end;
  285. SetLength (Visited, 0);
  286. SetLength (RightMatchedWith, 0);
  287. SetLength (LeftMatchedWith, 0);
  288. end;
  289. { TFreemanFeatute }
  290. procedure TFreemanFeature.AddNextRowOfFreemanFeature (
  291. ARowOfFreemanFeature: TARowOfFreemanFeature);
  292. begin
  293. if ARowOfFreemanFeature.Size<> FColumns then
  294. raise EInvalidFreemanFeatureRow.Create ('Invalid Size!');
  295. inherited Add (ARowOfFreemanFeature);
  296. end;
  297. constructor TFreemanFeature.Create (Row, Colum, BlackPixDensity: Integer);
  298. begin
  299. inherited Create;
  300. FRows:= Row;
  301. FColumns:= Colum;
  302. FImageBlackPixDensity:= BlackPixDensity;
  303. end;
  304. function TFreemanFeature.DescribeAllComponents (SubwordInfo: TSubwordInfo;
  305. ImageCoM: TPoint): TICLDescriptorCollection;
  306. var
  307. BlackPixOnBaseLine,
  308. BlackPixUpperBaseLine,
  309. BlackPixBelowBaseLine: Integer;
  310. function Describe (ICLRegion: TICLFeatureComponent): TICLDescriptor;
  311. var
  312. i: Integer;
  313. begin
  314. Result:= TICLDescriptor.Create (ICLRegion, FRows, FColumns);
  315. for i:=0 to ICLRegion.PointsInComponent.Size- 1 do
  316. if ICLRegion.PointsInComponent.Point [i].r<
  317. SubwordInfo.FBaseLineHeight then
  318. Inc(BlackPixUpperBaseLine)
  319. else if ICLRegion.PointsInComponent.Point [i].r >
  320. SubwordInfo.FBaseLineHeight + SubwordInfo.FThickness then
  321. Inc(BlackPixBelowBaseLine)
  322. else
  323. inc(BlackPixOnBaseLine);
  324. Result.FCompAreaRegardingImArea:= ICLRegion.FPercentageOfPointsInComp;
  325. end;
  326. var
  327. i: Integer;
  328. Ptr: PObject;
  329. TotalPoints:Integer;
  330. begin
  331. BlackPixOnBaseLine:= 0;
  332. BlackPixUpperBaseLine:= 0;
  333. BlackPixBelowBaseLine:= 0;
  334. Result:= TICLDescriptorCollection.Create;
  335. Result.FImageWidth:= FColumns;
  336. Result.FImageHeight:= FRows;
  337. Result.FImageBlackPixDensity:= FImageBlackPixDensity;
  338. { Result.FRelImageWidth:=
  339. FColumns/ (SubwordInfo.FThickness * SubwordInfo.FBaseLineWidthCoef);
  340. Result.FRelImageHeight:=
  341. FRows/ (SubwordInfo.FThickness * SubwordInfo.FBaseLineHeightCoef);
  342. }
  343. Result.FCOMRelPos.x:= ImageCoM.c/ FColumns;
  344. Result.FCOMRelPos.y:= ImageCoM.r / FRows;
  345. Ptr:= FComponents.GetPointerToFirst;
  346. if FComponents.Size<> 0 then
  347. begin
  348. for i:= 0 to FComponents.Size- 1 do
  349. begin
  350. Result.AddICLDescriptor (Describe (TICLFeatureComponent (Ptr^)));
  351. Inc (Ptr);
  352. end;
  353. TotalPoints:= BlackPixOnBaseLine+BlackPixUpperBaseLine+BlackPixBelowBaseLine;
  354. Result.FBlackPercOnBaseLine:= BlackPixOnBaseLine / TotalPoints;
  355. Result.FBlackPercUpperBaseLine:= BlackPixUpperBaseLine / TotalPoints;
  356. Result.FBlackPercBelowBaseLine:= BlackPixBelowBaseLine / TotalPoints;
  357. end;
  358. end;
  359. function TFreemanFeature.DescribeAllFeatures: String;
  360. begin
  361. Result:= '';
  362. end;
  363. procedure TFreemanFeature.FindComponents;
  364. const
  365. ICLCompMinThr= CONST_ICL_MIN_COMPONENT_SIZE;
  366. var
  367. TotalWhitePixCount,
  368. r, c: Integer;
  369. IsVisited: array of array of Boolean;
  370. RowPtrs: array of PObject;
  371. IsVisitedPtr: PBoolean;
  372. PixPtr: POBject;
  373. ActiveComp: TICLFeatureComponent;
  374. TempPtr: PObject;
  375. procedure DFS (r, c: Integer; CurPtr: PObject);
  376. var
  377. ThisPixelLabel: LongWord;
  378. begin
  379. if not ActiveComp.HashedData.IsExist (r, c) then
  380. begin
  381. Inc (TotalWhitePixCount);
  382. ActiveComp.AddPoint (r, c);
  383. IsVisited [r, c]:= True;
  384. ThisPixelLabel:= PLongWord (CurPtr^)^;
  385. TempPtr:= CurPtr;
  386. if c+ 1< FColumns then
  387. begin
  388. Inc (TempPtr);// Right Point
  389. if ThisPixelLabel= PLongWord (TempPtr^)^ then
  390. DFS (r, c+ 1, TempPtr);
  391. end;
  392. TempPtr:= CurPtr;
  393. if 0< c then
  394. begin
  395. Dec (TempPtr);// Left Point
  396. if ThisPixelLabel= PLongWord (TempPtr^)^ then
  397. DFS (r, c- 1, TempPtr);
  398. end;
  399. TempPtr:= CurPtr;
  400. if r+ 1< FRows then
  401. begin
  402. TempPtr:= RowPtrs [r+ 1];
  403. Inc (TempPtr, c);
  404. if ThisPixelLabel= PLongWord (TempPtr^)^ then
  405. DFS (r+ 1, c, TempPtr);
  406. end;
  407. TempPtr:= CurPtr;
  408. if 0< r then
  409. begin
  410. TempPtr:= RowPtrs [r- 1];
  411. Inc (TempPtr, c);
  412. if ThisPixelLabel= PLongWord (TempPtr^)^ then
  413. DFS (r- 1, c, TempPtr);
  414. end;
  415. end;
  416. end;
  417. function CheckIfIsHole (r, c: Integer): Boolean;
  418. var
  419. PixPtr: PObject;
  420. begin
  421. IsVisited [r, c]:= False;
  422. Result:= False;
  423. PixPtr:= RowPtrs [r];
  424. Inc (PixPtr, c- 1);
  425. if 0< c then
  426. begin
  427. if (PLongWord (PixPtr^)^<> 0) then
  428. begin
  429. if (PLongWord (PixPtr^)^<> LongWord (Ord (iclBlackPixInFreeman))) then
  430. Exit;
  431. end
  432. else
  433. if IsVisited [r, c- 1] then
  434. if not CheckIfIsHole (r, c- 1) then
  435. Exit;
  436. end;
  437. if c< FColumns- 1 then
  438. begin
  439. Inc (PixPtr, 2);
  440. if (PLongWord (PixPtr^)^<> 0) then
  441. begin
  442. if (PLongWord (PixPtr^)^<> LongWord (Ord (iclBlackPixInFreeman))) then
  443. Exit;
  444. end
  445. else
  446. if IsVisited [r, c+ 1] then
  447. if not CheckIfIsHole (r, c+ 1) then
  448. Exit;
  449. end;
  450. if 0< r then
  451. begin
  452. PixPtr:= RowPtrs [r- 1];
  453. Inc (PixPtr, c);
  454. if (PLongWord (PixPtr^)^<> 0) then
  455. begin
  456. if (PLongWord (PixPtr^)^<> LongWord (Ord (iclBlackPixInFreeman))) then
  457. Exit;
  458. end
  459. else
  460. if IsVisited [r- 1, c]then
  461. if not CheckIfIsHole (r- 1, c) then
  462. Exit;
  463. end;
  464. if r< FRows- 1 then
  465. begin
  466. PixPtr:= RowPtrs [r+ 1];
  467. Inc (PixPtr, c);
  468. if (PLongWord (PixPtr^)^<> 0) then
  469. begin
  470. if (PLongWord (PixPtr^)^<> LongWord (Ord (iclBlackPixInFreeman))) then
  471. Exit;
  472. end
  473. else
  474. if IsVisited [r+ 1, c] then
  475. if not CheckIfIsHole (r+ 1, c) then
  476. Exit;
  477. end;
  478. Result:= True;
  479. end;
  480. var
  481. i: Integer;
  482. CompPtr: PObject;
  483. begin
  484. SetLength (IsVisited, FRows);
  485. SetLength (RowPtrs, FRows);
  486. for r:= 0 to FRows- 1 do
  487. begin
  488. SetLength (IsVisited [r], FColumns);
  489. FillChar (IsVisited [r, 0], SizeOf (Boolean)* FColumns, 0);
  490. RowPtrs [r]:= ARowofFreemanFeature [r].GetPointerToFirst;
  491. end;
  492. FComponents:= TICLFeatureComponentCollection.Create;
  493. TotalWhitePixCount:= 0;
  494. for r:= 0 to FRows- 1 do
  495. begin
  496. PixPtr:= RowPtrs [r];
  497. IsVisitedPtr:= @IsVisited [r, 0];
  498. for c:= 0 to FColumns- 1 do
  499. begin
  500. if (PLongWord (PixPtr^)^<> LongWord (Ord (iclBlackPixInFreeman))) and
  501. (not IsVisitedPtr^) then
  502. begin
  503. Inc (TotalWhitePixCount);
  504. ActiveComp:= TICLFeatureComponent.Create (PLongWord (PixPtr^)^);
  505. DFS (r, c, PixPtr);
  506. FComponents.AddComponent (ActiveComp)
  507. end;
  508. Inc (PixPtr);
  509. Inc (IsVisitedPtr);
  510. end;
  511. end;
  512. CompPtr:= FComponents.GetPointerToFirst;
  513. Inc (CompPtr, FComponents.Size- 1);
  514. for i:= FComponents.Size- 1 downto 0 do
  515. begin
  516. TICLFeatureComponent (CompPtr^).FPercentageOfPointsInComp:=
  517. (TICLFeatureComponent (CompPtr^).FPointCollection.Size* 100) div (FRows* FColumns){TotalWhitePixCount};
  518. Dec (CompPtr);
  519. end;
  520. for i:= 0 to FComponents.Size- 1 do
  521. begin
  522. //All IsVisited Must be true
  523. if FComponents.Component [i].ICLLabel= 0 then
  524. if CheckIfIsHole (FComponents.Component [i].FPointCollection.Point [0].r,
  525. FComponents.Component [i].FPointCollection.Point [0].c) then
  526. FComponents.Component [i].FICLLabel:= Ord (iclHole);
  527. end;
  528. CompPtr:= FComponents.GetPointerToFirst;
  529. Inc (CompPtr, FComponents.Size- 1);
  530. for i:= FComponents.Size- 1 downto 0 do
  531. begin
  532. if (100* TICLFeatureComponent (CompPtr^).FPointCollection.Size <
  533. FRows* FColumns* ICLCompMinThr)
  534. and (TICLFeatureComponent (CompPtr^).FICLLabel <> Byte (Ord (iclHole))) then
  535. FComponents.Delete (i);
  536. Dec (CompPtr);
  537. end;
  538. for r:= 0 to FRows- 1 do
  539. SetLength (IsVisited [r], 0);
  540. SetLength (IsVisited, 0);
  541. SetLength (RowPtrs, 0);
  542. end;
  543. destructor TFreemanFeature.Destroy;
  544. begin
  545. if FComponents<> nil then
  546. FComponents.Free;
  547. inherited;
  548. end;
  549. function TFreemanFeature.GetARowofFreemanFeature (
  550. Index: Integer): TARowOfFreemanFeature;
  551. begin
  552. Result:= Member [Index] as TARowOfFreemanFeature;
  553. end;
  554. { TICLFeatureComponents }
  555. procedure TICLFeatureComponent.AddPoint (Point: TPoint);
  556. begin
  557. AddPoint (Point.r, Point.c);
  558. end;
  559. procedure TICLFeatureComponent.AddPoint(r, c: Integer);
  560. var
  561. NewPoint: TPoint;
  562. begin
  563. if HashedData.IsExist (r, c) then
  564. Exit;
  565. if FPointCollection.Size= 0 then
  566. begin
  567. if FMinPoint<> nil then
  568. FMinPoint.Free;
  569. if FMaxPoint<> nil then
  570. FMaxPoint.Free;
  571. FMinPoint:= TPoint.Create (r, c);
  572. FMaxPoint:= TPoint.Create (r, c);
  573. end
  574. else
  575. begin
  576. if r< FMinPoint.r then
  577. FMinPoint.r:= r
  578. else if FMaxPoint.r< r then
  579. FMaxPoint.r:= r;
  580. if c< FMinPoint.c then
  581. FMinPoint.c:= c
  582. else if FMaxPoint.c< c then
  583. FMaxPoint.c:= c;
  584. end;
  585. FCenterOfMass.Move (r, c);
  586. HashedData.Insert (r, c);
  587. NewPoint:= TPoint.Create (r, c);
  588. FPointCollection.AddPoint (NewPoint);
  589. end;
  590. constructor TICLFeatureComponent.Create (CompID: Integer; ICRLabel: TICLLabel);
  591. begin
  592. inherited Create;
  593. FICLLabel:= ICLLabel;
  594. FID:= CompID;
  595. FPointCollection:= TPointCollection.Create;
  596. HashedData:= THash.Create;
  597. FCenterOfMass:= TPoint.Create (0, 0);
  598. FMinPoint:= nil;
  599. FMaxPoint:= nil;
  600. end;
  601. constructor TICLFeatureComponent.Create (ICLLabel: TICLLabel);
  602. begin
  603. inherited Create;
  604. FICLLabel:= ICLLabel;
  605. FID:= 0;
  606. FPointCollection:= TPointCollection.Create;
  607. HashedData:= THash.Create;
  608. FCenterOfMass:= TPoint.Create (0, 0);
  609. FMinPoint:= nil;
  610. FMaxPoint:= nil;
  611. end;
  612. destructor TICLFeatureComponent.Destroy;
  613. begin
  614. HashedData.Free;
  615. FCenterOfMass.Free;
  616. FPointCollection.Free;
  617. if FMinPoint<> nil then
  618. FMinPoint.Free;
  619. if FMaxPoint<> nil then
  620. FMaxPoint.Free;
  621. inherited;
  622. end;
  623. { TICLFeatureComponentCollection }
  624. procedure TICLFeatureComponentCollection.AddComponent(
  625. NewComponent: TICLFeatureComponent);
  626. begin
  627. inherited Add (NewComponent);
  628. end;
  629. constructor TICLFeatureComponentCollection.Create;
  630. begin
  631. inherited Create;
  632. end;
  633. function TICLFeatureComponentCollection.GetComponent (
  634. Index: Integer): TICLFeatureComponent;
  635. begin
  636. Result:= Member [Index] as TICLFeatureComponent;
  637. end;
  638. function TICLFeatureComponent.GetMaxPoint: TPoint;
  639. begin
  640. if FPointCollection.Size= 0 then
  641. Result:= TPoint.Create (0, 0)
  642. else
  643. Result:= FMaxPoint.Copy;
  644. end;
  645. function TICLFeatureComponent.GetMinPoint: TPoint;
  646. begin
  647. if FPointCollection.Size= 0 then
  648. Result:= TPoint.Create (0, 0)
  649. else
  650. Result:= FMinPoint.Copy;
  651. end;
  652. function TICLFeatureComponent.GetNumberOfPointBetweenLines (MinY,
  653. MaxY: Integer; MinX, MaxX: Integer): Integer;
  654. var
  655. x, y: Integer;
  656. begin
  657. Result:= 0;
  658. for x:= MinX to MaxX do
  659. begin
  660. for y:= MinY to MaxY do
  661. if HashedData.IsExist (x, y) then
  662. Inc (Result);
  663. end;
  664. end;
  665. procedure TICLFeatureComponent.Merge(
  666. AnotherComponent: TICLFeatureComponent);
  667. var
  668. i, j: Integer;
  669. Hash: THash;
  670. Point: TPoint;
  671. begin
  672. Hash:= AnotherComponent.HashedData;
  673. for i:= 0 to High (Hash.Data) do
  674. begin
  675. for j:= 0 to High (Hash.Data [i]) do
  676. begin
  677. Point:= Hash.Data [i][j];
  678. Self.AddPoint (Point.r, Point.c);
  679. end;
  680. end;
  681. end;
  682. procedure TICLFeatureComponentCollection.SetComponent(Index: Integer;
  683. NewComponent: TICLFeatureComponent);
  684. begin
  685. FMembers [Index]:= NewComponent;
  686. end;
  687. function BalancedDiff (Source, Data, Max: Extended): Extended;
  688. begin
  689. if Abs (Source)< 1e-10 then
  690. begin
  691. if Abs (Data)< 1e-10 then
  692. Result:= Sign (Data)* Sign (Source)
  693. else
  694. Result:= 0;
  695. if Max< Result then
  696. Result:= Max;
  697. Exit;
  698. end;
  699. Result:= Abs ((Source- Data)/ Source);
  700. if Max< Result then
  701. Result:= Max;
  702. end;
  703. { TICLDescriptor }
  704. function TICLDescriptor.CalculateMomentum(ICLRegion: TICLFeatureComponent): TMomentums;
  705. var
  706. COMr,COMc: double;
  707. i: Integer;
  708. NewFCenterOfMass: TPoint;
  709. r,c: Double;
  710. begin
  711. NewFCenterOfMass := ICLRegion.CenterOfMass.Copy;
  712. NewFCenterOfMass.Move (Round (ICLRegion.FPointCollection.Size * 0.5)
  713. , Round (ICLRegion.FPointCollection.Size * 0.5));
  714. COMc:= NewFCenterOfMass.c/ ICLRegion.FPointCollection.Size;
  715. COMr:= NewFCenterOfMass.r/ ICLRegion.FPointCollection.Size;
  716. Result.momentum11 := 0;
  717. Result.momentum20 := 0;
  718. Result.momentum02 := 0;
  719. for i:=0 to ICLRegion.PointsInComponent.Size-1 do
  720. begin
  721. c:= (ICLRegion.FPointCollection.Point [i].c + 0.5) / ICLRegion.FPointCollection.Size;
  722. r:= (ICLRegion.FPointCollection.Point [i].r + 0.5) / ICLRegion.FPointCollection.Size;
  723. Result.momentum11:=Result.momentum11+ (r- COMr)*(c- COMc);
  724. Result.momentum20:=Result.momentum20+ sqr (c- COMc);
  725. Result.momentum02:=Result.momentum02+ sqr (r- COMr);
  726. end;
  727. end;
  728. constructor TICLDescriptor.Create (ICLRegion: TICLFeatureComponent;
  729. ImageHeigth, ImageWidth: Integer);
  730. var
  731. Momentoms: TMomentums;
  732. NewFCenterOfMass: TPoint;
  733. begin
  734. inherited Create;
  735. FLabel:= ICLRegion.ICLLabel;
  736. FCompAreaRegardingImArea:=
  737. Round (ICLRegion.FPercentageOfPointsInComp);
  738. NewFCenterOfMass:= ICLRegion.CenterOfMass.Copy;
  739. NewFCenterOfMass.c:= NewFCenterOfMass.c + Round (ICLRegion.FPointCollection.Size * 0.5);
  740. NewFCenterOfMass.r:= NewFCenterOfMass.r + Round (ICLRegion.FPointCollection.Size * 0.5);
  741. FCOMCordRegardingImage:= NewFCenterOfMass.Copy.Scale
  742. (100/ (ImageWidth* ICLRegion.FPointCollection.Size),
  743. 100/ (ImageHeigth* ICLRegion.FPointCollection.Size));
  744. FPointsInRegion:= ICLRegion.FPointCollection.Size;
  745. FComponentHeightRegImHeight:= (ICLRegion.MaxPoint.r- ICLRegion.MinPoint.r+ 1)/
  746. ImageHeigth;
  747. FComponentWidthRegImWidth:= (ICLRegion.MaxPoint.c- ICLRegion.MinPoint.c+ 1)/
  748. ImageWidth;
  749. Momentoms:= CalculateMomentum (ICLRegion);
  750. if (Abs (Momentoms.momentum20)< 1e-10) and (Abs (Momentoms.momentum02)< 1e-10) then
  751. begin
  752. //the region is just a point
  753. FElongation.Epsilon := 0;
  754. FElongation.Phi := 0;
  755. end
  756. else if Abs (Momentoms.momentum20) < 1e-10 then
  757. begin
  758. // the region is a one-pixel width column
  759. FElongation.Epsilon := 1;
  760. FElongation.Phi := pi / 2;
  761. end
  762. else if Abs (Momentoms.momentum02) < 1e-10 then
  763. begin
  764. // the region is a one-pixel width row
  765. FElongation.Epsilon := 1;
  766. FElongation.Phi := 0;
  767. end
  768. else
  769. begin
  770. FElongation.Epsilon:= (Sqr (Momentoms.momentum20 - Momentoms.momentum02)+
  771. 4* Sqr(Momentoms.momentum11)) /
  772. Sqr (Momentoms.momentum20 + Momentoms.momentum02);
  773. if abs (Momentoms.momentum20 - Momentoms.momentum02)<1e-10 then
  774. FElongation.Phi:= Pi/ 2
  775. else
  776. FElongation.Phi:= 0.5 *ArcTan (2 * Momentoms.momentum11 /
  777. (Momentoms.momentum20 - Momentoms.momentum02));
  778. end;
  779. FElongation.Phi:= FElongation.Phi+ pi/ 2;
  780. FElongation.x:= FElongation.Epsilon*Sin(2* FElongation.Phi);
  781. FElongation.y:= FElongation.Epsilon*Cos(2* FElongation.Phi);
  782. FElongation.Phi := FElongation.Phi * (180 / pi);
  783. FElongation.Phi:= (FElongation.Phi+ 90)/ 180;
  784. end;
  785. constructor TICLDescriptor.Create;
  786. begin
  787. inherited;
  788. FCOMCordRegardingImage:= nil;
  789. end;
  790. function TICLDescriptor.FindDistance (
  791. AnotherICLDescriptor: TICLDescriptor;
  792. WeightedArray: TWeightArray): Extended;
  793. begin
  794. if FLabel in [3, 6, 12, 9] then// Donbalan
  795. Result:= WeightedArray [6]* BalancedDiff (FComponentHeightRegImHeight,
  796. AnotherICLDescriptor.FComponentHeightRegImHeight, 1)
  797. else
  798. Result:= WeightedArray [7]* BalancedDiff (FCompAreaRegardingImArea,
  799. AnotherICLDescriptor.FCompAreaRegardingImArea, 1);
  800. if not (FLabel in [3, 6, 12, 9]) then//Donbalan
  801. Result:= Result+ WeightedArray [8]* (BalancedDiff (FCOMCordRegardingImage.r,
  802. AnotherICLDescriptor.FCOMCordRegardingImage.r, 1));
  803. Result:= Result+ WeightedArray [9]* (BalancedDiff (FCOMCordRegardingImage.r,
  804. AnotherICLDescriptor.FCOMCordRegardingImage.r, 1));
  805. {
  806. if FLabel= 17 then
  807. Result:= WeightedArray [10]* Result;
  808. }
  809. end;
  810. destructor TICLDescriptor.Destroy;
  811. begin
  812. FCOMCordRegardingImage.Free;
  813. inherited;
  814. end;
  815. function IsPow2 (n: Integer): Boolean;
  816. var
  817. i, j: Integer;
  818. begin
  819. Result:= False;
  820. j:= 1;
  821. for i:= 1 to 31 do
  822. begin
  823. if n and j<> 0 then
  824. begin
  825. if Result then
  826. begin
  827. Result:= False;
  828. Exit;
  829. end;
  830. Result:= True;
  831. end;
  832. j:= j shl 1;
  833. end;
  834. Result:= True;
  835. end;
  836. procedure TICLDescriptor.FstSaveToFile(var OutputFile: TextFile;
  837. selected : array of Boolean;CountOfSubWordParams: Integer; ConstInc: Double;
  838. RegionCoef: array of Integer);
  839. begin
  840. if FLabel= 17 then
  841. begin
  842. if selected [CountOfSubWordParams] then
  843. begin
  844. Writeln (OutputFile,(RegionCoef[0]* FComponentHeightRegImHeight)+ ConstInc:0:3);
  845. // Writeln (OutputFile,(RegionCoef[0]* FComponentWidthRegImWidth)+ ConstInc:0:3);
  846. end;
  847. if selected[CountOfSubWordParams+ 1] then
  848. Writeln (OutputFile, (RegionCoef[1]* Sqrt(FCompAreaRegardingImArea/ 100))+ ConstInc:0:3);
  849. end
  850. else
  851. begin
  852. if selected[CountOfSubWordParams] then
  853. begin
  854. Writeln (OutputFile, FComponentHeightRegImHeight+ ConstInc:0:3);
  855. // Writeln (OutputFile, FComponentWidthRegImWidth+ ConstInc:0:3);
  856. end;
  857. if selected[CountOfSubWordParams+ 1] then
  858. Writeln (OutputFile, Sqrt(FCompAreaRegardingImArea/ 100)+ ConstInc:0:3);
  859. end;
  860. if selected[CountOfSubWordParams+ 2] then
  861. begin
  862. Writeln(OutputFile,(FCOMCordRegardingImage.r / 100)+ ConstInc:0:3);
  863. Writeln(OutputFile,(FCOMCordRegardingImage.c / 100)+ ConstInc:0:3);
  864. end;
  865. if selected[CountOfSubWordParams+ 3] then
  866. begin
  867. Writeln(OutputFile, FElongation.Epsilon+ ConstInc:0:3);
  868. Writeln(OutputFile, FElongation.Phi+ ConstInc:0:3);
  869. end;
  870. if selected [CountOfSubWordParams+ 4] then
  871. begin
  872. Writeln (OutputFile,FElongation.x+ ConstInc:0:3);
  873. Writeln (OutputFile,FElongation.y+ ConstInc:0:3);
  874. end;
  875. end;
  876. function TICLDescriptor.IsMatchable (
  877. AnotherICLDescriptor: TICLDescriptor): Boolean;
  878. begin
  879. if FLabel= Byte (Ord (iclHole)) then
  880. begin
  881. if AnotherICLDescriptor.FLabel in [0, 14, 13, 11, 7, 17] then
  882. Result:= True
  883. else
  884. Result:= False;
  885. end
  886. else if IsPow2 (AnotherICLDescriptor.FLabel xor FLabel) or
  887. (FLabel= AnotherICLDescriptor.FLabel) then
  888. Result:= True
  889. else if AnotherICLDescriptor.FLabel= Byte (Ord (iclHole)) then
  890. begin
  891. if FLabel in [0, 14, 13, 11, 7, 17] then
  892. Result:= True
  893. else
  894. Result:= False;
  895. end
  896. else
  897. Result:= False;
  898. Result:= Result and
  899. (
  900. (FCompAreaRegardingImArea<= 3* AnotherICLDescriptor.FCompAreaRegardingImArea) and
  901. (AnotherICLDescriptor.FCompAreaRegardingImArea<= 3* FCompAreaRegardingImArea))
  902. end;
  903. procedure TICLDescriptor.LoadFromFile (var InputFile: TextFile);
  904. var
  905. S: String;
  906. begin
  907. ReadLn (InputFile, FCompAreaRegardingImArea);
  908. ReadLn (InputFile, S);
  909. if FCOMCordRegardingImage<> nil then
  910. FCOMCordRegardingImage.Free;
  911. FCOMCordRegardingImage:= TPoint.Create (S);
  912. ReadLn (InputFile, FLabel);
  913. ReadLn (InputFile, FPointsInRegion);
  914. ReadLn (InputFile, FComponentHeightRegImHeight);
  915. ReadLn (InputFile, FComponentWidthRegImWidth);
  916. end;
  917. procedure TICLDescriptor.SaveToFile (var OutputFile: TextFile);
  918. begin
  919. WriteLn (OutputFile, 'FCompAreaRegardingImArea= ', FCompAreaRegardingImArea);
  920. WriteLn (OutputFile, 'FCOMCordRegardingImage= ', FCOMCordRegardingImage.ToString);
  921. WriteLn (OutputFile, 'FLabel= ', FLabel);
  922. WriteLn (OutputFile, 'FPointsInRegion= ', FPointsInRegion);
  923. WriteLn (OutputFile, 'FComponentHeightRegImHeight= ', FComponentHeightRegImHeight);
  924. WriteLn (OutputFile, 'FComponentWidthRegImWidth= ', FComponentWidthRegImWidth);
  925. end;
  926. function TICLDescriptor.ToString: String;
  927. begin
  928. Result:= IntToStr (FLabel)+ ': RelSize= '+ IntToStr (FCompAreaRegardingImArea)+ #$0A#$0D+
  929. ' COM='+ FCOMCordRegardingImage.ToString;
  930. end;
  931. procedure TICLDescriptor.SaveToStream(var OutputStream: TMyFileStream);
  932. begin
  933. OutputStream.WriteLine ('FCompAreaRegardingImArea= '+ IntToStr (FCompAreaRegardingImArea));
  934. OutputStream.WriteLine ('FCOMCordRegardingImage= '+ FCOMCordRegardingImage.ToString);
  935. OutputStream.WriteLine ('FLabel= '+ IntToStr (Ord (FLabel)));
  936. OutputStream.WriteLine ('FPointsInRegion= '+ IntToStr (FPointsInRegion));
  937. OutputStream.WriteLine ('FComponentHeightRegImHeight= '+ FloatToStr (FComponentHeightRegImHeight));
  938. OutputStream.WriteLine ('FComponentWidthRegImWidth= '+ FloatToStr (FComponentWidthRegImWidth));
  939. OutputStream.WriteLine ('');
  940. end;
  941. { TICLNeighborRegion }
  942. constructor TICLNeighborRegion.Create(RegionID: Integer;
  943. Direction: TICLNeighberhoodDirection);
  944. begin
  945. end;
  946. destructor TICLNeighborRegion.Destroy;
  947. begin
  948. inherited;
  949. end;
  950. { TICLNeighborRegionCollection }
  951. procedure TICLNeighborRegionCollection.AddICLNeighbor(
  952. NewICLNeighbor: TICLNeighborRegion);
  953. begin
  954. inherited Add (NewICLNeighbor);
  955. end;
  956. function TICLNeighborRegionCollection.GetICLNeighbor (
  957. Index: Integer): TICLNeighborRegion;
  958. begin
  959. Result:= Member [Index] as TICLNeighborRegion;
  960. end;
  961. { TICLDescriptorCollection }
  962. procedure TICLDescriptorCollection.AddICLDescriptor(
  963. NewICLDescriptor: TICLDescriptor);
  964. begin
  965. inherited Add (NewICLDescriptor);
  966. end;
  967. constructor TICLDescriptorCollection.Create;
  968. begin
  969. inherited;
  970. //FCOMRelPos:= nil;
  971. FCOMRelPos := TRelPosInfo.Create;
  972. end;
  973. function TICLDescriptorCollection.FindDistanceDetailed (
  974. AnotherICLDescCol: TICLDescriptorCollection;
  975. WeightArray: TWeightArray): TDistanceInfo;
  976. type
  977. TWeightedGraph= array of array of Extended;
  978. TLeftSidesMatchedWith= array of Integer;
  979. TMatchingDetails= record
  980. LeftSidesMatch: TLeftSidesMatchedWith;
  981. MatchingSize: Integer;
  982. end;
  983. const
  984. MaxCost= 1.35;//0.65+ 2* 0.35;
  985. {
  986. Based on http://www.public.iastate.edu/~ddoty/HungarianAlgorithm.html
  987. }
  988. function FindMinWeightedMatching (Graph: TWeightedGraph): TLeftSidesMatchedWith;
  989. var
  990. RowCover, ColCover: array of Boolean;
  991. XSize, YSize: Integer;
  992. MinWeight: Extended;
  993. Mask: array of array of Byte;
  994. procedure Step1;
  995. var
  996. i, j: Integer;
  997. ExPtr: PExtended;
  998. begin
  999. for i:= 0 to XSize- 1 do
  1000. begin
  1001. MinWeight:= 1e100;
  1002. ExPtr:= @Graph [i, 0];
  1003. for j:= 0 to YSize- 1 do
  1004. begin
  1005. if ExPtr^< MinWeight then
  1006. MinWeight:= ExPtr^;
  1007. Inc (ExPtr);
  1008. end;
  1009. ExPtr:= @Graph [i, 0];
  1010. for j:= 0 to YSize- 1 do
  1011. begin
  1012. ExPtr^:= Abs (ExPtr^- MinWeight);// To avoid negative weights due !!!
  1013. Inc (ExPtr);
  1014. end;
  1015. end;
  1016. end;
  1017. procedure Step2;
  1018. var
  1019. r, c: Integer;
  1020. ExPtr: PExtended;
  1021. begin
  1022. for r:= 0 to XSize- 1 do
  1023. if not RowCover [r] then
  1024. begin
  1025. ExPtr:= @Graph [r, 0];
  1026. for c:= 0 to YSize- 1 do
  1027. begin
  1028. if (ExPtr^< 1e-10) and (not ColCover [c]) then
  1029. begin
  1030. Mask [r, c]:= 1;
  1031. RowCover [r]:= True;
  1032. ColCover [c]:= True;
  1033. Break;
  1034. end;
  1035. Inc (ExPtr);
  1036. end;
  1037. end;
  1038. FillChar (RowCover [0], XSize* SizeOf (Boolean), 0);
  1039. FillChar (ColCover [0], YSize* SizeOf (Boolean), 0);
  1040. end;
  1041. function Step3: Integer;
  1042. var
  1043. i, j: Integer;
  1044. BPtr: PByte;
  1045. begin
  1046. Result:= 0;
  1047. for i:= 0 to XSize- 1 do
  1048. begin
  1049. BPtr:= @Mask [i, 0];
  1050. for j:= 0 to YSize- 1 do
  1051. begin
  1052. if BPtr^= 1 then
  1053. begin
  1054. ColCover [j]:= True;
  1055. Break;
  1056. end;
  1057. Inc (BPtr);
  1058. end;
  1059. end;
  1060. for j:= 0 to YSize- 1 do
  1061. if ColCover [j] then
  1062. Inc (Result);
  1063. end;
  1064. type
  1065. TPoint= record
  1066. r, c: Integer;
  1067. end;
  1068. var
  1069. ZeroPoint: TPoint;
  1070. function Step4: Boolean;
  1071. function FindAZero: TPoint;
  1072. var
  1073. r, c: Integer;
  1074. ExPtr: PExtended;
  1075. begin
  1076. Result.r:= -1;
  1077. for r:= 0 to XSize- 1 do
  1078. begin
  1079. ExPtr:= @Graph [r, 0];
  1080. Inc (ExPtr, YSize- 1);
  1081. if not RowCover [r] then
  1082. for c:= YSize- 1 downto 0 do
  1083. begin
  1084. if (not ColCover [c]) and (ExPtr^< 1e-10) then
  1085. begin
  1086. Result.r:= r;
  1087. Result.c:= c;
  1088. Exit;
  1089. end;
  1090. Dec (ExPtr);
  1091. end;
  1092. end;
  1093. end;
  1094. function HaveStarInRow (Row: Integer): Boolean;
  1095. var
  1096. c: Integer;
  1097. BPtr: PByte;
  1098. begin
  1099. Result:= True;
  1100. BPtr:= @Mask [Row, 0];
  1101. for c:= 1 to YSize do
  1102. begin
  1103. if BPtr^= 1 then
  1104. Exit;
  1105. Inc (BPtr);
  1106. end;
  1107. Result:= False;
  1108. end;
  1109. function FindStarInRow (ARow: Integer): Integer;
  1110. var
  1111. BPtr: PByte;
  1112. begin
  1113. BPtr:= @Mask [ARow, 0];
  1114. for Result:= 0 to YSize- 1 do
  1115. begin
  1116. if BPtr^= 1 then
  1117. Exit;
  1118. Inc (BPtr);
  1119. end;
  1120. Result:= -1;
  1121. end;
  1122. var
  1123. c: Integer;
  1124. ZeroEntry: TPoint;
  1125. begin
  1126. Result:= False;
  1127. while True do
  1128. begin
  1129. ZeroEntry:= FindAZero;
  1130. if ZeroEntry.r< 0 then
  1131. begin
  1132. Result:= True;
  1133. Exit;
  1134. end;
  1135. Mask [ZeroEntry.r, ZeroEntry.c]:= 2;
  1136. c:= FindStarInRow (ZeroEntry.r);
  1137. if c< 0 then
  1138. begin
  1139. ZeroPoint:= ZeroEntry;
  1140. Break;
  1141. end
  1142. else
  1143. begin
  1144. RowCover [ZeroEntry.r]:= True; //Cover the star's row.
  1145. ColCover [c]:= False;
  1146. end;
  1147. end;
  1148. end;
  1149. procedure Step5;
  1150. function FindStarInCol (Column: Integer): Integer;
  1151. begin
  1152. for Result:= 0 to XSize- 1 do
  1153. if Mask [Result, Column]= 1 then
  1154. Exit;
  1155. Result:= -1;
  1156. end;
  1157. function FindPrimeInRow (ARow: Integer): Integer;
  1158. var
  1159. BPtr: PByte;
  1160. begin
  1161. BPtr:= @Mask [ARow, 0];
  1162. for Result:= 0 to XSize- 1 do
  1163. begin
  1164. if BPtr^= 2 then
  1165. Exit;
  1166. Inc (BPtr);
  1167. end;
  1168. Result:= -1;
  1169. end;
  1170. procedure ErasePrimes;
  1171. var
  1172. r, c: Integer;
  1173. BPtr: PByte;
  1174. begin
  1175. for r:= 0 to XSize- 1 do
  1176. begin
  1177. BPtr:= @Mask [r, 0];
  1178. for c:= 1 to YSize do
  1179. begin
  1180. if BPtr^= 2 then
  1181. BPtr^:= 0;
  1182. Inc (BPtr);
  1183. end;
  1184. end;
  1185. end;
  1186. var
  1187. Count: Integer;
  1188. Path: array of TPoint;
  1189. procedure ConvertPath;
  1190. var
  1191. i: Integer;
  1192. begin
  1193. for i:= 0 to Count- 1 do
  1194. if Mask [Path [i].r ,Path [i].c]= 1 then
  1195. Mask [Path [i].r ,Path [i].c]:= 0
  1196. else
  1197. Mask [Path [i].r ,Path [i].c]:= 1;
  1198. end;
  1199. var
  1200. ActivePoint: TPoint;
  1201. r, c: Integer;
  1202. begin
  1203. SetLength (Path, XSize);
  1204. Path [0]:= ZeroPoint;
  1205. ActivePoint:= Path [0];
  1206. Count:= 1;
  1207. while True do
  1208. begin
  1209. r:= FindStarInCol (ActivePoint.c);
  1210. if 0<= r then
  1211. begin
  1212. if Count= Length (Path) then
  1213. SetLength (Path, Length (Path)+ XSize);
  1214. Inc (Count);
  1215. Path [Count- 1].r:= r;
  1216. Path [Count- 1].c:= ActivePoint.c;
  1217. ActivePoint:= Path [Count- 1];
  1218. end
  1219. else
  1220. Break;
  1221. c:= FindPrimeInRow (ActivePoint.r);
  1222. Inc (Count);
  1223. if Length (Path)< Count then
  1224. SetLength (Path, Length (Path)+ XSize);
  1225. Path [Count- 1].r:= ActivePoint.r;
  1226. Path [Count- 1].c:= c;
  1227. ActivePoint:= Path [Count- 1];
  1228. end;
  1229. ConvertPath;
  1230. FillChar (RowCover [0], SizeOf (Boolean)* XSize, 0);
  1231. FillChar (ColCover [0], SizeOf (Boolean)* YSize, 0);
  1232. ErasePrimes;
  1233. end;
  1234. procedure Step6;
  1235. var
  1236. Smallest: Extended;
  1237. ExPtr: PExtended;
  1238. r, c: Integer;
  1239. begin
  1240. Smallest:= 1e100;
  1241. for r:= 0 to XSize- 1 do
  1242. begin
  1243. if not RowCover [r] then
  1244. begin
  1245. ExPtr:= @Graph [r, 0];
  1246. for c:= 0 to YSize- 1 do
  1247. begin
  1248. if not ColCover [c] then
  1249. if ExPtr^< Smallest then
  1250. Smallest:= ExPtr^;
  1251. Inc (ExPtr);
  1252. end;
  1253. end;
  1254. end;
  1255. for r:= 0 to XSize- 1 do
  1256. for c:= 0 to YSize- 1 do
  1257. begin
  1258. if RowCover [r] then
  1259. Graph [r, c]:= Graph [r, c]+ Smallest;
  1260. if not ColCover [c] then
  1261. Graph [r, c]:= Graph [r, c]- Smallest;
  1262. end;
  1263. end;
  1264. var
  1265. r, c: Integer;
  1266. begin
  1267. XSize:= Length (Graph);
  1268. YSize:= Length (Graph [0]);
  1269. SetLength (RowCover, XSize);
  1270. SetLength (ColCover, YSize);
  1271. FillChar (RowCover [0], XSize* SizeOf (Boolean), 0);
  1272. FillChar (ColCover [0], YSize* SizeOf (Boolean), 0);
  1273. SetLength (Mask, XSize);
  1274. for r:= 0 to XSize- 1 do
  1275. begin
  1276. SetLength (Mask [r], YSize);
  1277. FillChar (Mask [r, 0], YSize* SizeOf (Byte), 0);
  1278. end;
  1279. Step1;
  1280. Step2;
  1281. while Step3<> YSize do
  1282. begin
  1283. if Step4 then
  1284. begin
  1285. repeat
  1286. Step6
  1287. until not Step4;
  1288. Step5;
  1289. end
  1290. else
  1291. Step5;
  1292. end;
  1293. SetLength (Result, XSize);
  1294. FillChar (Result [0], XSize* SizeOf (Integer), 255);
  1295. for r:= 0 to XSize- 1 do
  1296. begin
  1297. for c:= 0 to YSize- 1 do
  1298. if Mask [r, c]= 1 then
  1299. begin
  1300. Result [r]:= c;
  1301. Break;
  1302. end;
  1303. end;
  1304. for r:= 0 to XSize- 1 do
  1305. SetLength (Mask [r], 0);
  1306. SetLength (Mask, 0);
  1307. SetLength (RowCover, 0);
  1308. SetLength (ColCover, 0);
  1309. end;
  1310. const
  1311. Inf= 1e3;
  1312. var
  1313. MatchingInfo: TLeftSidesMatchedWith;
  1314. w: Extended;
  1315. i, j: Integer;
  1316. AnotherSize: Integer;
  1317. Ptr1, Ptr2: PObject;
  1318. ExPtr1: PExtended;
  1319. Graph: TWeightedGraph;
  1320. begin
  1321. Result.Value:=
  1322. 0.6* (BalancedDiff (FImageWidth,
  1323. AnotherICLDescCol.FImageWidth, 1)+
  1324. BalancedDiff (FImageHeight,
  1325. AnotherICLDescCol.FImageHeight, 1));
  1326. Result.Value:= Result.Value+ 0.2* BalancedDiff (FBlackPercOnBaseLine,
  1327. AnotherICLDescCol.FBlackPercOnBaseLine, 1);
  1328. Result.Value:= Result.Value+ 0.1* (BalancedDiff (FCOMRelPos.x,
  1329. AnotherICLDescCol.FCOMRelPos.x, 1)+
  1330. BalancedDiff (FCOMRelPos.y,
  1331. AnotherICLDescCol.FCOMRelPos.y, 1));
  1332. Result.Value:= 100* Result.Value;
  1333. AnotherSize:= AnotherICLDescCol.Size;
  1334. SetLength (Graph, Size+ AnotherSize);
  1335. for i:= 0 to Size+ AnotherSize- 1 do
  1336. SetLength (Graph [i], Size+ AnotherSize);
  1337. Ptr1:= GetPointerToFirst;
  1338. for i:= 0 to Size- 1 do
  1339. begin
  1340. ExPtr1:= @Graph [i, 0];
  1341. Inc (ExPtr1, AnotherSize);
  1342. w:= TICLDescriptor (Ptr1^).FCompAreaRegardingImArea;
  1343. if TICLDescriptor (Ptr1^).FLabel= Byte (Ord (iclHole)) then
  1344. w:= 2* w;
  1345. for j:= AnotherSize to AnotherSize+ Size- 1 do
  1346. begin
  1347. ExPtr1^:= w* MaxCost;
  1348. Inc (ExPtr1);
  1349. end;
  1350. Inc (Ptr1);
  1351. end;
  1352. Ptr2:= AnotherICLDescCol.GetPointerToFirst;
  1353. for i:= Size to AnotherSize+ Size- 1 do
  1354. begin
  1355. ExPtr1:= @Graph [i, 0];
  1356. w:= TICLDescriptor (Ptr2^).FCompAreaRegardingImArea;
  1357. if TICLDescriptor (Ptr2^).FLabel= Byte (Ord (iclHole)) then
  1358. w:= 2* w;
  1359. for j:= 0 to AnotherSize- 1 do
  1360. begin
  1361. ExPtr1^:= w* MaxCost;
  1362. Inc (ExPtr1);
  1363. end;
  1364. Inc (Ptr2);
  1365. end;
  1366. for i:= Size to AnotherSize+ Size- 1 do
  1367. begin
  1368. ExPtr1:= @Graph [i, 0];
  1369. Inc (ExPtr1, AnotherSize);
  1370. for j:= AnotherSize to Size+ AnotherICLDescCol.Size- 1 do
  1371. begin
  1372. ExPtr1^:= 0;
  1373. Inc (ExPtr1);
  1374. end;
  1375. end;
  1376. Ptr1:= GetPointerToFirst;
  1377. for i:= 0 to Size- 1 do
  1378. begin
  1379. ExPtr1:= @Graph [i, 0];
  1380. w:= TICLDescriptor (Ptr1^).FCompAreaRegardingImArea;
  1381. Ptr2:= AnotherICLDescCol.GetPointerToFirst;
  1382. for j:= 0 to AnotherSize- 1 do
  1383. begin
  1384. if TICLDescriptor (Ptr1^).IsMatchable ( TICLDescriptor (Ptr2^)) then
  1385. ExPtr1^:= w*
  1386. (TICLDescriptor (Ptr1^).FindDistance (TICLDescriptor (Ptr2^), WeightArray))
  1387. else
  1388. ExPtr1^:= Inf;//??!!
  1389. Inc (ExPtr1);
  1390. Inc (Ptr2);
  1391. end;
  1392. Inc (Ptr1);
  1393. end;
  1394. (*$ifdef Debug_Matching_Details*)
  1395. WriteLn ('Self:');
  1396. WriteLn (Self.ToString);
  1397. WriteLn ('Another:');
  1398. WriteLn (AnotherICLDescCol.ToString);
  1399. for i:= 0 to High (Graph) do
  1400. begin
  1401. for j:= 0 to High (Graph [i]) do
  1402. Write (Graph [i, j]:0:4, ' ');
  1403. WriteLn;
  1404. end;
  1405. WriteLn;
  1406. (*$endif*)
  1407. MatchingInfo:= FindMinWeightedMatching (Graph);
  1408. (*$ifdef Debug_Matching_Details*)
  1409. for i:= 0 to High (Graph) do
  1410. Write (i, ':', MatchingInfo [i], ' ');
  1411. WriteLn;
  1412. Write (Result.Value:0:4, ' ');
  1413. (*$endif*)
  1414. SetLength (Result.Mapped, Size+ AnotherSize);
  1415. SetLength (Result.ScoreForMap, Size+ AnotherSize);
  1416. Ptr1:= GetPointerToFirst;
  1417. for i:= 0 to Size- 1 do
  1418. begin
  1419. j:= MatchingInfo [i];
  1420. Result.Mapped [i]:= j;
  1421. w:= TICLDescriptor (Ptr1^).FCompAreaRegardingImArea;
  1422. if TICLDescriptor (Ptr1^).FLabel= Byte (Ord (iclHole)) then
  1423. w:= 2* w;
  1424. if j< AnotherSize then
  1425. begin
  1426. if TICLDescriptor (Ptr1^).IsMatchable (AnotherICLDescCol.ICLDescriptor [j]) then
  1427. begin
  1428. Result.Value:= Result.Value+
  1429. w*
  1430. TICLDescriptor (Ptr1^).FindDistance (AnotherICLDescCol.ICLDescriptor [j], WeightArray);
  1431. Result.ScoreForMap [i]:= w*
  1432. TICLDescriptor (Ptr1^).FindDistance (AnotherICLDescCol.ICLDescriptor [j], WeightArray);
  1433. end
  1434. else
  1435. begin
  1436. Result.Value:= Result.Value+ Inf;
  1437. Result.ScoreForMap [i]:= Inf;
  1438. end;
  1439. end
  1440. else
  1441. begin
  1442. Result.Value:= Result.Value+
  1443. w* (MaxCost+ 1);
  1444. Result.ScoreForMap [i]:= w* (MaxCost+ 1);
  1445. end;
  1446. (*$ifdef Debug_Matching_Details*)
  1447. Write (i, ':', Result.Value:0:4, ' ');
  1448. (*$endif*)
  1449. Inc (Ptr1);
  1450. end;
  1451. (*$ifdef Debug_Matching_Details*)
  1452. Writeln;
  1453. Writeln;
  1454. (*$endif*)
  1455. for i:= Size to AnotherSize+ Size- 1 do
  1456. begin
  1457. j:= MatchingInfo [i];
  1458. Result.Mapped [i]:= j;
  1459. if j< AnotherSize then
  1460. begin
  1461. w:= AnotherICLDescCol.ICLDescriptor [j].FCompAreaRegardingImArea;
  1462. if AnotherICLDescCol.ICLDescriptor [j].FLabel= Byte (Ord (iclHole)) then
  1463. w:= 2* w;
  1464. Result.Value:= Result.Value+
  1465. w* (MaxCost+ 1);
  1466. Result.ScoreForMap [i]:= w* (MaxCost+ 1);
  1467. end
  1468. else
  1469. //Result:= Result+ 0;
  1470. Result.ScoreForMap [i]:= 0
  1471. end;
  1472. SetLength (MatchingInfo, 0);
  1473. for i:= 0 to High (Graph) do
  1474. SetLength (Graph [i], 0);
  1475. SetLength (Graph, 0);
  1476. end;
  1477. function TICLDescriptorCollection.FindDistance (
  1478. AnotherICLDescCol: TICLDescriptorCollection;
  1479. WeightArray: TWeightArray): Extended;
  1480. function IsPow2 (n: Integer): Boolean;
  1481. var
  1482. i, j: Integer;
  1483. begin
  1484. Result:= False;
  1485. j:= 1;
  1486. for i:= 1 to 31 do
  1487. begin
  1488. if n and j<> 0 then
  1489. begin
  1490. if Result then
  1491. begin
  1492. Result:= False;
  1493. Exit;
  1494. end;
  1495. Result:= True;
  1496. end;
  1497. j:= j shl 1;
  1498. end;
  1499. Result:= True;
  1500. end;
  1501. type
  1502. TWeightedGraph= array of array of Extended;
  1503. TLeftSidesMatchedWith= array of Integer;
  1504. TMatchingDetails= record
  1505. LeftSidesMatch: TLeftSidesMatchedWith;
  1506. MatchingSize: Integer;
  1507. end;
  1508. const
  1509. MaxCost= 1.35;//0.65+ 2* 0.35;
  1510. {
  1511. Based on http://www.public.iastate.edu/~ddoty/HungarianAlgorithm.html
  1512. }
  1513. function FindMinWeightedMatching (Graph: TWeightedGraph): TLeftSidesMatchedWith;
  1514. var
  1515. RowCover, ColCover: array of Boolean;
  1516. XSize, YSize: Integer;
  1517. MinWeight: Extended;
  1518. Mask: array of array of Byte;
  1519. procedure Step1;
  1520. var
  1521. i, j: Integer;
  1522. ExPtr: PExtended;
  1523. begin
  1524. for i:= 0 to XSize- 1 do
  1525. begin
  1526. MinWeight:= 1e100;
  1527. ExPtr:= @Graph [i, 0];
  1528. for j:= 0 to YSize- 1 do
  1529. begin
  1530. if ExPtr^< MinWeight then
  1531. MinWeight:= ExPtr^;
  1532. Inc (ExPtr);
  1533. end;
  1534. ExPtr:= @Graph [i, 0];
  1535. for j:= 0 to YSize- 1 do
  1536. begin
  1537. ExPtr^:= Abs (ExPtr^- MinWeight);// To avoid negative weights due !!!
  1538. Inc (ExPtr);
  1539. end;
  1540. end;
  1541. end;
  1542. procedure Step2;
  1543. var
  1544. r, c: Integer;
  1545. ExPtr: PExtended;
  1546. begin
  1547. for r:= 0 to XSize- 1 do
  1548. if not RowCover [r] then
  1549. begin
  1550. ExPtr:= @Graph [r, 0];
  1551. for c:= 0 to YSize- 1 do
  1552. begin
  1553. if (ExPtr^< 1e-10) and (not ColCover [c]) then
  1554. begin
  1555. Mask [r, c]:= 1;
  1556. RowCover [r]:= True;
  1557. ColCover [c]:= True;
  1558. Break;
  1559. end;
  1560. Inc (ExPtr);
  1561. end;
  1562. end;
  1563. FillChar (RowCover [0], XSize* SizeOf (Boolean), 0);
  1564. FillChar (ColCover [0], YSize* SizeOf (Boolean), 0);
  1565. end;
  1566. function Step3: Integer;
  1567. var
  1568. i,

Large files files are truncated, but you can click here to view the full file