C# BitmapSource小节

在C#中,处理位图(Bitmap)图像数据时,理解像素格式(PixelFormat)、步幅(stride)和像素数据复制是非常重要的。

BitmapSource常用属性与方法

PixelFormat——Defines a pixel format for images and pixel-based surfaces.即定义图像和基于像素表面的像素格式。

Stride——(步幅)是图像数据中每一行像素所占用的字节数。这个值不一定等于图像宽度乘以每个像素的字节数,因为出于内存对齐的考虑,有些图像格式可能会在行尾添加额外的填充字节(padding bytes)。

PixelFormats——表示受支持像素格式的集合。PixelFormat是一个静态类,描述了位图中每个像素的颜色深度和格式。例如,PixelFormats.Bgra32表示每个像素占用32位,其中包含了透明度(Alpha)、红色(Red)、绿色(Green)和蓝色(Blue)四个分量。

CopyPixels——将位图像素数据复制到具有从指定偏移量开始的指定跨距的像素数组中。(C#中对于BitmapSource像素数据的复制,提供了此方法。)

应用示例

      public static byte[] GetCorPixelDataFromCTData(CaseDTO currentCase, short[,,] ctData16ct, int curPhase, double frameIndex, out int width, out int height, double slope, double intercept, int imgWidth, int imgHeight)
      {
          Stopwatch sw = Stopwatch.StartNew();
          //ctData
          var ctDataCurrentPhrase = new short[currentCase.OnePhaseSlicesNumber, ctData16ct.GetLength(1), ctData16ct.GetLength(2)];
          var start = (curPhase - 1) * currentCase.OnePhaseSlicesNumber;
          var end = curPhase * currentCase.OnePhaseSlicesNumber;

          //设XOZ为矢状面
          width = ctDataCurrentPhrase.GetLength(2);
          height = ctDataCurrentPhrase.GetLength(0);
          //4个字节一个像素,参考ARGB
          byte[] PixelData = new byte[width * height * 4];
          try
          {
              //PixelData是按照height*width*4排列的数据
              var rowStride = width * 4;
              for (int y = 0; y < height; ++y)
              {
                  for (int x = 0; x < width; ++x)
                  {
                      var pixelDataindex = y * rowStride + x * 4;
                      var y0 = start + y;
                      var gray = (byte)HUtoGraysale(ctData16ct[y0, (int)frameIndex, x], slope, intercept, imgHeight, imgWidth);
                      UpdatePixelData(PixelData, pixelDataindex, gray);
                      /*   for (int i = 0; i < 4; ++i)
                         {
                             var pixelDataindex = y * rowStride + x * 4 + i;
                             if (i != 3)
                             {
                                 var y0 = start + y;
                                 PixelData[pixelDataindex] = (byte)HUtoGraysale(ctData16ct[y0, (int)frameIndex, x], slope, intercept, imgHeight, imgWidth);
                             }
                             else
                                 PixelData[pixelDataindex] = 255;
                         }*/
                  }
              }
              Debug.WriteLine($"GetCorPixelDataFromCTData cost time: {sw.ElapsedMilliseconds}");
              return PixelData;
          }
          catch (Exception ex)
          {
              return PixelData;
          }
          finally
          {
              sw.Stop();
          }

      }
     

        internal static void UpdatePixelData(byte[] PixelData, int pixelDataindex, byte gray)
        {
            PixelData[pixelDataindex] = gray;
            PixelData[pixelDataindex + 1] = gray;
            PixelData[pixelDataindex + 2] = gray;
            PixelData[pixelDataindex + 3] = 255;
        }

        public static int HUtoGraysale(int hu, double slope, double intercept, double windowCenter, double windowWidth)
        {
            //CT值转灰度值的关键公式pixel * slope + intercept
            hu = (int)(hu * slope + intercept);
            int low = (int)windowCenter - (int)windowWidth / 2;
            int high = (int)windowCenter + (int)windowWidth / 2;
            int grayscale = hu > high ? 255 : (hu < low ? 0 : (int)((hu - low) * 255 / windowWidth));
            return grayscale;
        }

注意事项

在上述示例中有一些关注点,在开发时需要注意:

  1. stride的求取要注意取整;示例中为了保证stride为整数操作为 (bitmap.PixelWidth * pixelFormat.BitsPerPixel + 7) / 8 ,因为1字节=8位,所以要将位数除以8来得到字节数。加7是为了实现向上取整的效果,比如如果每个像素占用3位,那么(3 * width + 7) / 8将确保每像素至少占用1个字节。
  2. RGBA的存储并不是按RGBA的先后顺序来的,而是B、G、R、A;这个一定要注意,上述代码中如下:
    int offset = y * stride + x * 4;
    byte blue = pixels[offset];
    byte green = pixels[offset + 1];
    byte red = pixels[offset + 2];
    //byte alpha = pixels[offset + 3];

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值