2009-03-02 10 views
3

Je ne connais pas un meilleur titre, mais je vais décrire le problème.Lecture de couleurs bitmap bitmap monochrome

Un composant que nous utilisons peut présenter des images. Il peut afficher une image en noir et blanc avec une résolution de 64 x 256.

Le problème est le format de l'image que nous devons envoyer à l'appareil. Il ne s'agit pas d'un format bitmap standard, mais plutôt d'un tableau de octets représentant chaque pixel de l'image.

0 = noir, 1 = blanc.

Donc, si nous avions une image avec la taille: 4 x 4 du tableau d'octets pourrait ressembler à:

Et l'image ressemblerait à ceci:

Bitmap http://www.mediafire.com/imgbnc.php/6ee6a28148d0170708cb10ec7ce6512e4g.jpg

Le problème est que nous devons créer cette image en créant un bitmap monochrome en C#, puis le convertir au format de fichier compris par le périphérique.

Par exemple, il est possible d'afficher du texte sur l'appareil. Pour ce faire, il aurait devoir créer un bitmap et écrire un texte à lui:

var bitmap = new Bitmap(256, 64); 

using (var graphics = Graphics.FromImage(bitmap)) 
{ 
    graphics.DrawString("Hello World", new Font("Courier", 10, FontStyle.Regular), new SolidBrush(Color.White), 1, 1); 
} 

Il y a 2 problèmes ici:

  1. Le bitmap généré n'est pas monochrome
  2. généré bitmap a un format binaire différent

donc je besoin d'un moyen de:

  1. Générer un bitmap monochrome dans .NET
  2. Lire les couleurs de pixels individuels pour chaque pixel dans l'image bitmap

J'ai trouvé que vous pouvez régler la profondeur de pixel à 16, 24 ou 32 bits, mais n'ont pas trouvé monochrome et je n'ai aucune idée de comment lire les données de pixel.

Les suggestions sont les bienvenues.

MISE À JOUR: Je ne peux pas utiliser Win32 PInvokes ... doit être plate-forme neutre!

SUIVI: Le code suivant fonctionne pour moi maintenant. (Juste au cas où tout le monde en a besoin)

private static byte[] GetLedBytes(Bitmap bitmap) 
{ 
    int threshold = 127; 
    int index = 0; 
    int dimensions = bitmap.Height * bitmap.Width; 

    BitArray bits = new BitArray(dimensions); 

    //Vertically 
    for (int y = 0; y < bitmap.Height; y++) 
    { 
     //Horizontally 
     for (int x = 0; x < bitmap.Width; x++) 
     { 
      Color c = bitmap.GetPixel(x, y); 
      int luminance = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11); 
      bits[index] = (luminance > threshold); 
      index++; 
     } 
    } 

    byte[] data = new byte[dimensions/8]; 
    bits.CopyTo(data, 0); 
    return data; 
} 

Répondre

6

Je calculerais la luminance de chaque pixel puis je le comparerais à une certaine valeur de seuil.

y=0.3*R+0.59G*G+0.11*B 

-dire la valeur de seuil est de 127:

const int threshold = 127; 
Bitmap bm = { some source bitmap }; 

byte[,] buffer = new byte[64,256]; 

for(int y=0;y<bm.Height;y++) 
{ 
    for(int x=0;x<bm.Width;x++) 
    { 
    Color c=source.GetPixel(x,y); 
    int luminance = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11); 
    buffer[x,y] = (luminance > 127) ? 1 : 0; 
    } 
} 
+1

Pointez pour ça! Mais si vous utilisez Bitmap.LockBits au lieu de Bitmap.GetPixel vous obtenez des performances supérieures! –

+0

Thnx! Avec quelques ajustements mineurs, ce code fonctionne comme un charme :-) – TimothyP

+0

danbystrom: Vous avez raison de vouloir garder l'exemple de code aussi propre et sans pointeur que possible. – arul

0

This chap a un code qui crée une image bitmap mono. L'exemple SaveImage est celui qui vous intéresse.

+0

Le lien est mort – danmiser

1

Je ne connais pas C#. Il y a peut-être plusieurs façons de le faire. Voici un moyen simple.

  1. Créez une image bitmap noire vierge de taille égale à la configuration de votre périphérique. Dessinez dessus tout ce que vous souhaitez dessiner comme du texte, des chiffres, etc.

  2. Maintenant, définissez le seuil de l'image, c'est-à-dire définissez le pixel de l'image en dessous d'une valeur d'intensité à zéro, sinon définissez-le. par exemple. définir toutes les valeurs d'intensité> 0 à 1.

  3. Maintenant, convertissez au format requis par votre appareil. Créer un tableau d'octets de la taille (64 * 256)/8. Régler les bits correspondant à 1, dans lequel les valeurs de pixels correspondantes dans bitmap antérieure sont 1, sinon les remettre à 0.

Edit: Etape 3. A l'aide des opérateurs de bits pour définir les bits.

+0

Le problème est que je n'ai aucune idée de la façon de lire les valeurs de pixel d'un bitmap – TimothyP

+0

Eh bien, vous devez vérifier les API. Il doit y avoir une méthode comme getPixel(), getIntensity() ou peut-être même une simple référence de tableau fera l'affaire. – Xolve

1

Vous ne devriez pas utiliser la méthode GetPixel de votre bitmap pour convertir bitmap entier d'un format à un autre! Ce sera inefficace. Au lieu de cela, vous devez utiliser la méthode LockBits pour accéder à une copie du tampon d'image et le convertir au format souhaité. Je ne suis pas complètement sûr de la convertir en monochrome mais il y a une valeur Format1bppIndexed dans l'énumération PixelFormat qui peut vous aider.

1

Vous pouvez essayer de fournir un pixelformat dans le constructeur:

var bitmap = new Bitmap(256, 64, PixelFormat.Format1bppIndexed); 

Quand je l'ai fait dessiner des bitmaps monochromes sur d'autres plates-formes que j'avais parfois pour désactiver l'anticrénelage ou le texte rendu ne serait pas visible:

graphics.SmoothingMode=SmoothingMode.None; 

YMMV.

+0

Vous ne pouvez pas appeler Graphics.FromImage sur quelque chose de moins que 32bpp – plinth

1

Bitmap has a GetPixel method que vous pouvez utiliser. Cela vous permettra de dessiner sur le Bitmap et plus tard de le convertir au format dont vous avez besoin. Les bitmaps dans les formulaires Windows (c.-à-d., Accessibles via Graphics.FromImage) sont de 24 bpp (peut-être 32? Il est trop tôt et j'oublie franchement). Néanmoins, GetPixel renvoie un objet Color, de sorte que la profondeur de bit de l'image n'est pas importante. Je vous suggère d'écrire votre code comme ceci:

MyBitmapFormat ToMyBitmap(Bitmap b) 
{ 
    MyBitmapFormat mine = new MyBitmapFormat(b.Width, b.Height); 

    for (int y=0; y < b.Height; y++) { 
     for (int x=0; x < b.Width; x++) { 
      mine.SetPixel(x, y, ColorIsBlackish(b.GetPixel(x, y))); 
     } 
    } 
} 

bool ColorIsBlackish(Color c) 
{ 
    return Luminance(c) < 128; // 128 is midline 
} 

int Luminance(c) 
{ 
    return (int)(0.299 * Color.Red + 0.587 * Color.Green + 0.114 * Color.Blue); 
} 

Ce processus est appelé seuillage simple. C'est braindead, mais cela fonctionnera comme une première coupe.

1

Merci pour le code ci-dessus - J'essaie de convertir une image monochrome en un tableau 2d où 1-noir 0-blanc mais j'ai quelques problèmes - j'ai utilisé votre code pour charger une image 8x8 bmp, et je suis sortie son contenu à l'aide d'une zone de texte en

myGrid =GetLedBytes(myBmp); 
    for (int x = 1; x < 8; x++) 
    { 
     textBox1.Text = textBox1.Text + Convert.ToString(myGrid[x])+ " "; 
    } 

mais je reçois cela comme un résultat dans la zone de texte:

225 231 231 231 231 129 255 

comment puis-je l'obtenir il est donc 0 et de 1?

+0

Si vous utilisez pixel.GetColor, vous pouvez obtenir les valeurs R G B d'un pixel non? Donc, puisque vous faites du noir et blanc, tout ce que vous avez à faire est de vérifier R G an B == 0 qui signifie noir. Tout le code n'est pas nécessaire. – TimothyP