图像识别中常用的降维的PCA方法。

博客使用最简单的PCA方法,直接求取协方差矩阵C的特征值,介绍了相关定义,如TxxyyArray。还给出了PCA类的代码实现,包括初始化、添加数据、计算特征图像、投影等方法,以及保存和加载文件的函数,还有析构函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里用的是最简单的PCA方法,直接求取协方差矩阵C的特征值,比较慢,具体优化方法件Petland的论文Eigenfaces for recognition。

某些定义我将不再给出,其实很简单,比如TxxyyArray,xx代码维数,比如Single就是一维,Double就是二维,Triple就是三维,yy代表类型,比如Byte、Longint、Integer、Extended等。

unit PCA;

interface

uses
  Math, Windows, SysUtils, Variants, Classes, unitypes, Matrix;

type
  TPCAData = record
    x: TSingleLongintArray;
  end;

  TPCADatabase = record
    Data: array of TPCAData;
    Count: longint;
  end;

  TPCA = class
  private
  public
    Database: TPCADatabase;
    N: longint;
    MeanData: TSingleLongintArray;
    EigenLambda: TSingleExtendedArray;
    EigenVector: TDoubleExtendedArray;
    procedure Init(sN: longint);
    procedure AddToDatabase(Data: TSingleLongintArray);
    procedure CalculateEigenImage;
    procedure CalculateProjection(Data: TSingleLongintArray; var EigenData: TSingleLongintArray; sN: longint);
    function SaveToFile(FileName: string): boolean;
    function LoadFromFile(FileName: string): boolean;
    destructor Destroy; override;
  end;

implementation

procedure TPCA.Init(sN: longint);
begin
  N := sN;
  setlength(EigenLambda, N);
  setlength(EigenVector, N, N);
  setlength(MeanData, N);
end;

procedure TPCA.AddToDatabase(Data: TSingleLongintArray);
var
  i: longint;
begin
  if High(Database.Data) >= Database.Count - 1 then setlength(Database.Data, Database.Count + $10);
  setlength(Database.Data[Database.Count].x, N);
  for i := 0 to N - 1 do
    Database.Data[Database.Count].x[i] := Data[i];
  Inc(Database.Count);
end;

procedure TPCA.CalculateEigenImage;
var
  i, j, fi, fj, TL, s: longint;
  fm: Extended;
  C, A: TDoubleLongintArray;
begin
  setlength(A, N, DataBase.Count);
  setlength(C, N, N);

  for i := 0 to N - 1 do begin
    TL := 0;
    for j := 0 to DataBase.Count - 1 do
      Inc(TL, Database.Data[j].x[i]);
    TL := TL div Database.Count;
    for j := 0 to Database.Count - 1 do
      A[i, j] := Database.Data[j].x[i] - TL;
    MeanData[i] := TL;
  end;

  for i := 0 to N - 1 do
    for j := 0 to N - 1 do begin
      TL := 0;
      for fi := 0 to Database.Count - 1 do
        Inc(TL, A[i, fi] * A[j, fi]);
      C[i, j] := TL div Database.Count;
    end;

  CalculateEigenVV(EigenLambda, EigenVector, C, N, 0.00001);

  for i := 0 to N - 1 do begin
    s := i;
    for j := i + 1 to N - 1 do
      if Abs(EigenLambda[j]) > Abs(EigenLambda[s]) then s := j;
    if s <> i then begin
      fm := EigenLambda[s]; EigenLambda[s] := EigenLambda[i]; EigenLambda[i] := fm;
      for j := 0 to N - 1 do begin
        fm := EigenVector[s, j];
        EigenVector[s, j] := EigenVector[i, j];
        EigenVector[i, j] := fm;
      end;
    end;
  end;
end;

procedure TPCA.CalculateProjection(Data: TSingleLongintArray; var EigenData: TSingleLongintArray; sN: longint);
var
  i, j: longint;
  fm: extended;
begin
  setlength(EigenData, sN);
  for i := 0 to sN - 1 do begin
    fm := 0;
    for j := 0 to N - 1 do
      fm := fm + (Data[j] - MeanData[j]) * EigenVector[i, j];
    EigenData[i] := trunc(fm);
  end;
end;

function TPCA.LoadFromFile(FileName: string): boolean;
var
  i, j: longint;
  ReadStream: TMemoryStream;
begin
  ReadStream := TMemoryStream.Create;
  try
    ReadStream.LoadFromFile(FileName);
    ReadStream.Read(N, sizeof(N));
    setlength(EigenLambda, N);
    setlength(EigenVector, N, N);
    setlength(MeanData, N);
    for i := 0 to N - 1 do
      ReadStream.Read(EigenLambda[i], sizeof(EigenLambda[i]));
    for i := 0 to N - 1 do
      for j := 0 to N - 1 do
        ReadStream.Read(EigenVector[i, j], sizeof(EigenVector[i, j]));
    for i := 0 to N - 1 do
      ReadStream.Read(MeanData[i], sizeof(MeanData[i]));
    Result := true;
  except
    Result := false;
  end;
  ReadStream.Free;
end;

function TPCA.SaveToFile(FileName: string): boolean;
var
  i, j: longint;
  SaveStream: TMemoryStream;
begin
  SaveStream := TMemoryStream.Create;
  try
    SaveStream.Write(N, sizeof(N));
    for i := 0 to N - 1 do
      SaveStream.Write(EigenLambda[i], sizeof(EigenLambda[i]));
    for i := 0 to N - 1 do
      for j := 0 to N - 1 do
        SaveStream.Write(EigenVector[i, j], sizeof(EigenVector[i, j]));
    for i := 0 to N - 1 do
      SaveStream.Write(MeanData[i], sizeof(MeanData[i]));
    SaveStream.SaveToFile(FileName);
    Result := true;
  except
    Result := false;
  end;
  SaveStream.Free;
end;

destructor TPCA.Destroy;
begin
  setlength(Database.Data, 0);
  setlength(EigenLambda, 0);
  setlength(EigenVector, 0);
  setlength(MeanData, 0);
  inherited;
end;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值