Einzelnen Beitrag anzeigen

Cyberstorm

Registriert seit: 23. Okt 2003
159 Beiträge
 
Delphi 2010 Architect
 
#13

Re: Durchschnittsfarbe eines TBitmap via Scanline?

  Alt 22. Jan 2008, 12:30
habe es jetzt ganz anders gemacht, damit ich mich nicht mit resample funktionen rumschlagen muss.
habe mit irfanview + batch mir "mini bmp's" gerechnet und lese diese pixel dann nur noch in den internen record.
ist von der sache her ja das gleiche, nur das ich die durchscnittspunkte auf eine etwas andere weise bekomme.

also ich habe es gerade mit beiden varianten getestet und es geht mit pf24bit und rgbtriple statt quad deutlich schneller.

ca. 160.000 bmp's laden mit einer jeweiligen "miniauflösung" von 30x40
jeden pixel in ein rgb - byte array laden (160.000*30*40 pixel) dauert mit pf32bit ca. 20 Sekunden und mit pf24bit ca. 13.5 Sekunden
(das sind die werte nach dem 2. durchlauf, wenn die festplatte den kram im cache hat und es nur noch um cpu geht.)

nachdem die db auf der platte liegt (knapp 600mb) dauert das einlesen des records übrigens nur ca. 1 sekunde.

nicht wundern, habe das ganze in 4 db files und records aufgeteilt, weil ich später noch was multi threading technisches machen will (quad core und so).
hier mal der komplette source (bilder/bzw. db laden, pixel in den record, auf platte speichern)

für weitere geschwindigkeitsverbesserungen gerade im dokumentiert zeitkritischem bereich währe ich sehr dankbar!
villeicht kann ja jemand die zwei zeilen in assembler umbasteln für einen geschwindigkeitsvorteil?:

Delphi-Quellcode:
unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Jpeg, ExtCtrls, Cyber;

const
  TestPointsX = 40;
  TestPointsY = 30;
  SmallPath = 'F:\kram\pics\small\';

type
  TRGB = record
    Blue: Byte;
    Green: Byte;
    Red: Byte;
  end;

  PRGB = ^TRGB;
  TRefPoints = array[0..TestPointsX-1, 0..TestPointsY-1] of TRGB;

  TPicInfoEntry = record
    FileLocation: string;
    RefPoints: TRefPoints;
  end;

  TCatalogue = record
    PicInfoList: array of TPicInfoEntry;
    Count: Integer;
  end;

  TfrmMain = class(TForm)
    btnOpenDb: TButton;
    procedure btnOpenDbClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    procedure SaveDB(DbId: Byte);
    procedure ReadFromStream(const Stream: TStream; DbId: Byte);
    procedure WriteToStream(const Stream: TStream; DbId: Byte);
    procedure CreateCatalog;
    { Public-Deklarationen }
  end;

var
  frmMain: TfrmMain;
  Catalogs: array[1..4] of TCatalogue;

implementation

{$R *.dfm}

procedure TfrmMain.btnOpenDbClick(Sender: TObject);
var
  s: TFileStream;
  i: Byte;
begin
  if not FileExists(ExtractFilePath(Application.ExeName) + 'PicDb1.dat') then CreateCatalog
  else
   for i:=1 to 4 do
    begin
      s:=TFileStream.Create(ExtractFilePath(Application.ExeName) + 'PicDb' + IntToStr(i) + '.dat', fmOpenRead);
        try
          ReadFromStream(s, i);
        finally
          s.Free;
        end;
    end;
//go on
end;

procedure TfrmMain.ReadFromStream(const Stream: TStream; DbId: Byte);
var
  i: integer;
  BigBuf: Word;
begin
  with Catalogs[DbId] do
    begin
      Stream.Read(Count, SizeOf(Count));
      SetLength(PicInfoList, Count);
      for i:=0 to Count-1 do
       with PicInfoList[i] do
        begin
          Stream.Read(BigBuf, SizeOf(BigBuf));
          SetLength(FileLocation, BigBuf);
          Stream.Read(FileLocation[1], BigBuf);
          Stream.Read(RefPoints, SizeOf(RefPoints));
        end;
    end;
end;

procedure TfrmMain.SaveDB(DbId: Byte);
var
  s: TFileStream;
begin
  s:=TFileStream.Create(ExtractFilePath(Application.ExeName) + 'PicDb' + IntToStr(DbId) + '.dat', fmCreate);
    try
      WriteToStream(s, DbId);
    finally
      s.Free;
    end;
end;

procedure TfrmMain.WriteToStream(const Stream: TStream; DbId: Byte);
var
  i: integer;
  BigBuf: Word;
begin
  with Catalogs[DbId] do
    begin
      Stream.Write(Count, SizeOf(Count));
      for i:=0 to Count-1 do
       with PicInfoList[i] do
        begin
          BigBuf:=Length(FileLocation);
          Stream.Write(BigBuf, SizeOf(BigBuf));
          Stream.Write(FileLocation[1], BigBuf);
          Stream.Write(RefPoints, SizeOf(RefPoints));
        end;
    end;
end;

procedure TfrmMain.CreateCatalog;
var
  i, j, k, l, ActDbNum: Integer;
  P: PRGB;
  B: TBitmap;
  ImageList: TStringList;
begin
  B:=TBitmap.Create;
  ImageList:=TStringList.Create;
    try //dateiliste laden
      ImageList:=ListFilesRecursive(SmallPath, '*.bmp', true);
      for i:=1 to 4 do //4 db files
        begin
          if i<>4 then
            begin
              SetLength(Catalogs[i].PicInfoList, ImageList.Count Div 4);
              Catalogs[i].Count:=ImageList.Count Div 4;
            end
          else
            begin //letzte db file größe richtig setzen, falls nicht gerade durch 4 geteilt worden konnte
              SetLength(Catalogs[4].PicInfoList, (ImageList.Count Div 4) + (ImageList.Count mod 4));
              Catalogs[4].Count:=(ImageList.Count Div 4) + (ImageList.Count mod 4)
            end;
          ActDbNum:=0; //j= dateilistenzähler (muss von 0 bis count durchgehen aber hängt von i ab)
          for j:=( (ImageList.Count Div 4) * (i-1) ) to ( (ImageList.Count Div 4) * (i-1) + (Catalogs[i].Count)-1 ) do
            begin
              B.LoadFromFile(ImageList[j]);
              B.PixelFormat:=pf24bit;
              Catalogs[i].PicInfoList[ActDbNum].FileLocation:=ImageList[j];
              for k:=0 to 29 do
                begin
                  P:=B.ScanLine[k];
                  for l:=0 to 39 do
                    begin //zeitkritischste schleife da am öftesten durchlaufen
                      Catalogs[i].PicInfoList[ActDbNum].RefPoints[l, k]:=P^; //asm?
                      Inc(p); //asm ?
                    end;
                end;
              Inc(ActDbNum);
            end;
          SaveDb(i);
        end;
    finally
      FreeAndNil(B);
      FreeAndNil(ImageList);
    end;
end;

end.
  Mit Zitat antworten Zitat