PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/General-Purpose-Units/FMLImage.pas

http://my-units.googlecode.com/
Pascal | 2702 lines | 1823 code | 632 blank | 247 comment | 208 complexity | ccf98e5cf867e47fa0daaddbfe2baf81 MD5 | raw file

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

  1. unit FMLImage;
  2. // (*$Define General_Debug*)
  3. // (*$DEFINE REVERSE_MODE*)
  4. //(*$DEFINE DEBUG_MODE*)
  5. interface
  6. uses
  7. Windows, Classes, SysUtils, GeometryUnit,
  8. FeatureUnit, CollectionUnit, ComponentsUnit,
  9. ICLFeatureUnit, Graphics, MyTypes;
  10. const
  11. UnknownPattern: Integer= 9999;
  12. UnImportantPattern: Integer= 9998;
  13. type
  14. EFileNotFound= class (Exception);
  15. EInvalidImage= class (Exception);
  16. TByteFile= file of Byte;
  17. TInputKind= (ikNumeral, ikAlphabet, ikCheckBox, ikPicture, ikHelpBar);
  18. TMyBoolean= (mbTrue, mbFalse, mbUnSet);
  19. TFMLImage= class;
  20. TImageCollection= class;
  21. TImageType= (itMonoChrome, it8bit, it24bit, it32Bit, itNone);
  22. TBlackPixelCountInRow= Integer;
  23. TBlackPixelCountInColumn= Integer;
  24. TBlackPixelCountInRows= array of TBlackPixelCountInRow;
  25. TBlackPixelCountInColumns= array of TBlackPixelCountInColumn;
  26. TComponentCollection= class (TBaseCollection)
  27. private
  28. function GetComponent (Index: Integer): TComponent;
  29. function GetMaxPoint: TPoint;
  30. function GetMinPoint: TPoint;
  31. procedure FindMaxPoint;
  32. procedure FindMinPoint;
  33. procedure SetComponent (Index: Integer; const Value: TComponent);
  34. protected
  35. MinR, MinC, MaxR, MaxC: Integer;
  36. procedure AddComponent(Component: TComponent);
  37. public
  38. property Component [Index: Integer]: TComponent read GetComponent
  39. write SetComponent;
  40. property MinPoint: TPoint read GetMinPoint;
  41. property MaxPoint: TPoint read GetMaxPoint;
  42. constructor Create;
  43. destructor Destroy; override;
  44. function IsExists (r, c: Integer): Boolean;
  45. procedure RemoveInvalidComponents;
  46. procedure Delete (Index: Integer); override;
  47. procedure Add (NewComponent: TComponent);
  48. procedure Clear; override;
  49. end;
  50. TVector = class (TObject)
  51. private
  52. FLength: Extended;
  53. FTeta: Extended;
  54. Fx, Fy: Extended;
  55. function Getx: Extended;
  56. function Gety: Extended;
  57. public
  58. property Len: Extended read FLength;
  59. property Teta: Extended read FTeta;
  60. property x: Extended read Getx;
  61. property y: Extended read Gety;
  62. constructor Create; overload;
  63. constructor Create (r, Teta: Extended); overload;//Teta is in Degree;
  64. constructor CreateXY (x, y: Extended); overload;//Teta is in Degree;
  65. function Add (AnotherVector: TVector): TVector;//Create a new Vector
  66. function Multiply (ASize: Extended): TVector;//Create a new Vector
  67. end;
  68. TArrayofArrayofInt= array of array of Integer;
  69. TColoredImage= class;
  70. TBaseImage= class (TObject)
  71. private
  72. function GetPattern: Integer;
  73. function GetBodyColor (r, c: Integer): Integer;
  74. function GetScanLine (RowIndex: Integer): PInteger;
  75. procedure SetPattern (const Value: Integer);
  76. procedure SetRow (const Value: Integer);
  77. procedure SetColumn (const Value: Integer);
  78. procedure SetImageKind(const Value: TInputKind);
  79. function DoSmooth: TColoredImage;
  80. protected
  81. BLACK, WHITE: Integer;
  82. FBody: TArrayofArrayofInt;
  83. FRow, FColumn, FPattern: Integer;
  84. FImageKind: TInputKind;
  85. FIsBlank: TMyBoolean;
  86. HistogramIsCalced: Boolean;
  87. FImageType: TImageType;
  88. FBlackPixelCountInRows: TBlackPixelCountInRows;
  89. FBlackPixelCountInColumns: TBlackPixelCountInColumns;
  90. BlackPixCount: Integer;
  91. FCenterOfMass: TPoint;
  92. function NewInstance: TBaseImage; virtual; abstract;
  93. public
  94. function GetBlackColor: Integer; virtual; abstract;
  95. function GetWhiteColor: Integer; virtual; abstract;
  96. property ImageKind: TInputKind read FImageKind;
  97. (*ImageType determines how the image is stored in the FBody array*)
  98. property ImageType: TImageType read FImageType;
  99. property Pattern: Integer read GetPattern write SetPattern;
  100. property Row: Integer read FRow write SetRow;
  101. property Column: Integer read FColumn write SetColumn;
  102. property Kind: TInputKind read FImageKind write SetImageKind;
  103. property IsBlank: TMyBoolean read FIsBlank write FIsBlank;
  104. (*returns the value of pixel located in r and c*)
  105. property Body [r, c: Integer]: Integer read GetBodyColor;
  106. (*returns a pointer to the first integer in the rowindex'th row*)
  107. property ScanLine [RowIndex: Integer]: PInteger read GetScanLine;
  108. constructor Create (ImageType: TImageType= itMonoChrome);overload;
  109. destructor Destroy; override;
  110. procedure SaveAsBitmap (FileName: string);
  111. procedure LoadBitMap (FileName: String); overload;
  112. procedure LoadBitMap (Bitmap: TBitmap; Pattern: Integer= 9999);overload; virtual; abstract;
  113. function GetAsBitmap: TBitmap; virtual; abstract;
  114. (*Note than, FCenterofMass holds the sum of x and y of black pixels,
  115. not the centerofmass. Use this function to get COM.
  116. The ReCalc can be used to force the function to recalculates the
  117. COM*)
  118. function GetCenterOfMass (Recalc: Boolean= False): TPoint;
  119. (*Returns the FBody array which stored the pixels of body.
  120. It can be used for fast work with pixels*)
  121. function GetBodyArray: TArrayofArrayofInt;
  122. (*Returns the ration of the black pixel in the column ColIndex by the BotRow- TopRow+ 1*)
  123. function IsHorizentalLineBlack (RowIndex: Integer; LeftCol, RightCol: Integer;
  124. Heigth: Integer= 1): Real;
  125. function IsVerticalLineBlack (ColIndex: Integer; TopRow, BotRow: Integer;
  126. Width: Integer= 1): Real;
  127. (*
  128. Copies a rectange from the image.
  129. *)
  130. function CopyPixels (TL, BR: TPoint): TBaseImage; virtual;
  131. (*Saves the image as text file.
  132. If the PrintBodyValue is false then it prints out the characters W and B.
  133. Otherwise, it prints the value of FBody.
  134. !!Note that PrintBodyValue= False only works for images whose imagetype is itMonochrome*)
  135. procedure SaveAsText (FileName: String; PrintBodyValue: Boolean= False);
  136. (*Smoothes the image*)
  137. function Smooth (RepeatCount: Integer): TColoredImage;
  138. function ApplySobelAndGetGradiantIn8Dir: T8DirGradiantFeature;
  139. function GetSampleGradiantFor8Dir: TSampleGradiantIn8Dir;
  140. (*Returns the number of black pixel in the image. Current implementation
  141. doesn't look at Recalc and always re-calculate the value*)
  142. function BlackPixCountInImage (ReCalc: Boolean= False): Integer;
  143. end;
  144. TFMLImage= class (TBaseImage)
  145. private
  146. function RemoveColors(AColor: Integer): TFMLImage;
  147. procedure LoadPhotoCopiedImage (Bitmap: TBitmap); overload;
  148. function DeleteImage (NoiseColor: TColor; NoiseThr: Integer): TFMLImage;
  149. function FindAllComponents: TComponentCollection;
  150. function DoSmooth1: TFMLImage;
  151. function DoSmooth2: TFMLImage;
  152. protected
  153. function NewInstance: TBaseImage; override;
  154. public
  155. function GetBlackColor: Integer; override;
  156. function GetWhiteColor: Integer; override;
  157. (*Create an image whose black pixel are stored in PixelCollection.
  158. Note!! this constructor crops the image*)
  159. constructor Create (PixelCollection: TComponent);overload;
  160. (*Create an image whose black pixel are stored in ComponentCollection (which is a collection of PixelCollection)*)
  161. constructor Create (ComponentCollection: TComponentCollection);overload;
  162. (*Create an image whose black pixel are stored in a BlackPoints (which is a collection of TPoint)*)
  163. constructor Create (BlackPoints: TPointCollection);overload;
  164. (*Saves the image in the file whose handle in OutputFile by FML format*)
  165. procedure SaveInFMLFile (var OutputFile: TByteFile); overload;
  166. (*Saves the image in the stream whose handle in OutputStream by FML format*)
  167. procedure SaveInFMLStream (OutputStream: TFileStream); overload;
  168. (*Saves the image in the filename by FML Format*)
  169. procedure SaveInFMLFile (Filename: String); overload;
  170. (*Load an image which is filtered by photoshop "Photocopy" fileter.
  171. The pixels of transformation of an image under this filter will be
  172. 0 or 255.*)
  173. procedure LoadPhotoCopiedImage (FileName: string); overload;
  174. procedure LoadBitMap (Bitmap: TBitmap; Pattern: Integer= 9999);override;
  175. procedure LoadFromFMLFile (var InputFile: TByteFile); overload;
  176. procedure LoadFromFMLStream (InputStream: TFileStream);
  177. procedure LoadFromBMLFile (var InputFile: TByteFile); overload;
  178. procedure LoadFromBMLStream (InputStream: TFileStream);
  179. function GetAsBitmap: TBitmap; override;
  180. (*Adds the pixels in ImaePixels Component to the image (Self) and
  181. returns the self*)
  182. function MixImage (ImagePixels: TComponent): TFMLImage;
  183. (*Sets the pixel in location r and c to black
  184. NOTE: This procedures do not perform range checking*)
  185. procedure SetPixelColor (r, c: Integer; NewColor: Integer); overload;
  186. procedure SetPixelColor (Point: TPoint; NewColor: Integer); overload;
  187. (*Clear the r'th row of the image
  188. NOTE: This procedure works when the ImageType is itMonochrome*)
  189. procedure ClearLine (r: Integer);
  190. (*Clear the c'th column of the image
  191. NOTE: This procedure works when the ImageType is itMonochrome*)
  192. procedure ClearColumn (c: Integer);
  193. (*Counts the black pixel in each row of image and returns them in an array.
  194. NOTE:: It works for Monochrome and 8 bit images. For 8 bit images, it calculates
  195. a threshold and ...*)
  196. function BlackPixelCountInRows: TBlackPixelCountInRows;
  197. function BlackPixelCountInColumns: TBlackPixelCountInColumns;
  198. (*
  199. This function finds all connected components () in the image using a BFS.
  200. TopLeft and BotRight indicate where the search area is and the boolean
  201. UseDialateBefExt indicates that if the image should be dialated or not.
  202. *)
  203. function FindAllComponentsInBox (TopLeft, BottomRight: TPoint): TComponentCollection;
  204. (*
  205. NOTE:: This procedure is not implemented Yet!!
  206. *)
  207. function FindAllComponentsHavePointInBox (TopLeft, BottomRight: TPoint): TComponentCollection;
  208. (*Dialtes the image and returns Self*)
  209. function Dilate (Mask: TArrayofArrayofInt): TFMLImage;
  210. (*Erodes the image and returns Self*)
  211. function Erode (Mask: TArrayofArrayofInt): TFMLImage;
  212. (*Apply Opening operator on the image and returns Self*)
  213. function Opening (Mask: TArrayofArrayofInt): TFMLImage;
  214. (*Apply Opening operator on the image and returns Self*)
  215. function Closing (Mask: TArrayofArrayofInt): TFMLImage;
  216. (*Apply Opening operator on the image and returns Self*)
  217. function HitAndMiss (Mask: TArrayofArrayofInt): TFMLImage;
  218. (*Thicks the image and returns Self*)
  219. function ThickTheImage: TFMLImage;
  220. (*Thins the image and returns Self*)
  221. function ThinTheImage: TFMLImage;
  222. (*returns an estimate for the pen width*)
  223. function ImageThickness: Integer;
  224. (*Crops the image and returns self*)
  225. function Crop: TFMLImage;
  226. (*
  227. NOTE:: This procedure is not implemented Yet!!
  228. *)
  229. procedure Write (PrintToFile: Boolean= False; FileName: String= '');
  230. (*
  231. NOTE:: This procedure is not implemented Yet!!
  232. *)
  233. procedure Add (Component: TComponent);
  234. (*
  235. Copies the rows in the range TopRowIndex and BottomRowIndex, inclusivly.
  236. *)
  237. function CopyRows (TopRowIndex, BottomRowIndex: Integer): TFMLImage;
  238. (*
  239. Rotates the image, and return the rotated image.
  240. NOTE:: This function only works with it8bit images.
  241. *)
  242. function Rotate (AngleInDeg: Integer): TFMLImage;
  243. (*Resizes the image
  244. NOTE:: These functions are <B>not suitable</B> when one wants to shrink the image *)
  245. function Resize (NewRow, NewColumn: Integer): TFMLImage;
  246. (*Resizes the image*)
  247. function NewResize (NewRow, NewColumn: Integer; SaveAspectRatio: Boolean= False): TFMLImage;
  248. function GetComponentByOnePoint (APoint: TPoint): TComponent;
  249. function ExtractFeatures (NewSize: Integer; SmoothDegree: Integer;
  250. NumberOfMasks: Integer= 5): TFeatureVectorBasedOnGradiant; virtual;
  251. function ExtractFreemanFeature: TFreemanFeature; virtual;
  252. (*Deletes a row from image*)
  253. procedure DeleteRow (Index: Integer);
  254. procedure DeleteRowsInRange (TopIndex, BotIndex: Integer);
  255. (*NOTE:: This function does not update the center of mass*)
  256. procedure DeleteColumnsInRange (TopIndex, BotIndex: Integer);
  257. (*Deletes the rows who have more than Percentage black pixel in them*)
  258. procedure DeleteVerticalBlackLine (Percentage: Extended= 1/2);
  259. procedure DeleteHorizentalBlackLine (Percentage: Extended= 1/2);
  260. (*Reverse the color of an FML Image, flip the WHITE pixels to BLACK and
  261. vice versa, and returns Self*)
  262. function ReverseColor: TFMLImage;
  263. destructor Destroy; override;
  264. function Copy (TL, BR: TPoint): TFMLImage;
  265. end;
  266. TColoredImage= class (TBaseImage)
  267. private
  268. procedure CalculateHistogram;
  269. function GetHistogram(Color: Integer): Integer;
  270. protected
  271. FHistogram: array [0..255] of Integer;
  272. function NewInstance: TBaseImage; override;
  273. public
  274. (*Histogram returns the number of occurence of each color. It only works when ImageType= it8bit*)
  275. property Histogram [Color: Integer]: Integer read GetHistogram;
  276. (*This function returns a new bitmap in Monochrome style, but doesn't change
  277. the image itself*)
  278. function ConvertToGrayScale: TColoredImage;
  279. (*Find a threshold for convertToBinary. It works for the images whose ImageType is it8Bit, only*)
  280. function GrayThreshold: Integer;
  281. function ConvertToBinary: TFMLImage;
  282. procedure LoadBitmap (Bitmap: TBitmap; Pattern: Integer= 9999); override;
  283. (*Returns a 8 or 24 bits Bitmap image*)
  284. function GetAsBitmap: TBitmap; override;
  285. constructor Create (ImageType: TImageType);
  286. function Copy (TL, BR: TPoint): TColoredImage;
  287. function GetBlackColor: Integer; override;
  288. function GetWhiteColor: Integer; override;
  289. end;
  290. TImageCollection= class (TBaseCollection)
  291. private
  292. function GetImageNumber: Integer;
  293. function GetImage (Index: Integer): TFMLImage;
  294. public
  295. property ImageNumber: Integer read GetImageNumber;
  296. property Image [Index: Integer]: TFMLImage read GetImage;
  297. procedure LoadFromFMLFile (FileName: string);
  298. procedure LoadFromBMLFile (FileName: string);
  299. procedure SaveToFile (FileName: string);
  300. procedure SaveFilesAsBitmap (BaseFileName: String);
  301. procedure AddImage (Image: TFMLImage);
  302. procedure AddImageCollection (ImageCollection: TimageCollection);
  303. procedure Dilate (Mask: TArrayofArrayofInt);
  304. constructor Create; overload;
  305. function ExtractAllImagesFeatures (NewSize, SmoothDegree: Integer): TFeatureVectorBasedOnGradiantCollection;
  306. function GetAllWithPattern (PatternIndex: Integer): TImageCollection;
  307. end;
  308. implementation
  309. uses
  310. {Borland.Vcl.Controls, System.Xml.XPath, }
  311. Math, ExceptionUnit, TypInfo, VectorUnit, JPeg;
  312. type
  313. EFMLImageNotInitialized= class (Exception);
  314. ERangeCheckError= class (Exception);
  315. TArrArrInt= array of array of Integer;
  316. TArrInt= array of Integer;
  317. function MyArcTan (x, y: Extended): Extended;//Result is in Degree.
  318. begin
  319. if abs (x)< 1e-10 then
  320. begin
  321. if y< 0 then
  322. Result:= 3* Pi/ 2.0
  323. else
  324. Result:= Pi/ 2.0;
  325. end
  326. else
  327. Result:= ArcTan2 (x, y);
  328. end;
  329. function TFMLImage.GetAsBitmap: TBitmap;
  330. var
  331. // Temp: Byte;
  332. r, c: Integer;
  333. PixPtr: PInteger;
  334. RowPtr: PByte;
  335. begin
  336. Result:= TBitmap.Create;
  337. if IsBlank= mbTrue then
  338. begin
  339. Result.Width:= 1;
  340. Result.Height:= 1;
  341. Result.Monochrome:= True;
  342. Exit;
  343. end;
  344. if ImageType= itMonoChrome then
  345. begin
  346. Result.PixelFormat:= pf1bit;
  347. Result.Monochrome:= True;
  348. Result.Height:= FRow;
  349. Result.Width:= FColumn;
  350. for r:= 0 to Row- 1 do
  351. begin
  352. RowPtr:= Result.ScanLine [r];
  353. PixPtr:= @FBody [r, 0];
  354. RowPtr^:= 0;
  355. c:= 0;
  356. while c< FColumn do
  357. begin
  358. RowPtr^:= (1- PixPtr^) shl (7- c mod 8)+ RowPtr^;
  359. Inc (PixPtr);
  360. Inc (c);
  361. if c mod 8= 0 then
  362. begin
  363. Inc (RowPtr);
  364. RowPtr^:= 0;
  365. end;
  366. end;
  367. end;
  368. end
  369. else
  370. raise EInvalidImage.Create ('MonoChrome Image is needed');
  371. end;
  372. {
  373. procedure TFMLImage.Load (var InputHandle: &File);
  374. var
  375. r, c: Integer;
  376. b1, b2: Byte;
  377. begin
  378. Read (InputHandle, b1, b2);
  379. Pattern:= b1+ b2 shl 8;
  380. b1:= Row mod 256;
  381. b2:= Row div 256;
  382. Write (InputHandle, b1, b2);
  383. b1:= Column mod 256;
  384. b2:= Column div 256;
  385. Write (InputHandle, b1, b2);
  386. for r:= 0 to Row- 1 do
  387. for c:= 0 to Column do
  388. begin
  389. b1:= FBody [r][c] mod 256;
  390. b2:= FBody [r][c] div 256;
  391. Write (InputHandle, b1, b2);
  392. end;
  393. b1:= 255;
  394. b2:= 255;
  395. Write (InputHandle, b1, b2);
  396. end;
  397. }
  398. procedure TFMLImage.LoadBitMap (Bitmap: TBitmap; Pattern: Integer);
  399. var
  400. r, c, i: Integer;
  401. PixPtr: PInteger;
  402. RowPtr: PByte;
  403. cIndex: Integer;
  404. begin
  405. Row:= Bitmap.Height;
  406. Column:= Bitmap.Width;
  407. if FCenterOfMass<> nil then
  408. FCenterOfMass.Free;
  409. FCenterOfMass:= TPoint.Create (0, 0);
  410. BlackPixCount:= 0;
  411. if Bitmap.PixelFormat= pf1bit then
  412. begin
  413. FImageType:= itMonoChrome;
  414. for r:= 0 to FRow- 1 do
  415. begin
  416. RowPtr:= Bitmap.ScanLine [r];
  417. PixPtr:= ScanLine [r];
  418. cIndex:= 0;
  419. for c:= 0 to (FColumn- 1) div 8- 1 do
  420. begin
  421. for i:= 0 to 7 do
  422. begin
  423. (*$IFNDEF REVERSE_MODE*)
  424. if (RowPtr^ shr (7- i)) and 1= 1 then
  425. begin
  426. PixPtr^:= BLACK;
  427. FCenterOfMass.Move (r, cIndex);
  428. Inc (BlackPixCount);
  429. end
  430. else
  431. PixPtr^:= WHITE;
  432. (*$ELSE*)
  433. if (RowPtr^ shr (7- i)) and 1= 0 then
  434. begin
  435. PixPtr^:= BLACK;
  436. FCenterOfMass.Move (r, cIndex);
  437. Inc (BlackPixCount);
  438. end
  439. else
  440. PixPtr^:= WHITE;
  441. (*$ENDIF*)
  442. Inc (cIndex);
  443. Inc (PixPtr);
  444. end;
  445. Inc (RowPtr);
  446. end;
  447. for i:= 0 to (FColumn- 1) mod 8 do
  448. begin
  449. (*$IFNDEF REVERSE_MODE*)
  450. if (RowPtr^ shr (7- i)) and 1= 1 then
  451. begin
  452. PixPtr^:= BLACK;
  453. FCenterOfMass.Move (r, cIndex);
  454. Inc (BlackPixCount);
  455. end
  456. else
  457. PixPtr^:= WHITE;
  458. (*$ELSE*)
  459. if (RowPtr^ shr (7- i)) and 1= 0 then
  460. begin
  461. PixPtr^:= BLACK;
  462. FCenterOfMass.Move (r, cIndex);
  463. Inc (BlackPixCount);
  464. end
  465. else
  466. PixPtr^:= WHITE;
  467. (*$ENDIF*)
  468. Inc (cIndex);
  469. Inc (PixPtr);
  470. end;
  471. end;
  472. end
  473. else
  474. raise Exception.Create ('Invalid filetype!');
  475. FPattern:= Pattern;
  476. end;
  477. { TImageCollection }
  478. procedure TImageCollection.AddImage (Image: TFMLImage);
  479. begin
  480. inherited Add (Image);
  481. end;
  482. constructor TImageCollection.Create;
  483. begin
  484. inherited;
  485. end;
  486. procedure TImageCollection.Dilate (Mask: TArrayofArrayofInt);
  487. var
  488. i: Integer;
  489. Ptr: PObject;
  490. begin
  491. Ptr:= GetPointerToFirst;
  492. for i:= 1 to Size do
  493. begin
  494. TFMLImage (Ptr^).Dilate (Mask);
  495. Inc (Ptr);
  496. end;
  497. end;
  498. function TImageCollection.ExtractAllImagesFeatures
  499. (NewSize, SmoothDegree: Integer): TFeatureVectorBasedOnGradiantCollection;
  500. var
  501. i: Integer;
  502. begin
  503. Result:= TFeatureVectorBasedOnGradiantCollection.Create;
  504. for i:= 0 to ImageNumber- 1 do
  505. Result.Add (Image [i].ExtractFeatures (NewSize, SmoothDegree));
  506. end;
  507. function TImageCollection.GetImage (Index: Integer): TFMLImage;
  508. begin
  509. Result:= Member [Index] as TFMLImage;
  510. end;
  511. function TImageCollection.GetImageNumber: Integer;
  512. begin
  513. Result:= Size;
  514. end;
  515. procedure TImageCollection.SaveToFile (FileName: string);
  516. var
  517. i: Integer;
  518. OutputStream: TFileStream;
  519. b1, b2: Byte;
  520. begin
  521. OutputStream:= TFileStream.Create (FileName, fmCreate);
  522. {
  523. AssignFile (OutputFile, FileName);
  524. Rewrite (OutputFile);
  525. }
  526. b1:= ImageNumber and 255;
  527. b2:= ImageNumber shr 8;
  528. OutputStream.Write (b1, 1);
  529. OutputStream.Write (b2, 1);
  530. for i:= 0 to ImageNumber- 1 do
  531. Image [i].SaveInFMLStream (OutputStream);
  532. OutputStream.Free;
  533. end;
  534. procedure TFMLImage.Write (PrintToFile: Boolean; FileName: String);
  535. {var
  536. OutputFile: TextFile;
  537. i, j: Integer;
  538. }
  539. begin
  540. raise Exception.Create ('Not Implemented Yet!');
  541. {
  542. if PrintToFile then
  543. begin
  544. AssignFile (OutputFile, FileName);
  545. Rewrite (OutputFile);
  546. for i:= 0 to Row- 1 do
  547. begin
  548. for j:= 0 to Column- 1 do
  549. Borland.Delphi.System.Write (OutputFile, Body [i, j]);
  550. Borland.Delphi.System.Writeln (OutputFile);
  551. end;
  552. Close (OutputFile);
  553. end;
  554. }
  555. end;
  556. function TFMLImage.Dilate (Mask: TArrayofArrayofInt): TFMLImage;
  557. var
  558. NewBody: TArrayofArrayofInt;
  559. BodyPtr: PInteger;
  560. r, c,
  561. ir, ic,
  562. MaskRow, MaskCol: Integer;
  563. begin
  564. Result:= Self;
  565. if IsBlank= mbTrue then
  566. Exit;
  567. MaskRow:= High (Mask);
  568. MaskCol:= High (Mask [0]);
  569. SetLength (NewBody, Row+ MaskRow);
  570. for r:= 0 to Row+ MaskRow- 1 do
  571. begin
  572. SetLength (NewBody [r], Column+ MaskCol);
  573. FillChar (NewBody [r, 0], SizeOf (NewBody [r]), WHITE);
  574. end;
  575. for r:= 0 to Row- 1 do
  576. begin
  577. BodyPtr:= ScanLine [r];
  578. for c:= 0 to Column- 1 do
  579. begin
  580. if BodyPtr^= BLACK then
  581. for ir:= 0 to MaskRow- 1 do
  582. for ic:= 0 to MaskCol- 1 do
  583. if Mask [ic, ic]= BLACK then
  584. NewBody [r+ ir, c+ ic]:= BLACK;
  585. Inc (BodyPtr);
  586. end;
  587. end;
  588. for r:= 0 to FRow- 1 do
  589. Move (NewBody [r][0], FBody [r][0], SizeOf (Integer)* FColumn);
  590. for r:= 0 to FRow+ MaskRow- 1 do
  591. SetLength (NewBody [r], 0);
  592. SetLength (NewBody, 0);
  593. end;
  594. function TFMLImage.Erode (Mask: TArrayofArrayofInt): TFMLImage;
  595. var
  596. BodyPtr: PInteger;
  597. NewBody: TArrayofArrayofInt;
  598. r, c,
  599. ir, ic,
  600. MaskRow, MaskCol: Integer;
  601. begin
  602. MaskRow:= Length (Mask);
  603. MaskCol:= Length (Mask [0]);
  604. SetLength (NewBody, Row);
  605. for r:= 0 to Row- 1 do
  606. begin
  607. SetLength (NewBody [r], FColumn);
  608. Move (FBody [r, 0], NewBody [r, 0], SizeOf (Integer)* FColumn);
  609. end;
  610. for r:= 0 to Row- MaskRow- 1 do
  611. begin
  612. BodyPtr:= ScanLine [r];
  613. for c:= 0 to Column- MaskCol- 1 do
  614. begin
  615. if BodyPtr^= WHITE then
  616. for ir:= 0 to MaskRow- 1 do
  617. for ic:= 0 to MaskCol- 1 do
  618. if Mask [ir, ic]= BLACK then
  619. NewBody [r+ ir, c+ ic]:= WHITE;
  620. Inc (BodyPtr);
  621. end;
  622. end;
  623. for r:= 0 to Row- 1 do
  624. SetLength (FBody [r], 0);
  625. SetLength (FBody, 0);
  626. FBody:= NewBody;
  627. Result:= Self;
  628. end;
  629. function TFMLImage.DeleteImage (NoiseColor: TColor; NoiseThr: Integer): TFMLImage;
  630. begin
  631. raise ENotImplemented.Create ('TFMLImage.DeleteImage');
  632. end;
  633. constructor TFMLImage.Create (PixelCollection: TComponent);
  634. var
  635. r, c,
  636. MinR, MinC,
  637. i: Integer;
  638. MinPoint, MaxPoint: TPoint;
  639. Pixel: TMyPixel;
  640. Ptr: PInteger;
  641. begin
  642. inherited Create;
  643. FImageType:= itMonoChrome;
  644. HistogramIsCalced:= False;
  645. FRow:= -1; FColumn:= -1; FPattern:= -1;
  646. FIsBlank:= mbUnSet;
  647. MinPoint:= PixelCollection.GetMinimum;
  648. MaxPoint:= PixelCollection.GetMaximum;
  649. MinC:= MinPoint.c; MinR:= MinPoint.r;
  650. Row:= MaxPoint.r- MinPoint.r+ 1;
  651. Column:= MaxPoint.c- MinPoint.c+ 1;
  652. for r:= 0 to Row- 1 do
  653. begin
  654. Ptr:= @FBody [r, 0];
  655. for c:= 0 to Column- 1 do
  656. begin
  657. Ptr^:= WHITE;
  658. Inc (Ptr);
  659. end;
  660. end;
  661. if PixelCollection.Count= 0 then
  662. FIsBlank:= mbTrue
  663. else
  664. begin
  665. FCenterOfMass:= TPoint.Create (0, 0);
  666. for i:= 0 to PixelCollection.Count- 1 do
  667. begin
  668. Pixel:= PixelCollection.GetPixel (i);
  669. FBody [Pixel.Location.r- MinR, Pixel.Location.c- MinC]:= BLACK;
  670. FCenterOfMass.Move (Pixel.Location);
  671. FCenterOfMass.Move (-MinR, -MinC);
  672. end;
  673. end;
  674. FPattern:= 0;
  675. // Self.SaveInFMLFile ('C:\ImageFromComp.FML');//??!!
  676. MinPoint.Free;
  677. MaxPoint.Free;
  678. end;
  679. constructor TFMLImage.Create (ComponentCollection: TComponentCollection);
  680. var
  681. PixelCollection: TComponent;
  682. MinC, MinR,
  683. i, j: Integer;
  684. MinPoint, MaxPoint: TPoint;
  685. Pixel: TMyPixel;
  686. begin
  687. inherited Create;
  688. FImageType:= itMonoChrome;
  689. HistogramIsCalced:= False;
  690. FRow:= -1; FColumn:= -1; FPattern:= UnImportantPattern;
  691. if ComponentCollection.Size= 0 then
  692. begin
  693. FIsBlank:= mbTrue;
  694. Exit;
  695. end
  696. else
  697. FIsBlank:= mbFalse;
  698. MinPoint:= ComponentCollection.MinPoint;
  699. MaxPoint:= ComponentCollection.MaxPoint;
  700. MinC:= MinPoint.c; MinR:= MinPoint.r;
  701. Row:= MaxPoint.r- MinPoint.r+ 1;
  702. Column:= MaxPoint.c- MinPoint.c+ 1;
  703. FCenterOfMass:= TPoint.Create (0, 0);
  704. for i:= 0 to ComponentCollection.Size- 1 do
  705. begin
  706. PixelCollection:= ComponentCollection.Component [i];
  707. for j:= 0 to PixelCollection.Count- 1 do
  708. begin
  709. Pixel:= PixelCollection.GetPixel (j);
  710. FBody [Pixel.Location.r- MinR, Pixel.Location.c- MinC]:= BLACK;
  711. FCenterOfMass.Move (Pixel.Location);
  712. end;
  713. end;
  714. MinPoint.Free;
  715. MaxPoint.Free;
  716. end;
  717. procedure TImageCollection.SaveFilesAsBitmap (BaseFileName: String);
  718. var
  719. i: Integer;
  720. Ptr: PObject;
  721. begin
  722. Ptr:= GetPointerToFirst;
  723. for i:= 1 to Size do
  724. begin
  725. TFMLImage (Ptr^).SaveAsBitmap (BaseFileName+ IntToStr (i)+ '.bmp');
  726. Inc (Ptr);
  727. end;
  728. end;
  729. procedure TImageCollection.LoadFromFMLFile (FileName: string);
  730. var
  731. i: Integer;
  732. b1, b2: Byte;
  733. ImageNo: Integer;
  734. NewImage: TFMLImage;
  735. InputStream: TFileStream;
  736. Ptr: PObject;
  737. begin
  738. if not FileExists (FileName) then
  739. raise EFileNotFound.Create (FileName);
  740. InputStream:= TFileStream.Create (FileName, fmOpenRead);
  741. InputStream.Read (b1, 1);
  742. InputStream.Read (b2, 1);
  743. ImageNo:= b1+ 256* b2;
  744. Allocate (ImageNo);
  745. Ptr:= GetPointerToFirst;
  746. for i:= 1 to ImageNo do
  747. begin
  748. NewImage:= TFMLImage.Create;
  749. NewImage.LoadFromFMLStream (InputStream);
  750. Ptr^:= NewImage;
  751. Inc (Ptr);
  752. end;
  753. InputStream.Free;
  754. end;
  755. function TImageCollection.GetAllWithPattern (
  756. PatternIndex: Integer): TImageCollection;
  757. var
  758. i: Integer;
  759. begin
  760. Result:= TImageCollection.Create;
  761. for i:= 0 to Size- 1 do
  762. if Image [i].Pattern= PatternIndex then
  763. Result.AddImage (Image [i]);
  764. end;
  765. procedure TFMLImage.Add (Component: TComponent);
  766. begin
  767. raise ENotImplemented.Create ('TFMLImage.Add (Component: TComponent)');
  768. {
  769. if FRow< Component.MaxX then
  770. for i:= 0 to Component.Count- 1 do
  771. begin
  772. end;
  773. }
  774. end;
  775. procedure TFMLImage.SetPixelColor (r, c: Integer; NewColor: Integer);
  776. begin
  777. FBody [r, c]:= NewColor;
  778. end;
  779. procedure TFMLImage.SetPixelColor (Point: TPoint; NewColor: Integer);
  780. begin
  781. FBody [Point.r, Point.c]:= NewColor;
  782. end;
  783. function TFMLImage.FindAllComponentsInBox (TopLeft, BottomRight: TPoint): TComponentCollection;
  784. (*$J+*)
  785. const
  786. P1: TPoint= nil;
  787. P2: TPoint= nil;
  788. (*$J-*)
  789. var
  790. NewImage: TFMLImage;
  791. begin
  792. if P1= nil then
  793. begin
  794. P1:= TPoint.Create;
  795. P2:= TPoint.Create;
  796. end;
  797. P1.r:= Max (0, TopLeft.r);
  798. P1.c:= Max (0, TopLeft.c);
  799. P2.r:= Min (Row- 1, BottomRight.r);
  800. P2.c:= Min (Column- 1, BottomRight.c);
  801. NewImage:= Self.Copy (P1, P2);
  802. (*$IFDEF DEBUG_MODE*)
  803. NewImage.SaveInFMLFile ('C:\Temp.FML');
  804. (*$ENDIF*)
  805. Result:= NewImage.FindAllComponents;
  806. NewImage.Free;
  807. end;
  808. function TFMLImage.FindAllComponents: TComponentCollection;
  809. var
  810. i, j, Turn,
  811. MaxCompIndex,
  812. r, c: Integer;
  813. PixPtr, LeftPixPtr,
  814. UpPixPtr, UpperLeftPixPtr,
  815. UpperRightPixPtr: PInteger;
  816. CurRowPtr,
  817. CurLeftPtr, LastRowPtr, LastLeftRowPtr,
  818. LastRightRowPtr
  819. : PInteger;
  820. ActiveComponent: TComponent;
  821. IsCopied: array of Boolean;
  822. LastRow, CurRow: TIntegerArray;
  823. CompPtr: PObject;
  824. ToBeReplacedComponent,
  825. ToBeRemovedComponent: TComponent;
  826. (*$J+*)
  827. const
  828. Rows: array [0..1] of TIntegerArray= (nil, nil);
  829. PtrArray: array [0..3] of ^PInteger= (nil, nil, nil, nil);
  830. (*$J-*)
  831. begin
  832. if Length (Rows [0])< FColumn then
  833. begin
  834. SetLength (Rows [0], FColumn);
  835. SetLength (Rows [1], FColumn);
  836. end;
  837. Result:= TComponentCollection.Create;
  838. FillChar (Rows [0, 0], SizeOf (Integer)* Length (Rows [0]), 255);
  839. FillChar (Rows [1, 0], SizeOf (Integer)* Length (Rows [1]), 255);
  840. PixPtr:= @FBody [0, 0];
  841. ActiveComponent:= nil;
  842. Turn:= 0;
  843. CurRow:= Rows [Turn];
  844. c:= 0;
  845. //c is 0 and r is also 0
  846. if PixPtr^= BLACK then
  847. begin
  848. ActiveComponent:= TComponent.Create (Result.Size);
  849. ActiveComponent.Add (0, c);
  850. Result.Add (ActiveComponent);
  851. CurRow [c]:= Result.Size- 1;
  852. end;
  853. for c:= 1 to FColumn- 1 do
  854. begin
  855. LeftPixPtr:= PixPtr;
  856. Inc (PixPtr);
  857. if PixPtr^= BLACK then
  858. begin
  859. if LeftPixPtr^= BLACK then
  860. begin
  861. ActiveComponent.Add (0, c);
  862. CurRow [c]:= CurRow [c- 1];
  863. end
  864. else
  865. begin
  866. ActiveComponent:= TComponent.Create (Result.Size);
  867. ActiveComponent.Add (0, c);
  868. Result.Add (ActiveComponent);
  869. CurRow [c]:= Result.Size- 1;
  870. end;
  871. end
  872. else
  873. CurRow [c]:= -1;
  874. end;
  875. LastRow:= nil;
  876. PtrArray [0]:= @CurLeftPtr;
  877. PtrArray [1]:= @LastRowPtr;
  878. PtrArray [2]:= @LastLeftRowPtr;
  879. PtrArray [3]:= @LastRightRowPtr;
  880. for r:= 1 to FRow- 1 do
  881. begin
  882. Turn:= Turn xor 1;
  883. LastRow:= CurRow;
  884. CurRow:= Rows [Turn];
  885. PixPtr:= ScanLine [r];
  886. UpPixPtr:= ScanLine [r- 1];
  887. CurRowPtr:= @CurRow [0];
  888. LastRowPtr:= @LastRow [0];
  889. if PixPtr^= BLACK then
  890. begin
  891. if UpPixPtr^= Black then
  892. begin
  893. Result.Component [LastRowPtr^].Add (r, 0);
  894. CurRowPtr^:= LastRowPtr^;
  895. end
  896. else
  897. begin
  898. ActiveComponent:= TComponent.Create (Result.Size);
  899. ActiveComponent.Add (r, 0);
  900. Result.Add (ActiveComponent);
  901. CurRowPtr^:= Result.Size- 1;
  902. end;
  903. end;
  904. for c:= 1 to FColumn- 2 do
  905. begin
  906. // LeftPixPtr:= PixPtr;
  907. // UpperLeftPixPtr:= UpPixPtr;
  908. Inc (PixPtr);
  909. // Inc (UpPixPtr);
  910. CurLeftPtr:= CurRowPtr;
  911. LastLeftRowPtr:= LastRowPtr;
  912. Inc (CurRowPtr);
  913. Inc (LastRowPtr);
  914. LastRightRowPtr:= LastRowPtr;
  915. Inc (LastRightRowPtr);
  916. if PixPtr^= BLACK then
  917. begin
  918. MaxCompIndex:= Max (Max (CurLeftPtr^, LastRowPtr^),
  919. Max (LastLeftRowPtr^, LastRightRowPtr^));
  920. if MaxCompIndex= -1 then// All visited adjanced are white
  921. begin
  922. ActiveComponent:= TComponent.Create (Result.Size);
  923. ActiveComponent.Add (r, c);
  924. Result.AddComponent (ActiveComponent);
  925. CurRowPtr^:= Result.Size- 1;
  926. end
  927. else
  928. begin
  929. Result.Component [MaxCompIndex].Add (r, c);
  930. CurRowPtr^:= MaxCompIndex;
  931. for i:= 0 to 3 do
  932. if (PtrArray [i]^^<> -1) and (PtrArray [i]^^<> MaxCompIndex) then
  933. begin
  934. Result.Component [MaxCompIndex].Merge (Result.Component [PtrArray [i]^^]);
  935. ToBeReplacedComponent:= Result.Component [MaxCompIndex];
  936. ToBeRemovedComponent:= Result.Component [PtrArray [i]^^];
  937. if ToBeReplacedComponent.ID<> ToBeRemovedComponent.ID then
  938. begin
  939. CompPtr:= Result.GetPointerToFirst;
  940. for j:= 1 to Result.Size do
  941. begin
  942. if CompPtr^= ToBeRemovedComponent then
  943. CompPtr^:= ToBeReplacedComponent;
  944. Inc (CompPtr);
  945. end;
  946. ToBeRemovedComponent.Free;
  947. end;
  948. end;
  949. end;
  950. end
  951. else
  952. CurRowPtr^:= -1;
  953. end;
  954. c:= FColumn- 1;
  955. // LeftPixPtr:= PixPtr;
  956. // UpperLeftPixPtr:= UpPixPtr;
  957. Inc (PixPtr);
  958. // Inc (UpPixPtr);
  959. CurLeftPtr:= CurRowPtr;
  960. LastLeftRowPtr:= LastRowPtr;
  961. Inc (CurRowPtr);
  962. Inc (LastRowPtr);
  963. if PixPtr^= BLACK then
  964. begin
  965. MaxCompIndex:= Max (Max (CurLeftPtr^, LastRowPtr^),
  966. LastLeftRowPtr^);
  967. if MaxCompIndex= -1 then// All visited adjanced are white
  968. begin
  969. ActiveComponent:= TComponent.Create (Result.Size);
  970. ActiveComponent.Add (r, c);
  971. Result.AddComponent (ActiveComponent);
  972. CurRowPtr^:= Result.Size- 1;
  973. end
  974. else
  975. begin
  976. Result.Component [MaxCompIndex].Add (r, c);
  977. CurRowPtr^:= MaxCompIndex;
  978. for i:= 0 to 2 do
  979. if (PtrArray [i]^^<> -1) and (PtrArray [i]^^<> MaxCompIndex) then
  980. begin
  981. Result.Component [MaxCompIndex].Merge (Result.Component [PtrArray [i]^^]);
  982. ToBeReplacedComponent:= Result.Component [MaxCompIndex];
  983. ToBeRemovedComponent:= Result.Component [PtrArray [i]^^];
  984. if ToBeReplacedComponent.ID<> ToBeRemovedComponent.ID then
  985. begin
  986. CompPtr:= Result.GetPointerToFirst;
  987. for j:= 1 to Result.Size do
  988. begin
  989. if CompPtr^= ToBeRemovedComponent then
  990. CompPtr^:= ToBeReplacedComponent;
  991. Inc (CompPtr);
  992. end;
  993. ToBeRemovedComponent.Free;
  994. end;
  995. end;
  996. end;
  997. end;
  998. end;
  999. if Length (IsCopied)< Result.Size+ 1 then
  1000. SetLength (IsCopied, Result.Size+ 1);
  1001. FillChar (IsCopied [0], SizeOf (IsCopied), 0);
  1002. CompPtr:= Result.GetPointerToFirst;
  1003. j:= 0;
  1004. for i:= 1 to Result.Size do
  1005. begin
  1006. if not IsCopied [TComponent (CompPtr^).ID] then
  1007. begin
  1008. Result.Component [j]:= TComponent (CompPtr^);
  1009. Inc (j);
  1010. // WriteLn (i, ' Saved: ', Result.FComponents [i].ID);
  1011. IsCopied [TComponent (CompPtr^).ID]:= True;
  1012. end;
  1013. Inc (CompPtr);
  1014. end;
  1015. CompPtr:= Result.GetPointerToFirst;
  1016. Inc (CompPtr, j);
  1017. for i:= j to Result.Size- 1 do
  1018. begin
  1019. CompPtr^:= nil;
  1020. Inc (CompPtr);
  1021. end;
  1022. Result.Allocate (j);
  1023. end;
  1024. procedure TBaseImage.SaveAsText (FileName: String; PrintBodyValue: Boolean);
  1025. var
  1026. r, c: Integer;
  1027. OutputFile: TextFile;
  1028. begin
  1029. AssignFile (OutputFile, FileName);
  1030. Rewrite (OutputFile);
  1031. if FImageType= itMonoChrome then
  1032. for r:= 0 to FRow- 1 do
  1033. begin
  1034. for c:= 0 to FColumn- 1 do
  1035. if FBody [r, c]= WHITE then
  1036. if PrintBodyValue then
  1037. System.Write (OutputFile, ' (', FBody [r, c], ')')
  1038. else
  1039. System.Write (OutputFile, 'W')
  1040. else
  1041. if PrintBodyValue then
  1042. System.Write (OutputFile, ' (', FBody [r, c], ')')
  1043. else
  1044. System.Write (OutputFile, 'B');
  1045. Writeln (OutputFile);
  1046. end
  1047. else
  1048. if FImageType= it8bit then
  1049. for r:= 0 to FRow- 1 do
  1050. begin
  1051. for c:= 0 to FColumn- 1 do
  1052. System.Write (OutputFile, ' (', FBody [r, c], ')');
  1053. Writeln (OutputFile);
  1054. end
  1055. else
  1056. raise EInvalidImage.Create ('The image format should be monochrome');
  1057. CloseFile (OutputFile);
  1058. end;
  1059. function TFMLImage.FindAllComponentsHavePointInBox (TopLeft, BottomRight: TPoint):
  1060. TComponentCollection;
  1061. begin
  1062. raise ENotImplemented.Create ('FindAllComponentsHavePointInBox (');
  1063. end;
  1064. function TFMLImage.ExtractFeatures (NewSize: Integer; SmoothDegree: Integer;
  1065. NumberOfMasks: Integer): TFeatureVectorBasedOnGradiant;
  1066. var
  1067. ResizedImage: TFMLImage;
  1068. SmoothedImage: TColoredImage;
  1069. GradiantIn8Dir: T8DirGradiantFeature;
  1070. begin
  1071. ResizedImage:= Self.NewResize (NewSize, NewSize, True);
  1072. (*$IFDEF DEBUG_MODE*)
  1073. ResizedImage.SaveAsText ('C:\Resized.00.txt');
  1074. (*$ENDIF DEBUG_MODE*)
  1075. SmoothedImage:= ResizedImage.Smooth (SmoothDegree);
  1076. (*$IFDEF DEBUG_MODE*)
  1077. SmoothedImage.ConvertToBinary.SaveAsText ('C:\Smoothed.00.txt');
  1078. SmoothedImage.SaveAsBitmap ('C:\SmoothedImage.bmp');
  1079. (*$ENDIF DEBUG_MODE*)
  1080. GradiantIn8Dir:= SmoothedImage.ApplySobelAndGetGradiantIn8Dir;
  1081. Result:= GradiantIn8Dir.SampleGradiant (NumberOfMasks);
  1082. GradiantIn8Dir.Free;
  1083. SmoothedImage.Free;
  1084. ResizedImage.Free;
  1085. end;
  1086. function TBaseImage.Smooth (RepeatCount: Integer): TColoredImage;
  1087. var
  1088. TempImage: TColoredImage;
  1089. i: Integer;
  1090. begin
  1091. if 0< RepeatCount then
  1092. begin
  1093. TempImage:= Self.DoSmooth;
  1094. Result:= TempImage;
  1095. for i:= 2 to RepeatCount do
  1096. begin
  1097. (*$IFDEF DEBUG_MODE*)
  1098. TempImage.ConvertToBinary.SaveAsText ('R'+ IntToStr (i- 1)+ '.txt');
  1099. (*$ENDIF DEBUG_MODE*)
  1100. TempImage:= Result.DoSmooth;
  1101. Result.Free;
  1102. Result:= TempImage;
  1103. end;
  1104. end
  1105. else
  1106. Result:= nil;
  1107. end;
  1108. function TFMLImage.Resize (NewRow, NewColumn: Integer): TFMLImage;
  1109. var
  1110. ix, iy: Integer;
  1111. xc, yc: Double;
  1112. xprimc, yprimc: Double;
  1113. m10, m00, m01: Int64;
  1114. Alpha, Beta,
  1115. L: Double;
  1116. r, c: Integer;
  1117. Dummy: Integer;
  1118. RowPtr: PInteger;
  1119. begin
  1120. m10:= 0; m00:= 0; m01:= 0;
  1121. for r:= 0 to FRow- 1 do
  1122. begin
  1123. RowPtr:= Self.ScanLine [r];
  1124. for c:= 0 to FColumn- 1 do
  1125. begin
  1126. dummy:= RowPtr^;
  1127. Inc (m00, dummy);
  1128. Inc (m10, c* dummy);
  1129. Inc (m01, r* dummy);
  1130. Inc (RowPtr);
  1131. end;
  1132. end;
  1133. xc:= m10/ m00;
  1134. yc:= m01/ m00;
  1135. xprimc:= FColumn/ 2.0;
  1136. yprimc:= FRow/ 2.0;
  1137. L:= Math.Max (Row, Column);
  1138. if L= FRow then
  1139. begin
  1140. Beta:= NewRow/ L;
  1141. Alpha:= Beta;
  1142. end
  1143. else
  1144. begin
  1145. Alpha:= NewColumn/ L;
  1146. Beta:= Alpha;
  1147. end;
  1148. Result:= TFMLImage.Create;
  1149. Result.FImageType:= Self.ImageType;
  1150. Result.Column:= NewColumn;
  1151. Result.Row:= NewRow;
  1152. for r:= 0 to NewRow- 1 do
  1153. begin
  1154. RowPtr:= Result.ScanLine [r];
  1155. for c:= 0 to NewColumn- 1 do
  1156. begin
  1157. ix:= Round ( (c- xprimc)/ Alpha+ xc);
  1158. iy:= Round ( (r- yprimc)/ Beta+ yc);
  1159. if (ix< FColumn) and (0<= ix ) and (iy< FRow) and (0<= iy) then
  1160. RowPtr^:= FBody [iy, ix]
  1161. else
  1162. RowPtr^:= WHITE;
  1163. Inc (RowPtr);
  1164. end;
  1165. end;
  1166. end;
  1167. (*
  1168. This function generate a new TFMLImage.
  1169. The value of each pixel of the new FMLImage, is equal to the average of all members of it, in the original Image
  1170. The argument RepeatCount told how many times it should be applied.
  1171. ------------------------------------------------------------------
  1172. The DP approach is to simply set
  1173. Result.Pixels [r, c]:=
  1174. (Result.Pixels [r- 1, c- 1]+ Result.Pixels [r- 1, c]+...+ Result.Pixels [r+ 1, c+ 1]) div 9;
  1175. The Exectution time of this approach is 9*Row* Column.
  1176. In this function, I implemented the folowing approach.
  1177. At first step, set
  1178. TempResult.Pixels [r, c]:=
  1179. Sum of all pixles in rectangle from (0, 0) to (r, c).
  1180. So,
  1181. TempResult.Pixels [r, c]:= TempResult.Pixels [r- 1, c]+
  1182. TempResult.Pixels [r, c- 1]- TempResult.Pixels [r- 1, c- 1]+ Source [r, c];
  1183. At second step, calculate the real value of each pixel:
  1184. Result.Pixels [r, c]:= TempResult.Pixels [r+ 1, c+ 1]+
  1185. Result.Pixels [r- 1, c- 1]- Result.Pixels [r- 1, c+ 1]
  1186. - Result.Pixels [r+ 1, c- 1];
  1187. *)
  1188. function TBaseImage.DoSmooth: TColoredImage;
  1189. const
  1190. {$J+}
  1191. SumOfPixels: array of array of Integer= nil;
  1192. {The SumOfPixels is an static variable}
  1193. {$J-}
  1194. var
  1195. r, c: Integer;
  1196. SourcePtr,//
  1197. TargetPtr//,
  1198. // LastPixTPtr,//Pixel [r, c- 1]
  1199. // LastRowTPtr,//Pixel [r- 1, c]
  1200. // LastRowCelTPtr//Pixel [r- 1, c- 1]
  1201. : PInteger;
  1202. procedure AllocateSumOfPixels;
  1203. var
  1204. r: Integer;
  1205. begin
  1206. if SumOfPixels= nil then
  1207. SetLength (SumOfPixels, Row+ 4);
  1208. if Length (SumOfPixels)< Row+ 4 then
  1209. begin
  1210. for r:= 0 to High (SumOfPixels) do
  1211. SetLength (SumOfPixels [r], 0);
  1212. SetLength (SumOfPixels, 0);
  1213. SetLength (SumOfPixels, Row+ 4);
  1214. for r:= 0 to Row+ 3 do
  1215. SetLength (SumOfPixels [r], Column+ 4);
  1216. end;
  1217. if Length (SumOfPixels [0])< Column+ 4 then
  1218. for r:= 0 to High (SumOfPixels) do
  1219. SetLength (SumOfPixels [r], Column+ 4);
  1220. for r:= 0 to Row+ 3 do
  1221. FillChar (SumOfPixels [r][0], SizeOf (SumOfPixels [r]), 0);
  1222. end;
  1223. var
  1224. ActiveSumOfPixelsPtr,// Points to SUmofPixels [r, c]
  1225. R_1CSumOfPixelPtr, // Points to SUmofPixels [r- 1, c]
  1226. RC_1SumOfPixelPtr, // Points to SUmofPixels [r, c- 1]
  1227. R_1C_1SumOfPixelPtr,// Points to SUmofPixels [r- 1, c- 1]
  1228. R__1C__1SumOfPixelPtr, // Points to SUmofPixels [r+ 1, c+ 1]
  1229. R_2C_2SumOfPixelPtr, // Points to SUmofPixels [r- 2, c- 2]
  1230. R_2C__1SumOfPixelPtr,// Points to SUmofPixels [r- 2, c+ 1]
  1231. R__1C_2SumOfPixelPtr// Points to SUmofPixels [r+ 1, c- 2]
  1232. : PInteger;
  1233. MainImageType: TImageType;
  1234. begin
  1235. MainImageType:= Self.ImageType;
  1236. if Self.ImageType= itMonoChrome then
  1237. begin
  1238. for r:= 0 to FRow- 1 do
  1239. begin
  1240. SourcePtr:= Self.ScanLine [r];
  1241. for c:= 0 to FColumn- 1 do
  1242. begin
  1243. SourcePtr^:= (1- SourcePtr^)* 255;
  1244. Inc (SourcePtr);
  1245. end;
  1246. end;
  1247. FImageType:= it8bit;
  1248. end;
  1249. (*$IFDEF DEBUG_MODE*)
  1250. Self.SaveAsText ('C:\Image.txt', True);
  1251. (*$ENDIF*)
  1252. AllocateSumOfPixels;
  1253. Result:= TColoredImage.Create (it8bit);
  1254. Result.FImageType:= it8bit;
  1255. Result.FPattern:= FPattern;
  1256. Result.Column:= Column;
  1257. Result.Row:= Row;
  1258. {Step 1: Calculating SumofPixels array }
  1259. {putting white pixel around the main image and
  1260. SumOfPixels [r, c] holds the sum of the pixels [i,j]
  1261. for which i<= r and j<= c.
  1262. 0<= r<= Row+1, 0<= c<= Column+1,
  1263. }
  1264. {Calculating SumOfPixels for 0's Row}
  1265. ActiveSumOfPixelsPtr:= @SumOfPixels [0][0];
  1266. ActiveSumOfPixelsPtr^:= 255;
  1267. RC_1SumOfPixelPtr:= ActiveSumOfPixelsPtr;
  1268. Inc (ActiveSumOfPixelsPtr);
  1269. for c:= 1 to FColumn+ 3 do
  1270. begin
  1271. ActiveSumOfPixelsPtr^:=
  1272. RC_1SumOfPixelPtr^+ 255;
  1273. Inc (ActiveSumOfPixelsPtr);
  1274. Inc (RC_1SumOfPixelPtr);
  1275. end;
  1276. ActiveSumOfPixelsPtr:= @SumOfPixels [1][0];
  1277. R_1CSumOfPixelPtr:= @SumOfPixels [0][0];
  1278. for c:= 0 to FColumn+ 3 do
  1279. begin
  1280. ActiveSumOfPixelsPtr^:= 2* R_1CSumOfPixelPtr^;
  1281. Inc (ActiveSumOfPixelsPtr);
  1282. Inc (R_1CSumOfPixelPtr);
  1283. end;
  1284. for r:= 2 to FRow+ 1 do
  1285. begin
  1286. {Calculating SumOfPixels for r's Row}
  1287. ActiveSumOfPixelsPtr:= @SumOfPixels [r][0];
  1288. ActiveSumOfPixelsPtr^:= (r+ 1)* 255;
  1289. ActiveSumOfPixelsPtr:= @SumOfPixels [r][1];
  1290. ActiveSumOfPixelsPtr^:= 2* (r+ 1)* 255;
  1291. R_1CSumOfPixelPtr:= @SumOfPixels [r- 1][2];
  1292. R_1C_1SumOfPixelPtr:= @SumOfPixels [r- 1][1];
  1293. RC_1SumOfPixelPtr:= @SumOfPixels [r][1];
  1294. ActiveSumOfPixelsPtr:= @SumOfPixels [r][2];
  1295. SourcePtr:= ScanLine [r- 2];
  1296. for c:= 2 to Column+ 1 do
  1297. begin
  1298. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1299. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ SourcePtr^;
  1300. Inc (ActiveSumOfPixelsPtr);
  1301. Inc (R_1CSumOfPixelPtr);
  1302. Inc (R_1C_1SumOfPixelPtr);
  1303. Inc (RC_1SumOfPixelPtr);
  1304. Inc (SourcePtr);
  1305. end;
  1306. //SumOfPixels [r][FCol+ 2]
  1307. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1308. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ 255;
  1309. Inc (ActiveSumOfPixelsPtr);
  1310. Inc (R_1CSumOfPixelPtr);
  1311. Inc (R_1C_1SumOfPixelPtr);
  1312. Inc (RC_1SumOfPixelPtr);
  1313. //SumOfPixels [r][FCol+ 3]
  1314. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1315. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ 255;
  1316. end;
  1317. {Calculating SumOfPixels for FRow+2's Row}
  1318. for r:= FRow+ 2 to FRow+ 3 do
  1319. begin
  1320. ActiveSumOfPixelsPtr:= @SumOfPixels [r][0];
  1321. ActiveSumOfPixelsPtr^:= (r+ 1)* 255;
  1322. Inc (ActiveSumOfPixelsPtr);
  1323. ActiveSumOfPixelsPtr^:= 2* (r+ 1)* 255;
  1324. R_1CSumOfPixelPtr:= @SumOfPixels [r- 1][2];
  1325. R_1C_1SumOfPixelPtr:= @SumOfPixels [r- 1][1];
  1326. RC_1SumOfPixelPtr:= @SumOfPixels [r][1];
  1327. ActiveSumOfPixelsPtr:= @SumOfPixels [r][2];
  1328. for c:= 2 to Column+ 1 do
  1329. begin
  1330. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1331. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ 255;
  1332. Inc (ActiveSumOfPixelsPtr);
  1333. Inc (R_1CSumOfPixelPtr);
  1334. Inc (R_1C_1SumOfPixelPtr);
  1335. Inc (RC_1SumOfPixelPtr);
  1336. end;
  1337. //SumOfPixels [r][FCol+ 2]
  1338. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1339. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ 255;
  1340. Inc (ActiveSumOfPixelsPtr);
  1341. Inc (R_1CSumOfPixelPtr);
  1342. Inc (R_1C_1SumOfPixelPtr);
  1343. Inc (RC_1SumOfPixelPtr);
  1344. //SumOfPixels [r][FCol+ 3]
  1345. ActiveSumOfPixelsPtr^:= R_1CSumOfPixelPtr^+
  1346. RC_1SumOfPixelPtr^- R_1C_1SumOfPixelPtr^+ 255;
  1347. end;
  1348. (*$IFDEF DEBUG_MODE*)
  1349. AssignFile (Output, 'C:\Output.txt');
  1350. Rewrite (Output);
  1351. for r:= 0 to FRow+ 1 do
  1352. begin
  1353. for c:= 0 to FColumn+ 1 do
  1354. System.Write (SumOfPixels [r][c], ' ');
  1355. WriteLn;
  1356. end;
  1357. CloseFile (Output);
  1358. (*$ENDIF*)
  1359. {Step 2: Calculating Results Value }
  1360. for r:= 2 to FRow+ 1 do
  1361. begin
  1362. TargetPtr:= Result.ScanLine [r- 2];
  1363. // Result.FBody [r- 1, 0]:= SumOfPixels [r- 1,
  1364. R__1C__1SumOfPixelPtr:= @SumOfPixels [r+ 1][3];
  1365. R__1C_2SumOfPixelPtr:= @SumOfPixels [r+ 1][0];
  1366. R_2C__1SumOfPixelPtr:= @SumOfPixels [r- 2][3];
  1367. R_2C_2SumOfPixelPtr:= @SumOfPixels [r- 2][0];
  1368. for c:= 2 to FColumn+ 1 do
  1369. begin
  1370. TargetPtr^:= (R__1C__1SumOfPixelPtr^+
  1371. R_2C_2SumOfPixelPtr^-
  1372. R_2C__1SumOfPixelPtr^-
  1373. R__1C_2SumOfPixelPtr^) div 9;
  1374. Inc (R__1C__1SumOfPixelPtr);
  1375. Inc (R__1C_2SumOfPixelPtr);
  1376. Inc (R_2C__1SumOfPixelPtr);
  1377. Inc (R_2C_2SumOfPixelPtr);
  1378. Inc (TargetPtr);
  1379. end;
  1380. end;
  1381. (*$IFDEF DEBUG_MODE*)
  1382. Result.SaveAsText ('C:\SmoothedImage.txt', True);
  1383. (*$ENDIF*)
  1384. if MainImageType= itMonoChrome then
  1385. begin
  1386. for r:= 0 to FRow- 1 do
  1387. begin
  1388. SourcePtr:= Self.ScanLine [r];
  1389. for c:= 0 to FColumn- 1 do
  1390. begin
  1391. SourcePtr^:= 1- SourcePtr^ div 255;
  1392. Inc (SourcePtr);
  1393. end;
  1394. end;
  1395. FImageType:= itMonoChrome;
  1396. end;
  1397. end;
  1398. function TFMLImage.DoSmooth2: TFMLImage;
  1399. var
  1400. S, i, j, k,
  1401. r, c: Integer;
  1402. begin
  1403. Result:= TFMLImage.Create;
  1404. Result.Column:= Column;
  1405. Result.Row:= Row;
  1406. for r:= 0 to Row- 1 do
  1407. for c:= 0 to Column- 1 do
  1408. begin
  1409. k:= 9;
  1410. S:= 0;
  1411. for i:= -1 to 1 do
  1412. for j:= -1 to 1 do
  1413. try
  1414. S:= S+ Body [r+ i, c+ j];
  1415. except
  1416. on E: ERangeCheckError do
  1417. Dec (k);
  1418. end;
  1419. if S div 2< k then
  1420. Result.FBody [r, c]:= WHITE
  1421. else
  1422. Result.FBody [r, c]:= BLACK;
  1423. end;
  1424. end;
  1425. function TFMLImage.DoSmooth1: TFMLImage;
  1426. var
  1427. r, c: Integer;
  1428. SourcePtr,//
  1429. TargetPtr//Pixel [r, c]
  1430. : PInteger;
  1431. Count, ExcepCounter,
  1432. Sum: Integer;
  1433. TempResult: TFMLImage;
  1434. begin
  1435. Result:= TFMLImage.Create;
  1436. TempResult:= TFMLImage.Create;
  1437. Result.Column:= Column;
  1438. Result.Row:= Row;
  1439. TempResult.Row:= Row+ 2;
  1440. TempResult.Column:= Column+ 2;
  1441. // Self.SaveAsText ('BeforeSmooth.txt');
  1442. {Step 1: Calculating TempResult's Values }
  1443. for r:= 0 to Row- 1 do
  1444. begin
  1445. for c:= 0 to Column- 1 do
  1446. begin
  1447. Sum:= Self.FBody [r, c];
  1448. Count:= 9;
  1449. ExcepCounter:= 0;
  1450. try
  1451. Inc (Sum, TempResult.Body [r- 1, c]);
  1452. except
  1453. Dec (Count, 3);
  1454. Inc (ExcepCounter);
  1455. end;
  1456. try
  1457. Inc (Sum, TempResult.Body [r, c- 1]);
  1458. except
  1459. Dec (Count, 3);
  1460. if ExcepCounter<> 0 then
  1461. Inc (Count);
  1462. end;
  1463. try
  1464. Dec (Sum, TempResult.Body [r- 1, c- 1]);
  1465. except
  1466. on E: ERangeCheckError do;
  1467. end;
  1468. if Sum< Count div 2 then
  1469. TempResult.FBody [r, c]:= BLACK
  1470. else
  1471. TempResult.FBody [r, c]:= WHITE;
  1472. end;
  1473. end;
  1474. for r:= 0 to Row do
  1475. TempResult.FBody [r, Column+ 1]:=
  1476. TempResult.FBody [r, Column];
  1477. TargetPtr:= TempResult.ScanLine [Row+ 1];
  1478. SourcePtr:= TempResult.ScanLine [Row];
  1479. for c:= 0 to Column+ 1 do
  1480. begin
  1481. TargetPtr^:= SourcePtr^;
  1482. Inc (TargetPtr);
  1483. Inc (SourcePtr);
  1484. end;
  1485. // TempResult.SaveAsText ('TempResult.txt', True);
  1486. {Step 2: Calculating Results Value }
  1487. r:= 0;
  1488. TargetPtr:= Result.ScanLine [r];
  1489. TargetPtr^:= TempResult.FBody [r+ 2, 2];
  1490. if TargetPtr^< 3 then
  1491. TargetPtr^:= BLACK
  1492. else
  1493. TargetPtr^:= WHITE;
  1494. Inc (TargetPtr);
  1495. for c:= 1 to Column- 1 do
  1496. begin
  1497. TargetPtr^:= TempResult.FBody [r+ 2, c+ 2]
  1498. - TempResult.FBody [r+ 2, c- 1];
  1499. if TargetPtr^< 3 then
  1500. TargetPtr^:= BLACK
  1501. else
  1502. TargetPtr^:= WHITE;
  1503. Inc (TargetPtr);
  1504. end;
  1505. for r:= 1 to Row- 1 do
  1506. begin
  1507. TargetPtr:= Result.ScanLine [r];
  1508. TargetPtr^:= TempResult.FBody [r+ 2, 2]
  1509. - TempResult.FBody [r- 1, 2];
  1510. if r= Row- 1 then
  1511. begin
  1512. if TargetPtr^< 3 then
  1513. TargetPtr^:= BLACK

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