écriture lecture ram ????

Résolu
cs_TouTSpeed Messages postés 72 Date d'inscription jeudi 5 janvier 2006 Statut Membre Dernière intervention 30 août 2007 - 3 nov. 2006 à 22:20
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 - 7 nov. 2006 à 04:00
bonsoir à tous.

Je suis en train de retranscrire un programme écrit en language c et en delphi !! ( en fait je lance un programme que j'ai écrit en C afin de traiter une opération que je ne savais faire en delphi  à l'époque ! )

le programme en question capture une image toutes les x secondes , l'enregistre au format jpg puis la lit, et en fonction des infos recueillit je détermine la position d'un objet d'une couleur définit auparavant !

le programme fonctionnait parfaitement avec le petit prog en C ! avec capture toutes les demi seconde ce qui me convenait or en delphi je ne peux descendre en dessous de 1 seconde car  l'affichage sacade et ensuite il y a probleme de temps de lecture/écriture !

y a t il un moyen d'enregistrer l'image dan sla ram a un eadresse précise et de lire cette image a la meme adresse évidemment !!

en espérant avoir été assez clair

je vous en remercie d'avance !

( le programme d edépart permmettait a une webcam de suivre l'objet en question !

voir vidéo ->  ici ( BE Projet 2006 DUT GEII )

le programme dirige la cam et l'on observe alors que l'objet est toujours au centre de l'écran !

encore merci

31 réponses

f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
5 nov. 2006 à 18:21
Cirec qui utiliser Canvas.Pixel .... #sig# ... tu me decois la, nostalgie de debutant ou ?

voila un exemple concret :

sur la fiche :
une TListbox,
un boutton,
un opendialog.

Type
  // pixel
  TPixel24bit = array[0..2] of byte;
 
  // ligne de l'image (pixel*width)
  pScanLine = ^TScanLine;
  // width max de l'image 16384 pixels
  TScanLine = array[0..16383] of TPixel24Bit;

// convertion TPixel24bit vers integer ([RR][GG][BB] > 00BBGGRR)
function Pixel24ToInt(const P24 : TPixel24bit): Integer;
asm
  mov eax, dword ptr [ebp+$08];
  rol eax, $08;
  xor al, al;
  ror eax, $08;
end;

// Analyse de l'image et affichage des infos dans un TStrings

procedure GetBitmapInfo(const BMPFileName : string; Strings : TStrings);
var  X,Y        : Integer;
     BMP        : TBitmap;
     pData      : pScanline;
     TFS        : TFileStream;
     BMPHeader  : TBITMAPFILEHEADER;
     BMPInfo    : TBITMAPINFO;
begin
  // si le fichier n'existe pas
  if not FileExists(BMPFileName) then
     // on sort
     exit;

  // on efface la liste
  Strings.Clear;

  // et on la prepare pour des modifications
  Strings.BeginUpdate;

  // on crée un stream fichier, pour economiser la memoire
  TFS := TFileStream.Create(BMPFileName, fmOpenRead);
  try
    // on lit les infos
    TFS.ReadBuffer(BMPHeader,SizeOf(TBITMAPFILEHEADER));
    TFS.ReadBuffer(BMPInfo,SizeOf(TBITMAPINFO));

    // on recupere le nom de l'image
    Strings.Add(ExtractFileName(BMPFileName));

    // on recupere d'autres infos
    with BMPInfo.bmiHeader do begin
         Strings.Add(format('Width x Height  : %dx%d',[biWidth, biHeight]));
         Strings.Add(       'Pixel format    : '+IntToStr(biBitCount)+' bits');
         Strings.Add(       'Image Size      : '+IntToStr((biWidth*biHeight*biBitCount) div 8));
         Strings.Add('');
    end;
  finally
    // on libere le stream
    TFS.Free;

    // on mets a jours l'affichage de la liste
    Strings.EndUpdate;
  end;

  // on reprepare la liste pour les modif
  Strings.BeginUpdate;

  // on crée un objet bitmap
  BMP := TBitmap.Create;
  try
    // on charge l'image
    BMP.LoadFromFile(BMPFileName);
    // on regle son format a 24bits
    BMP.PixelFormat := pf24bit;

    // on prepare une entete de tableau (utiliser la police "Courier New")
    Strings.Add('R   | G   | B   | Color     | X    | Y');
    Strings.Add('----+-----+-----+-----------+------+------');
   
    // enfin on scan l'image
    for y := 0 to BMP.height-1 do begin
        // on recupere tout les pixels de la ligne Y
        pData := BMP.ScanLine[y];
       
        // on scan la ligne
        for x := 0 to BMP.Width-1 do
            // on affiche les données du pixel

            // Rouge, Vert, Bleu, couleur delphi, coordonées X,Y du pixel
            Strings.Add(format('%3.d | %3.d | %3.d | $%.8x | %4.d | %4.d',
                        [pData[x,0], pData[x,1], pData[x,2], Pixel24ToInt(pData[x]), x, y]));

        // a chaque fin de boucle on rafraichis la liste
        Strings.EndUpdate;
        Strings.BeginUpdate;
    end;
  finally
    // enfin on libere le bitmap
    BMP.Free;
    // puis on mets fin aux modifications de la liste
    Strings.EndUpdate;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // si on ouvre une image
  if OpenDialog1.Execute then
     // on recuper analyse l'image et on affiche les données dans listbox1
     GetBitmapInfo(OpenDialog1.FileName, ListBox1.Items);
end;

0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
5 nov. 2006 à 23:57
"tu me decois la, nostalgie de debutant ou ?"

La grande différence entre ton code et le miens c'est que tu charge deux fois le fichier pour extraire les informations ?

Une fois avec TFileStream pour lire le Header
Et une fois avec TBitmap pour les Pixels (ScanLine)

alors que moi je lis le tout en une fois depuis un TMemoryStream et jusqu'à preuve du contraire ScanLine n'existe pas dans TMemoryStream

cela dit, oui, je dois être un peu nostalgique ... ça me rappel ma jeunesse
 
@+
Cirec

0
cs_TouTSpeed Messages postés 72 Date d'inscription jeudi 5 janvier 2006 Statut Membre Dernière intervention 30 août 2007
6 nov. 2006 à 01:47
Encore merci à tous ça marche du tonnerre je posterai ma source d'ici quelque temps quand elle sera épurée , puis commenter , ( source de base ) et bien sur avec les fonctions de reconnaissance ( plus tard en mise à jour ) !

Encore merci à tous !
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 nov. 2006 à 02:07
...J'ai suivi du coin de l'oeil et j'ai appris bcp, bcp de choses.
Avec Cirec et Foxi, ça risque pas de rester en rade longtemps, de toute façon...

Merci pour ce topic, ToutSpeed,
Merci à tous.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
6 nov. 2006 à 14:14
Voilà ...
Pour faire plaisir à F0xi

voici une autre méthode avec pseudo ScanLine qui, je le rappel, contrairement a celle de F0xi ne charge qu'une seul fois le fichier.

En effet, je charge le fichier dans un TMemoryStream, je lis le Header et les Infos et du même fichier j'extrais
les données de l'image que je reconstitue directement dans un TBitmap et pour finir j'affiche le résultat et quelques données

Le code peut encore être optimisé mais je préfère le laisser tel quel dans un souci de compréhension.
Je ne commente que ce qui a changé ...

Type
    TRGBRec = record
    R,G,B : Byte;
  end;

procedure TForm1.Button2Click(Sender: TObject);
Var
  MS         : TMemoryStream;
  FileHeader : TBITMAPFILEHEADER;
  Info       : TBITMAPINFO;
  NB         : Byte;
  DataSize   : Cardinal;
  aData      : Array Of TRGBRec;
  X,Y        : Integer;
  BMP        : TBitmap;

begin
  NB : = 3;
   MS := TMemoryStream.Create;
   With MS do
   Try
     LoadFromFile('fcsambug.BMP');
     ReadBuffer(FileHeader, SizeOf(TBITMAPFILEHEADER));
     ReadBuffer(Info, SizeOf(TBITMAPINFO));
     If Info.bmiHeader.biBitCount = 32 Then NB := 4;
     DataSize := (Info.bmiHeader.biWidth * Info.bmiHeader.biHeight) * NB;
     MS.Position := FileHeader.bfOffBits;
     If Info.bmiHeader.biBitCount = 24 Then
     Begin
       BMP : = TBitmap.Create;
       Try
         BMP.PixelFormat :=   pf24Bit;
         BMP.Width       :=  Info.bmiHeader.biWidth;
         BMP.Height      :=  Info.bmiHeader.biHeight;
         // on fixe la taille de notre pseudo ScanLine
         SetLength(aData, BMP.Width);
         //  Verticalement les données sont inversées
         // elles commencent par le bas de l'image

         For Y : = BMP.Height - 1 DownTo 0 Do
         Begin
         // Lecture par Bloc comme avec ScanLine
           MS.readBuffer(Pointer(aData)^, BMP.Width * 3);
           For X := 0 to BMP.Width - 1 Do
         // Replace les données dans le bon ordre (BGR au lieu de RGB)
             BMP.Canvas.Pixels[X,  Y] : = RGB(aData[X].B,
             aData[X].G, aData[X].R);
         End;
       Finally
         Self.Canvas.Draw(0,0,BMP);
         BMP.Free;
       End;
     End;
   Finally
     Free;
   End;
   With Info.bmiHeader, Memo1.Lines do
   Begin
     Clear;
     Add(Format('HeaderImageSize : %d', [FileHeader.bfSize]));
     Add(Format('Width : %d,  Height : %d', [biWidth, biHeight]));
     Add(Format('BitCount : %d', [biBitCount]));
     Add(Format('ImageSize : %d', [biSizeImage]));
     Add(Format('DataSize : %d', [DataSize]));
   End;
End;

@F0xi : Si tu arrives à "réinjecter" les données avec
Bitmap.ScanLine je serais vivement intéressé ...

toutes mes tentatives sont restées nul   Grrr !!!

@+
Cirec

0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
6 nov. 2006 à 15:21
Petite modification pour plus de rapidité ( ça va faire plaisir à F0xi)

On ajoute ceci :

// Sur le principe de la solution 3 [78..94ms 8MPixels]  de F0xi:
//  la plus rapide des modifiables (pour moi)  ... la version 4 est certe plus rapide
//  mais je ne sais pas comment inverser les Bytes R et B 
function PixelRGBToInt(const PRGB : TRGBRec) : integer;
begin
  result := (PRGB.R shl 16) + (PRGB.G shl 8) + PRGB.B;
end;

et à la place de :             
BMP.Canvas.Pixels[X,  Y] : = RGB(aData[X].B,  aData[X].G, aData[X].R);

Mettre ceci:        
BMP.Canvas.Pixels[X, Y] := Pixel24ToInt3(aData[X]);

@+
Cirec

0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
6 nov. 2006 à 15:24
Argh

BMP.Canvas.Pixels[X, Y] := <strike> Pixel24ToInt3 </strike>(aData[X]);

BMP.Canvas.Pixels[X, Y] : = PixelRGBToInt(aData[X]);

sinon ça marche pô

 
@+
Cirec

0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
6 nov. 2006 à 22:02
aller pouf, j'adore les defis !

Type
  // pixel 24 bits
  TPixel24 = record
    R,G,B : byte;
  end;

  // pour ScanLine en pixelformat pf24bit
  pPixelLine = ^TPixelLine;
  TPixelLine = array[0..16383] of TPixel24;

  // pour copier du stream vers TBitmap
  pBytes = ^TBytes;
  TBytes = array of byte;

// procedure qui permet d'analyser l'image
procedure AnalyseBitmap(const FileName : string; Strings : TStrings);
Var
  MS         : TMemoryStream;
  BMP        : TBitmap;
  FileHeader : TBITMAPFILEHEADER;
  Info       : TBITMAPINFO;
  pB         : pBytes;
  pPL        : pPixelLine;
  Pixel      : TPixel24;
  X,Y,
  LineLen,
  BytesCount : integer;
begin
   MS := TMemoryStream.Create;
   try
     // on charge le stream
     MS.LoadFromFile(FileName);

     // on recupere les infos
     MS.ReadBuffer(FileHeader, SizeOf(TBITMAPFILEHEADER));
     MS.ReadBuffer(Info, SizeOf(TBITMAPINFO));
    
     // on vas a l'offset des données
     MS.Position := FileHeader.bfOffBits;

     BMP := TBitmap.Create;
     try
       // on selectionne le format des pixels
       // tout les formats bmp sont supportés
       with Info.bmiHeader do begin
          case biBitCount of
             1 : BMP.PixelFormat :=  pf1Bit;
             4 : BMP.PixelFormat :=  pf4Bit;
             8 : BMP.PixelFormat :=  pf8Bit;
            15 : BMP.PixelFormat :=  pf15Bit;
            16 : BMP.PixelFormat :=  pf16Bit;
            24 : BMP.PixelFormat :=  pf24Bit;
            32 : BMP.PixelFormat :=  pf32Bit;
          end;
          BMP.Width  := biWidth;
          BMP.Height := biHeight;
          // on calcul la longeur d'une ligne (shr 3 = div 8)
          LineLen    := (BMP.Width * biBitCount) shr 3;
       end;
       
       // on injecte rapidement les données dans le bitmap
       // il faut lire a l'envers car les données sont stockées
       // de bas en haut dans le fichier bitmap
       for Y := BMP.Height-1 downto 0 do begin

           // on recupere la ligne Y dans un pBytes
           pB := BMP.ScanLine[y];

           // on lit la ligne en une seule fois
           MS.readBuffer(pB^, LineLen);
       end;
      
       // on prepare la liste
       Strings.Clear;
       Strings.BeginUpdate;

       // on mets par defaut en 24bits pour faciliter la lecture
       BMP.PixelFormat := pf24bit;
       for Y := 0 to BMP.Height-1 do begin

           // on recupere cette fois la ligne dans un pPixelLine
           pPL := BMP.ScanLine[Y];

           for X := 0 to BMP.Width-1 do begin

               // on ajoute la ligne dans la liste
               Strings.Add(format( 'R=%3.d G=%3.d B=%3.d',
                                 [ pPL[x].R, pPL[x].G, pPL[x].B ]));
           end;
       end;

       // on affiche d'autres infos
       With Info.bmiHeader do Begin
         // Taille du fichier, de l'entête et de données
         Strings.Add(Format( 'File size   : %d bytes (Head=%d bytes, Data=%d bytes)',[FileHeader.bfSize, FileHeader.bfSize-(LineLen * biHeight), LineLen * biHeight]));

         // Resolutions complete Width x Height x Bits
         Strings.Add(Format( 'Resolution  : %d x %d x %d', [biWidth, biHeight, biBitCount]));
       End;
      
       // on notifie la liste que les modifications sont finies
       Strings.EndUpdate;
       // ici c'est juste pour verifier que le BMP a été lus correctement
//       form1.PaintBox1.Canvas.Draw(0,0,BMP);

     // on libere tout
     finally
       BMP.Free;
     end;
   finally
     MS.Free;
   end;
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Trés simplement
  AnalyseBitmap('E:\TropPleinDeTrucsEnBordel\ProgDelphi\test16bits.bmp', ListBox1.Items);
end;

0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
7 nov. 2006 à 00:36
Je dois avouer que ça fonctionne ... Mais ...

Il y a un mais et pas des moindres

Pour une image 24bit 800 X 600

Méthode de F0xi:

  Temps de chargement : 106729 MS
  Utilisation UC              : 50 %
  Utilisation mémoire    : 24456 Ko

Ma méthode:


  Temps de chargement : 346 MS

  Utilisation UC              : 17 %

  Utilisation mémoire    : 3748 Ko

je peu charger 308 l'image avec ma méthode pendant que je la charge une fois avec la tienne !!!!

Tu as réussit à rendre ScanLine moins performant que Canvas.Pixels

pour l'instant je préfère la mienne

 
@+
Cirec

0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
7 nov. 2006 à 01:19
Bon tu peux retirer mon précédant message

j'ai repris le principe du PBytes avec mon code et là l'image se charge en 16 MS

et en fait c'est ton affichage dans TStrings qui met le "bordel" 
en mettant cette partie en commentaire j'obtiens le même résultat à savoir 16 MS

je n'ai plus qu'une chose à dire :

 
@+
Cirec

0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
7 nov. 2006 à 04:00
oui c'est le listing des couleurs dans le TStrings qui prend facilement 800..1000 ms (sur mon proco).
si on retire cela, on tombe entre 0..16ms

0
Rejoignez-nous