4
votes

Créer une image à partir d'un tampon de caractères non signé

Je capture des empreintes digitales à l'aide d'un appareil appelé Secugen Pro 20, il possède son propre SDK pour Linux, et je souhaite capturer l'image d'empreinte digitale et l'enregistrer sous n'importe quel format d'image .

Ils ont ce typedef unsigned char BYTE;

J'ai déclaré mon imageBuffer

BYTE * CurrentImageBuffer;

Ensuite, je lui alloue de la mémoire en utilisant les spécifications des appareils

CurrentImageBuffer = malloc (device_info.ImageWidth * device_info.ImageHeight);

Et à un moment donné à mon code, je capture l'image et passe CurrentImageBuffer comme argument à la fonction de capture:

SGFPM_GetImageEx (m_hFPM, CurrentImageBuffer, GET_IMAGE_TIMEOUT, NULL, GET_IMAGE_DESIRED_QUALITY)

Voilà à quoi ressemble la variable juste après cette ligne de code (je peux confirmer qu'elle a capturé un doigt):

représentation currentImageBuffer

Je ne comprends tout simplement pas comment procéder pour créer une image à partir de ce tampon, car elle ne ressemble pas à un ByteArray

Je ne sais même pas si c'est le bon endroit pour obtenir mon image, mais cela semble être le bon endroit parce que c'est un tampon, n'est-ce pas?

OBS: je suis nouveau sur C


17 commentaires

Que dit la documentation sur SGFPM_GetImageEx () ? Chacun de ses arguments et sa valeur de retour


SGFPM_GetImage () capture une image sans vérifier la présence d'un doigt ou vérifier la qualité de l'image. SGFPM_GetImageEx () capture les images d'empreintes digitales en continu, vérifie la qualité de l'image par rapport à une valeur de qualité spécifiée et ignore l'image si elle ne contient pas d'empreinte digitale. Si une image de qualité est capturée dans le délai donné (le deuxième paramètre), SGFPM_GetImageEx () termine son traitement. Si un handle de fenêtre est fourni par l'application, les pilotes dessineront une image d'empreinte digitale dans la fenêtre fournie en utilisant la valeur de handle.


SGFPM_DLL_DECL DWORD WINAPI SGFPM_GetImageEx (HSGFPM hFpm, BYTE * buffer, DWORD time, HWND dispWnd, DWORD quality);


Donc, si je comprends bien, le 4ème argument de cette fonction ( dispWnd ) est l'endroit où l'image d'empreinte digitale est dessinée. Vous avez fourni NULL afin de ne pas obtenir d'image.


Mais ça devrait être un gestionnaire de fenêtre (?), Je ne veux pas afficher l'image sur une fenêtre, je veux l'image elle-même, en l'enregistrant dans un fichier


Selon doc. , il semble correct de passer NULL pour le handle de fenêtre. (C'est une poignée - pas une poignée r .)


BYTE * CurrentImageBuffer = malloc (device_info.ImageWidth * device_info.ImageHeight); laissez-moi réfléchir, vous obtenez les données de pixel d'une image de niveau de gris (avec probablement 256 nuances de gris dans la plage [0, 255 ] (= [noir, blanc])). Avez-vous essayé de l'afficher comme tel?


Il semble que j'ai trouvé un chemin, ici stackoverflow.com/questions/2654480/...


Je pense que CurrentImageBuffer est une sorte de données bmp


@Scheff qu'entendez-vous par "Afficher ceci comme tel"? Comment pourrais-je le faire?


Veuillez ne pas prendre le char (dans unsigned char ) trop littéral. unsigned char est un type intégral non signé comme short int ou int . Il est utilisé car il fournit des entiers de 8 bits qui semblent être nécessaires pour le stockage de l'image.


Alors vous dites que cela pourrait être un tableau d'octets? Désolé de ne pas bien comprendre tout ce que vous dites, c'est un peu loin de mes connaissances mais je fais de mon mieux ici


Selon la taille allouée (code similaire trouvé avec google - donc, cela semble correct), vous n'avez que les données brutes de pixels. Pour l'afficher, vous devez utiliser n'importe quelle fonction disponible qui est capable d'afficher des images à partir de données brutes. Alternativement, vous pouvez le stocker sous forme de fichier image (avec la configuration resp. Des informations d'en-tête) et l'afficher dans une visionneuse d'images (si vous voulez juste voir le résultat).


hmm, compris, avez-vous un exemple où je peux essayer de prendre ces données brutes dans un fichier image? Je travaille actuellement sur celui sur le lien que j'ai commenté


Le stockage des données comme BMP pourrait être une option. Vous devez remplir soigneusement l'en-tête BMP. Je n'ai pas pu ouvrir votre lien, mais Wikipedia: BMP a également une description.


continuons cette discussion dans le chat .


" Vous dites que cela pourrait être un tableau d'octets? ": typedef unsigned char BYTE; et BYTE * buffer sont utilisés exactement dans ce but .


3 Réponses :



8
votes

Voici un petit exemple de programme pour écrire une image de niveau de gris 8 bits dans un fichier BMP Windows:

#include <stdio.h>

typedef unsigned char Byte;

int writeBMPGray8(FILE *f, int w, int h, const Byte *data)
{
  unsigned bytesPerRow = (w + 3) & ~3; // align to 4 bytes (requirement)
  unsigned size
    = 14 // Bitmap file header size
    + 12 // DIB header size
    + 256 * 3; // palette size
  unsigned gap = size;
  size = (size + 3) & ~3; // align to 4 bytes (requirement)
  gap = size - gap; // get size of gap between end of headers and raw data
  unsigned offs = size; // store offset of raw data
  size += h * bytesPerRow; // bitmap data size in file
  /* write Bitmap file header (14 bytes) */      
  { const Byte buffer[14] = {
      'B', 'M', // magic code
      size & 0xff, size >> 8 & 0xff, size >> 16 & 0xff, size >> 24 & 0xff, // size of BMP file in bytes
      0, 0, // reserved
      0, 0, // reserved
      offs & 0xff, offs >> 8 & 0xff, offs >> 16 & 0xff, offs >> 24 & 0xff // starting offset of pixel data
    };
    if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!
  }
  /* write DIB header (12 bytes) */
  { const Byte buffer[12] = {
      12, 0, 0, 0, // size of this header
      w & 0xff, w >> 8 & 0xff, // bitmap width in pixels
      h & 0xff, h >> 8 & 0xff, // bitmap height in pixels
      1, 0, // number of color planes, must be 1
      8, 0 // number of bits per pixel
    };
    if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!
  }
  /* write color palette (3 * 256 bytes) */
  for (int i = 0; i < 256; ++i) { // make a gray level palette
    Byte buffer[3] = { i, i, i };
    if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!   
  }
  /* write gap (to align start address of raw data with 4 */
  for (int i = 0; i < gap; ++i) {
    if (fputc(0, f) < 0) return -1; // ERROR!
  }
  /* write raw data */
  for (int y = 0; y < h; ++y) { // for all rows
    int x = 0;
    for (; x < w; ++x) { // for all columns
      if (fputc(*data++, f) < 0) return -1; // ERROR!
    }
    // write row padding
    for (; x < bytesPerRow; ++x) {
      if (fputc(0, f) < 0) return -1; // ERROR!
    }
  }
  /* done */
  return 0;
}

int main()
{
  /* a sample image 6 x 8, gray level */
  enum { w = 6, h = 8 };
  const Byte imgRaw[w * h] = {
    0x00, 0x30, 0x60, 0x90, 0xc0, 0xf0,
    0x02, 0x32, 0x62, 0x92, 0xc2, 0xf2,
    0x04, 0x34, 0x64, 0x94, 0xc4, 0xf4,
    0x06, 0x36, 0x66, 0x96, 0xc6, 0xf6,
    0x08, 0x38, 0x68, 0x98, 0xc8, 0xf8,
    0x0a, 0x3a, 0x6a, 0x9a, 0xca, 0xfa,
    0x0c, 0x3c, 0x6c, 0x9c, 0xcc, 0xfc,
    0x0e, 0x3e, 0x6e, 0x9e, 0xce, 0xfe
  };
  FILE *f = fopen("test.bmp", "wb");
  if (!f) return 1; // ERROR!
  if (writeBMPGray8(f, w, h, imgRaw)) return 1; // ERROR!
  if (fclose(f)) return 1; // ERROR!
  return 0; // success
}

L'exemple d'image fournit une sorte de dégradés horizontalement et verticalement. J'ai choisi une largeur de 6 intentionnellement pour vérifier / montrer que l'alignement des lignes est fait correctement.

La mise en œuvre est basée sur la description de Wikipedia Format de fichier BMP .

Pour faire court, j'ai encodé le format le plus simple - l'ancien BITMAPCOREHEADER de Windows 2.0 et OS / 2 1.x. (MS Paint peut charger ceci ainsi que l'aperçu de Windows 10. J'ai testé avec GIMP qui s'est également chargé sans aucune plainte.)

Voici à quoi cela ressemble dans GIMP :

 Instantané de test.bmp dans GIMP (agrandi) a >


5 commentaires

Peut-être que l'utilisation d'une bibliothèque (openCV par exemple, mais il y a probablement des bibliothèques plus légères pour le faire) simplifierait ce travail. Vote positif cependant; il est toujours bon de savoir comment cela se fait manuellement


@CacahueteFrito Il y a sûrement beaucoup de bibliothèques open source. Par exemple. Qt fournit le support BMP ainsi que ImageMagick (probablement) (qui a également une API C ++). Parfois (en particulier pour de telles réponses MCVE SO), il est agréable d'avoir un code minimal sans autres dépendances que les bibliothèques standard C / C ++ (qui peuvent même être testées / démontrées sur des compilateurs en ligne).


Ce n'est pas le format bitmap Windows. La taille de l'en-tête DIB doit être de 40 et non de 12 ( BITMAPINFOHEADER ). La taille de la palette doit être de 256 * 4 et non de 256 * 3


@BarmakShemirani Veuillez noter que l'article Wikipédia lié décrit plusieurs versions de BMP. J'ai choisi l'un des premiers avec le moins d'empreinte mémoire / impl. effort. Veuillez noter que MS Paint / MS Explorer Preview ainsi que GIMP peuvent charger l'image stockée sans aucun problème.


Désolé, je me suis trompé. Je n'ai pas lu la seconde moitié de votre message.



1
votes

Si vous avez correctement capturé l'image dans CurrentImageBuffer, vous pouvez l'écrire en tant que fichier brut en utilisant le fragment de code ci-dessous:

        fp = fopen(rawFileName,"wb");
        fwrite (CurrentImageBuffer, sizeof (BYTE) , device_info.ImageHeight*device_info.ImageWidth , fp);
        fclose(fp);

Comme j'ai utilisé le même environnement, j'envoie ce qui précède fragment de ma base de code de travail. En fait, le fichier brut est ultérieurement converti en modèle qui est ensuite utilisé pour la correspondance / identification et non directement utilisé pour l'affichage, etc. La variable rawFileName stocke le nom du fichier sous forme de tableau de caractères (chaîne) où ce tampon est stocké.


1 commentaires

Merci pour la réponse, j'ai réussi à enregistrer l'image en tant que bmp et à enregistrer le modèle et tout dans un fichier, je peux maintenant enregistrer les minutae et l'ouvrir plus tard pour les propositions de match, tout fonctionne maintenant