2016-02-14 19 views
5

tôi cố gắng để tải tập tin JPEG và xóa tất cả các pixel đen và trắng từ ảnhNET phương pháp Bitmap.Load sản xuất kết quả khác nhau trên các máy tính khác nhau

C# Code:

... 
    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)); 
     } 
    } 
    ... 

Sau đó tôi cố gắng tìm các màu duy nhất trong Danh sách theo mã này

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); 

Và mã này tạo ra các kết quả khác nhau trên các máy khác nhau trên cùng một hình ảnh!

Ví dụ, trên this image nó tạo ra:

màu
  • 43198 độc đáo trên XP SP3 với phiên bản .NET 4
  • 43.168 màu sắc độc đáo trên Win7 Ultimate với phiên bản NET 4,5

tối thiểu dự án thử nghiệm bạn có thể download here. Nó chỉ mở ra hình ảnh được chọn và tạo ra tập tin txt với màu sắc độc đáo.

Một thực tế khác. Một số pixel được đọc khác nhau trên các máy khác nhau. Tôi so sánh các tệp txt với notepad ++ và nó cho thấy rằng một số pixel có các thành phần RGB khác nhau. Sự khác biệt là 1 cho mỗi thành phần, ví dụ:

  • Win7 điểm ảnh: 255 200 100
  • WinXP điểm ảnh: 254 199 99

Tôi đã đọc bài này

stackoverflow.com/questions/2419598/why-might-different- máy tính-tính-khác nhau-số học-kết quả-in-vb-net

(xin lỗi, tôi chưa đủ số tiền cho liên kết thông thường).

... nhưng không có thông tin về cách khắc phục.


Dự án đã được biên soạn cho .NET 4 Hồ sơ khách hàng trên máy tính có hệ điều hành Windows 7 trong phiên bản 2015 Commumity VS.

+0

Để tải lên hình ảnh, bạn nên chọn dịch vụ tải lên miễn phí không yêu cầu chúng tôi đăng nhập – TaW

+0

@TaW Di chuyển hình ảnh đến imgur.com và di chuyển dự án thử nghiệm sang github –

+0

Cảm ơn bạn. Tuy nhiên tôi đoán câu trả lời của Lasse là chính xác: JPeg không có nghĩa là tái tạo hình ảnh với độ chính xác tuyệt đối. Hãy chuyển sang PNG nếu bạn thực sự cần điều đó! – TaW

Trả lời

3

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

Mô tả mã hóa trong JPEG chuẩn vẫn không sửa được độ chính xác cần thiết cho sản lượng nén ảnh.Tuy nhiên, chuẩn JPEG (và các chuẩn MPEG tương tự) bao gồm một số yêu cầu chính xác cho giải mã, bao gồm tất cả các phần của quá trình giải mã (giải mã độ dài biến đổi, DCT nghịch đảo, khử, tái chuẩn hóa đầu ra); đầu ra từ các thuật toán tham khảo không được vượt quá:

  • tối đa là một chút khác biệt cho mỗi thành phần điểm ảnh
  • lỗi bình phương trung bình thấp trên mỗi 8 × 8 pixel khối
  • trung bình rất thấp lỗi trên mỗi × 8 pixel khối
  • lỗi bình phương trung bình rất thấp 8 trên toàn bộ hình ảnh
  • sai số trung bình rất thấp so với toàn bộ hình ảnh

(tôi nhấn mạnh)

Nói tóm lại, đơn giản là hai triển khai bộ giải mã khác nhau tại chơi ở đây, và họ tạo ra hình ảnh khác nhau, trong phạm vi yêu cầu độ chính xác (1 bit = +/- 1 trong các thành phần các giá trị, như bạn đã quan sát).

Vì vậy, ngắn sử dụng cùng một bộ giải mã jpeg (không có sẵn), điều này được mong đợi. Nếu bạn cần phải có cùng một đầu ra chính xác thì có thể bạn cần phải chuyển sang một bộ giải mã khác, một bộ giải mã sẽ giống nhau bất kể phiên bản .NET hoặc Windows nào bạn đang chạy. Tôi đoán rằng GDI + là thủ phạm ở đây vì điều này đã trải qua những thay đổi lớn hơn kể từ Windows XP.

+0

Tin buồn ... Thanx cho câu trả lời. Bạn có biết thư viện có thể làm việc với các định dạng PNG, BMP, JPEG và TIFF cùng nhau không? –

+0

Tôi đã cố gắng thêm thư viện Bitmiracle Libjpeg.NET vào dự án và kết quả tương tự ... –

+1

Tại sao bạn cần điều này để tạo cùng một pixel trên các nền tảng? Bạn đang sử dụng định dạng hình ảnh nén mất dữ liệu, bạn vẫn chưa thực sự kiểm soát pixel. –

0

tôi giải quyết vấn đề của tôi bằng cách thêm Libjpeg.NET dự án và viết mã này:

 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; 
     } 

Vì vậy, đó là đủ cho tôi.

Các vấn đề liên quan