DICOM调窗
该方法是用的C#安全代码,同样是地址操作,该方法实际使用下来,和指针操作用时差别不大,稍微慢了15ms左右。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
public unsafe Bitmap convertTo8(BinaryReader streamdata, int colors, bool littleEdition, bool signed, short nHighBit, int dataLen, float rescaleSlope, float rescaleIntercept, float windowCenter, float windowWidth, int width, int height) { Bitmap bmp = new Bitmap(width, height); Graphics gg = Graphics.FromImage(bmp); gg.Clear(Color.Green); BitmapData bmpDatas = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb); long numPixels = width * height; if (colors == 3)//color Img { byte* p = (byte*)bmpDatas.Scan0; int indx = 0; for (int i = 0; i < bmp.Height; i++) { for (int j = 0; j < bmp.Width; j++) { p[indx + 2] = streamdata.ReadByte(); p[indx + 1] = streamdata.ReadByte(); p[indx] = streamdata.ReadByte(); indx += 3; } } } else if (colors == 1)//grayscale Img { byte* p = (byte*)bmpDatas.Scan0; int nMin = ~(0xffff << (nHighBit + 1)), nMax = 0; int indx = 0;//byteData index for (int n = 0; n < numPixels; n++)//pixNum index { short nMask; nMask = (short)(0xffff << (nHighBit + 1)); short nSignBit; byte[] pixData = null; short pixValue = 0; pixData = streamdata.ReadBytes(dataLen / 8 * colors); if (nHighBit <= 15 && nHighBit > 7) { if (littleEdition == false) Array.Reverse(pixData, 0, 2); // 1. Clip the high bits. if (signed == false)// Unsigned integer { pixValue = (short)((~nMask) & (BitConverter.ToInt16(pixData, 0))); } else { nSignBit = (short)(1 << nHighBit); if (((BitConverter.ToInt16(pixData, 0)) & nSignBit) != 0) pixValue = (short)(BitConverter.ToInt16(pixData, 0) | nMask); else pixValue = (short)((~nMask) & (BitConverter.ToInt16(pixData, 0))); } } else if (nHighBit <= 7) { if (signed == false)// Unsigned integer { nMask = (short)(0xffff << (nHighBit + 1)); pixValue = (short)((~nMask) & (pixData[0])); } else { nMask = (short)(0xffff << (nHighBit + 1)); nSignBit = (short)(1 << nHighBit); if (((pixData[0]) & nSignBit) != 0) pixValue = (short)((short)pixData[0] | nMask); else pixValue = (short)((~nMask) & (pixData[0])); } } // 2. Rescale if needed (especially for CT) if ((rescaleSlope != 1.0f) || (rescaleIntercept != 0.0f)) { float fValue = pixValue * rescaleSlope + rescaleIntercept; pixValue = (short)fValue; } // 3. Window-level or rescale to 8-bit if ((windowCenter != 0) || (windowWidth != 0)) { float fSlope; float fShift; float fValue; fShift = windowCenter - windowWidth / 2.0f; fSlope = 255.0f / windowWidth; fValue = ((pixValue) - fShift) * fSlope; if (fValue < 0) fValue = 0; else if (fValue > 255) fValue = 255; p[indx++] = (byte)fValue; p[indx++] = (byte)fValue; p[indx++] = (byte)fValue; } else { // We will map the whole dynamic range. float fSlope; float fValue; int i = 0; // First compute the min and max. if (n == 0) nMin = nMax = pixValue; else { if (pixValue < nMin) nMin = pixValue; if (pixValue > nMask) nMask = pixValue; } // Calculate the scaling factor. if (nMax != nMin) fSlope = 255.0f / (nMax - nMin); else fSlope = 1.0f; fValue = ((pixValue) - nMin) * fSlope; if (fValue < 0) fValue = 0; else if (fValue > 255) fValue = 255; p[indx++] = (byte)fValue; } } } bmp.UnlockBits(bmpDatas); //bmp.Dispose(); return bmp; } |