DELPHI 对DICOM中的窗宽、窗位调整

来源:互联网 发布:淘宝猛犸象牙 编辑:程序博客网 时间:2024/05/17 08:16

在写这篇文章前72小时,我的多窗显示组件对于个别大W/C值的16位影像显示还是个问题,也发了帖子到PACS站询问过,更是在Google上猫刨了很久,终归一无所获,今天静下心来,用了2小时反复查看程序处理过程,对比数据,居然就这么搞定了,原来如此简单,哎,困惑了3天,把答案公布了,也算是助人为乐(中国地大物博,人心应宽广无量)


对16位的影像,要判断DICOM中最大像素值(0028,0107)大于65534,是则将16位影像数据的像素值大于等于0的全部减去65535,小于0的全部加上65535,然后在window-level的方法中将pixel_val按word取值(word是无符号类型,相当于取绝对值)进行判断,然后赋值即可(CT影像不能用word类型取值和赋值),就这么简单,以下是关键代码,祝你愉快!!!

 

procedure DCM_GetWidAndCenBySmallint(var DICOMDATA: TDICOMDATA; var Buffer: SMallIntp0);
var
  Value, Size, i: integer;
  min16, max16: integer;
begin
  Size := DICOMDATA.ImageColumns * DICOMDATA.ImageRows;

  Value := Buffer[0];
  max16 := Value;
  min16 := Value;
  i := 0;
  while i < Size do begin
    Value := Buffer;
    if Value < min16 then min16 := Value;
    if Value > max16 then max16 := Value;
    i := i + 1;
  end;

  if DICOMDATA.MaxIntensity = 0 then DICOMDATA.MaxIntensity := max16;

  if (DICOMDATA.MaxIntensity > 65534) then begin//这里对高CT值的数据进行处理
    i := 0;
    while i < (Size) do begin
      if Buffer >= 0 then
        Buffer := Buffer - 65535
      else
        Buffer := 65535 + Buffer;
      i := i + 1;
    end;
  end;

  DICOMDATA.WinCen := round(DICOMDATA.WindowCenter);
  DICOMDATA.WinWid := round(DICOMDATA.WindowWidth);
  DICOMDATA.ImgMin := min16;
  DICOMDATA.ImgMax := max16;
  DICOMDATA.ImgWid := DICOMDATA.ImgMax - DICOMDATA.ImgMin;
  DICOMDATA.ImgCen := DICOMDATA.ImgMin + ((DICOMDATA.ImgWid) shr 1);
  if DICOMDATA.WindowWidth <= 0 then begin
    DICOMDATA.WinCen := DICOMDATA.ImgCen;
    DICOMDATA.WinWid := DICOMDATA.ImgWid;
    DICOMDATA.WindowCenter := DICOMDATA.ImgCen;
    DICOMDATA.WindowWidth := DICOMDATA.ImgWid;
  end;
end;

procedure DCM_Scale16to8bit(var DICOMDATA: TDICOMDATA; var Buffer: SMallIntp0; var lOutBuff: pByteArray; DataLen: integer);
var
  Value, i, lScaleShl10, Size, lWid, lcen: integer;
  min16, max16: integer;
  PixelVal: integer;
  Modality_CT: boolean;
begin
  if Buffer = nil then exit;
  //影像是否是CT
  if (DICOMDATA.TransferSyntax = '1.2.840.10008.5.1.4.1.1.2') or (trim(DICOMDATA.Modality) = 'CT') then
    Modality_CT := true
  else
    Modality_CT := false;
  DICOMDATA.WinCen := round(DICOMDATA.WindowCenter);
  DICOMDATA.WinWid := round(DICOMDATA.WindowWidth);
  Size := DICOMDATA.ImageColumns * DICOMDATA.ImageRows;
  lcen := round((round(DICOMDATA.WindowCenter) - DICOMDATA.IntenIntercept) / DICOMDATA.IntenScale); // 截距/斜率
  lWid := (trunc((round(DICOMDATA.WindowWidth) / DICOMDATA.IntenScale) / 2));


  min16 := lcen - lWid; //15za
  max16 := lcen + lWid; //15za

  getmem(lOutBuff, Size);
  Size := Size - 1;
  Value := (max16 - min16);
  if (Value = 0) or (trunc((1024 / Value) * 255) = 0) then begin
    if DICOMDATA.WinWid > 1024 then begin
      for i := 0 to Size do
        lOutBuff := 128;
    end else begin
      for i := 0 to Size do
        if Buffer < DICOMDATA.WinCen then
          lOutBuff := 0
        else
          lOutBuff := 255;
    end;
  end else begin
    if Value = 0 then Value := 1;
    lScaleShl10 := trunc((1024 / Value) * 255); //value = range,Scale = 255/range
    for i := 0 to Size do begin
      //除CT外,其余的全部取正值
      if Modality_CT then begin
        if (Buffer) < min16 then
          lOutBuff := 0
        else if (Buffer) > max16 then
          lOutBuff := 255
        else
          lOutBuff := (((Buffer) - min16) * lScaleShl10) shr 10;
      end else begin //非CT
        if word(Buffer) < min16 then
          lOutBuff := 0
        else if word(Buffer) > max16 then
          lOutBuff := 255
        else
          lOutBuff := ((word(Buffer) - min16) * lScaleShl10) shr 10;
      end; 
    end;
  end;
  DICOMDATA.BitsStored := 8; //转换为8位
end;