2016-02-14 22 views
5

cerco di caricare il file JPEG e cancellare tutti i pixel in bianco e nero da un'immagine.NET metodo Bitmap.Load produrre risultato diverso su computer diversi

C# Codice:

... 
    m_SrcImage = new Bitmap(imagePath); 

    Rectangle r = new Rectangle(0, 0, m_SrcImage.Width, m_SrcImage.Height); 
    BitmapData bd = m_SrcImage.LockBits(r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 

    //Load Colors 
    int[] colours = new int[m_SrcImage.Width * m_SrcImage.Height]; 
    Marshal.Copy(bd.Scan0, colours, 0, colours.Length); 
    m_SrcImage.UnlockBits(bd); 

    int len = colours.Length; 

    List<Color> result = new List<Color>(len); 

    for (int i = 0; i < len; ++i) 
    { 
     uint w = ((uint)colours[i]) & 0x00FFFFFF; //Delete alpha-channel 
     if (w != 0x00000000 && w != 0x00FFFFFF) //Check pixel is not black or white 
     { 
      w |= 0xFF000000;      //Return alpha channel 
      result.Add(Color.FromArgb((int)w)); 
     } 
    } 
    ... 

Dopo che cerco di trovare colori univoci nell'elenco di questo codice

result.Sort((a, b) => 
    { 
     return a.R != b.R ? a.R - b.R : 
       a.G != b.G ? a.G - b.G : 
       a.B != b.B ? a.B - b.B : 
       0; 
    }); 


    List<Color> uniqueColors = new List<Color>(result.Count); 

    Color rgbTemp = result[0]; 

    for (int i = 0; i < len; ++i) 
    { 
     if (rgbTemp == result[i]) 
     {  
       continue; 
     } 

     uniqueColors.Add(rgbTemp); 
     rgbTemp = result[i]; 
    } 
    uniqueColors.Add(rgbTemp); 

E questo codice produce risultati diversi su macchine diverse sulla stessa immagine!

Per esempio, su this image Produce:

colori
  • 43198 unici su XP SP3 con la versione .NET 4
  • 43168 colori unici su Win7 Ultimate con la versione .NET 4,5

minima progetto di prova è possibile download here. Apre solo l'immagine selezionata e produce file txt con colori unici.

Un altro fatto. Alcuni pixel vengono letti in modo diverso su macchine diverse. Confronto i file txt con Notepad ++ e mostra che alcuni pixel hanno componenti RGB differenti. La differenza è 1 per ciascun componente, ad es.

  • Win7 pixel: 255 200 100
  • WinXP pixel: 254 199 99

Ho letto questo post

stackoverflow.com/questions/2419598/why-might-different- calcolatori-calcoli-diversi-aritmetici-risultati-in-vb-net

(mi dispiace, non ho abbastanza rastrellamento per il collegamento normale).

... ma non c'erano informazioni su come risolverlo.


Il progetto è stato compilato per .NET 4 Profilo client su macchina con sistema operativo Windows 7 in VS 2015 Commumity Edition.

+0

Per caricare immagini, è necessario scegliere un servizio di caricamento gratuito che non richieda il login – TaW

+0

@TaW Spostare l'immagine su imgur.com e spostare il progetto di test su github –

+0

Grazie. Comunque credo che la risposta di Lasse sia corretta: JPeg non è pensato per riprodurre l'immagine con assoluta precisione. Passa al PNG se ne hai davvero bisogno! – TaW

risposta

3

Wikipedia has this to say about the accuracy requirements for JPEG Decoders:

La descrizione codifica in standard JPEG non risolve la precisione necessaria per l'uscita dell'immagine compressa.Tuttavia, lo standard JPEG (e gli standard MPEG simili) include alcuni requisiti di precisione per la decodifica, comprese tutte le parti del processo di decodifica (decodifica a lunghezza variabile, DCT inverso, dequantizzazione, rinormalizzazione delle uscite); l'uscita dall'algoritmo di riferimento non deve superare:

  • un massimo di un po 'di differenza per ogni componente pixel
  • partire errore quadratico medio su ogni 8 × 8 pixel blocco
  • molto basso medio errore per ogni 8 × 8 pixel
  • blocco
  • molto basso errore quadratico medio su tutta l'immagine
  • estremamente basso errore medio su tutta l'immagine

(corsivo mio)

In breve, non è semplicemente due diverse implementazioni di decoder in gioco qui, e producono immagini diverse, all'interno del requisito di precisione (1 bit = +/- 1 nel componente valori, come hai osservato).

Quindi, non è possibile utilizzare lo stesso decodificatore jpeg (non incorporato). Se è necessario avere lo stesso output, probabilmente è necessario passare a un decodificatore diverso, uno che sarà lo stesso indipendentemente dalla versione .NET o Windows su cui si sta eseguendo. Sto indovinando che GDI + è il colpevole qui come questo ha subito modifiche più grandi da Windows XP.

+0

È una triste notizia ... Grazie per la risposta. Conoscete una libreria che può lavorare insieme con i formati PNG, BMP, JPEG e TIFF? –

+0

Ho provato ad aggiungere la libreria BitDracle Libjpeg.NET per proiettare e ottenere lo stesso risultato ... –

+1

Perché avete bisogno di questo per produrre comunque gli stessi pixel su tutte le piattaforme? Stai utilizzando un formato immagine con compressione con perdita di dati, non hai comunque un controllo reale sui pixel. –

0

ho risolvere il mio problema con l'aggiunta di Libjpeg.NET di progettare e scrivere questo codice:

 private Bitmap JpegToBitmap(JpegImage jpeg) 
     { 
      int width = jpeg.Width; 
      int height = jpeg.Height; 

      // Read the image into the memory buffer 
      int[] raster = new int[height * width]; 

      for(int i = 0; i < height; ++i) 
      { 
       byte[] temp = jpeg.GetRow(i).ToBytes(); 

       for (int j = 0; j < temp.Length; j += 3) 
       { 
        int offset = i*width + j/3; 
        raster[offset] = 0; 
        raster[offset] |= (((int)temp[j+2]) << 16); 
        raster[offset] |= (((int)temp[j+1]) << 8); 
        raster[offset] |= (int)temp[j]; 
       } 
      } 

      Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); 
      Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
      BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 
      byte[] bits = new byte[bmpdata.Stride * bmpdata.Height]; 

      for (int y = 0; y < bmp.Height; y++) 
      { 
       int rasterOffset = y * bmp.Width; 
       int bitsOffset = (bmp.Height - y - 1) * bmpdata.Stride; 

       for (int x = 0; x < bmp.Width; x++) 
       { 
        int rgba = raster[rasterOffset++]; 
        bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff); 
        bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff); 
        bits[bitsOffset++] = (byte)(rgba & 0xff); 
       } 
      } 
      System.Runtime.InteropServices.Marshal.Copy(bits, 0, bmpdata.Scan0, bits.Length); 
      bmp.UnlockBits(bmpdata); 

      return bmp; 
     } 

Quindi, questo è abbastanza per me.

Problemi correlati