Plot 如何创建用于显示Ct扫描的julia配色方案Makie.jl

Plot 如何创建用于显示Ct扫描的julia配色方案Makie.jl,plot,julia,medical-imaging,Plot,Julia,Medical Imaging,我使用makie.jl和slicesNumb对PET/CT扫描进行可视化,我有衰减值的3d阵列,我用滑块显示热图,并改变切片-这很好,我有两个问题 我不知道如何定义自定义颜色贴图(基本上,我需要能够指定高于某个阈值的所有颜色都是黑色,低于白色的所有颜色,以及介于两者之间的值的灰度值与衰减值成比例) 2) 我希望能够显示在我的图像上(快速热图),我可以控制透明度-像素的alpha值-以便显示一些注释/PET 代码,但没有这两个功能,以及它的外观 using GLMakie ```@doc sim

我使用makie.jl和slicesNumb对PET/CT扫描进行可视化,我有衰减值的3d阵列,我用滑块显示热图,并改变切片-这很好,我有两个问题

  • 我不知道如何定义自定义颜色贴图(基本上,我需要能够指定高于某个阈值的所有颜色都是黑色,低于白色的所有颜色,以及介于两者之间的值的灰度值与衰减值成比例)
  • 2) 我希望能够显示在我的图像上(快速热图),我可以控制透明度-像素的alpha值-以便显示一些注释/PET

    代码,但没有这两个功能,以及它的外观

    using GLMakie
    
    ```@doc
    simple display of single image - only in transverse plane
    ```
    function singleCtScanDisplay(arr ::Array{Number, 3}) 
      
    
      fig = Figure()
      sl_x = Slider(fig[2, 1], range = 1:1:size(arr)[3], startvalue = 40)
      ax = Axis(fig[1, 1])
      hm = heatmap!(ax, lift(idx-> arr[:,:, floor(idx)], sl_x.value) ,colormap = :grays)
      Colorbar(fig[1, 2], hm)
    
      
      fig
    
    end
    


    谢谢你的帮助

    您可以使用
    颜色
    颜色方案工具
    ,但需要根据阈值添加方案的顶部和底部

    using Colors, ColorSchemeTools
    
    truemin = 0
    truemax = 600
    max_shown_black = 20
    min_shown_white = 500
    
    data = rand(truemin:truemax, (500, 500, 20))
    
    grayscheme =  [fill(colorant"black", max_shown_black - truemin + 1);
                   collect(make_colorscheme(identity, identity, identity,
                       length = min_shown_white - max_shown_black - 1));
                   fill(colorant"white", truemax - min_shown_white + 1)]
    
     
    

    为了控制alpha,我会添加一个带有alpha滑块的弹出窗口。以一些可分发的DICOM工具为例。

    我最终管理了它,基本上我加载了存储在hdf5中的三维数据(我使用python从原始数据加载到hdf5中)

    它可以查看横向切片,并在将显示在主图像上的遮罩中注释三维路径

    exmpleH = @spawnat persistenceWorker Main.h5manag.getExample()
    minimumm = -1000
    maximumm = 2000
    arrr= fetch(exmpleH)
    imageDim = size(arrr)
    using GLMakie
    maskArr = Observable(BitArray(undef, imageDim))
    MyImgeViewer.singleCtScanDisplay(arrr, maskArr,minimumm, maximumm)
    
    现在定义所需的模块

    ```@doc
    functions responsible for displaying medical image Data
    ```
    using DrWatson
    @quickactivate "Probabilistic medical segmentation"
    
    
    module MyImgeViewer
    
    using GLMakie
    using Makie
    #using GeometryBasics
    using GeometricalPredicates
    using ColorTypes
    using Distributed
    using GLMakie
    using Main.imageViewerHelper
    using Main.workerNumbers
    ## getting id of workers 
    
    ```@doc
    simple display of single image - only in transverse plane we are adding also a mask  that 
    arrr - main 3 dimensional data representing medical image for example in case of CT each voxel represents value of X ray attenuation
    minimumm, maximumm - approximately minimum and maximum values we can have in our image
    ```
    function singleCtScanDisplay(arrr ::Array{Number, 3}, maskArr , minimumm, maximumm) 
    #we modify 2 pixels just in order to make the color range constant so slices will be displayed in the same windows
    arrr[1,1,:].= minimumm 
    arrr[2,1,:].= maximumm 
      
    
    imageDim = size(arrr) # dimenstion of the primary image for example CT scan
    slicesNumb =imageDim[3] # number of slices 
    
    #defining layout variables
    scene, layout = GLMakie.layoutscene(resolution = (600, 400))
    ax1 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
    ax2 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
    
    #control widgets
    sl_x =layout[2, 1]= GLMakie.Slider(scene, range = 1:1: slicesNumb , startvalue = slicesNumb/2 )
    sliderXVal = sl_x.value
    
    
    #color maps
    cmwhite = cgrad(range(RGBA(10,10,10,0.01), stop=RGBA(0,0,255,0.4), length=10000));
    greyss = createMedicalImageColorSchemeB(200,-200,maximumm, minimumm )
    ####heatmaps
    
    #main heatmap that holds for example Ct scan
    currentSliceMain = GLMakie.@lift(arrr[:,:, convert(Int32,$sliderXVal)])
    hm = GLMakie.heatmap!(ax1, currentSliceMain ,colormap = greyss) 
    
    #helper heatmap designed to respond to both changes in slider and changes in the bit matrix
    currentSliceMask = GLMakie.@lift($maskArr[:,:, convert(Int32,$sliderXVal)])
    hmB = GLMakie.heatmap!(ax1, currentSliceMask ,colormap = cmwhite) 
    
    #adding ability to be able to add information to mask  where we clicked so in casse of mit matrix we will set the point where we clicked to 1 
    indicatorC(ax1,imageDim,scene,maskArr,sliderXVal)
    
    #displaying
    colorB = layout[1,2]= Colorbar(scene, hm)
    GLMakie.translate!(hmB, Vec3f0(0,0,5))  
    
    scene
    
    end
    
    ```@doc
    inspired by   https://github.com/JuliaPlots/Makie.jl/issues/810
    Generaly thanks to this function  the viewer is able to respond to clicking on the slices and records it in the supplied 3 dimensional AbstractArray
      ax - Axis which store our heatmap slices which we want to observe wheather user clicked on them and where
      dims - dimensions of  main image for example CT
      sc - Scene where our axis is
      maskArr - the 3 dimensional bit array  that has exactly the same dimensions as main Array storing image 
      sliceNumb - represents on what slide we are on currently on - ussually it just give information from slider 
    ```
    function indicatorC(ax::Axis,dims::Tuple{Int64, Int64, Int64},sc::Scene,maskArr,sliceNumb::Observable{Any})
      register_interaction!(ax, :indicator) do event::GLMakie.MouseEvent, axis
      if event.type === MouseEventTypes.leftclick
        println("clicked")
        #@async begin
          #appropriately modyfing wanted pixels in mask array
       @async calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb)            
        #  
        #  
        #  println("fetched" + fetch(maskA))
    
        #  finalize(maskA)
        #end
        return true
        #print("xMouse: $(xMouse)  yMouse: $(yMouse)   compBoxWidth: $(compBoxWidth)  compBoxHeight: $(compBoxHeight)   calculatedXpixel: $(calculatedXpixel)  calculatedYpixel: $(calculatedYpixel)      pixelsNumbInX  $(pixelsNumbInX)         ") 
      end
      
    end
    end
    ```@doc
    wrapper for calculateMouseAndSetmask  - from imageViewerHelper module
      given mouse event modifies mask accordingly
      maskArr - the 3 dimensional bit array  that has exactly the same dimensions as main Array storing image 
      event - mouse event passed from Makie
      sc - scene we are using in Makie
      ```
    function calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb) 
      maskArr[] = calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb)
    end
    
    
    end #module
    
    和助手方法

    ```@doc
    functions responsible for helping in image viewer - those functions are  meant to be invoked on separate process
    - in parallel
    ```
    using DrWatson
    @quickactivate "Probabilistic medical segmentation"
    
    module imageViewerHelper
    using Documenter
    using ColorTypes
    using Colors, ColorSchemeTools
    using Makie
    
    export calculateMouseAndSetmask
    export createMedicalImageColorSchemeB
    # using AbstractPlotting
    ```@doc
      given mouse event modifies mask accordingly
      maskArr - the 3 dimensional bit array  that has exactly the same dimensions as main Array storing image 
      event - mouse event passed from Makie
      sc - scene we are using in Makie
      ```
    function calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb) 
      #position from top left corner 
      xMouse= Makie.to_world(sc,event.data)[1]
      yMouse= Makie.to_world(sc,event.data)[2]
      #data about height and width in layout
      compBoxWidth = 510 
      compBoxHeight = 510 
      #image dimensions - number of pixels  from medical image for example ct scan
      pixelsNumbInX =dims[1]
      pixelsNumbInY =dims[2]
      #calculating over which image pixel we are
      calculatedXpixel =convert(Int32, round( (xMouse/compBoxWidth)*pixelsNumbInX) )
      calculatedYpixel =  convert(Int32,round( (yMouse/compBoxHeight)*pixelsNumbInY ))
      sliceNumbConv =convert(Int32,round( sliceNumb[] ))
      #appropriately modyfing wanted pixels in mask array
      return markMaskArrayPatch( maskArr ,CartesianIndex(calculatedXpixel, calculatedYpixel, sliceNumbConv  ),2)
    end
    
    
    
    ```@doc
      maskArr - the 3 dimensional bit array  that has exactly the same dimensions as main Array storing image 
      point - cartesian coordinates of point around which we want to modify the 3 dimensional array from 0 to 1
    
    ```
    function markMaskArrayPatch(maskArr, pointCart::CartesianIndex{3}, patchSize ::Int64)
    
      ones = CartesianIndex(patchSize,patchSize,patchSize) # cartesian 3 dimensional index used for calculations to get range of the cartesian indicis to analyze
      maskArrB = maskArr[]
      for J in (pointCart-ones):(pointCart+ones)
        diff = J - pointCart # diffrence between dimensions relative to point of origin
          if cartesianTolinear(diff) <= patchSize
            maskArrB[J]=1
          end
          end
    return maskArrB
    end
    ```@doc
    works only for 3d cartesian coordinates
      cart - cartesian coordinates of point where we will add the dimensions ...
    ```
    function cartesianTolinear(pointCart::CartesianIndex{3}) :: Int16
       abs(pointCart[1])+ abs(pointCart[2])+abs(pointCart[3])
    end
    
    ```@doc
    creating grey scheme colors for proper display of medical image mainly CT scan
    min_shown_white - max_shown_black range over which the gradint of greys will be shown
    truemax - truemin the range of values in the image for which we are creating the scale
    ```
    #taken from https://stackoverflow.com/questions/67727977/how-to-create-julia-color-scheme-for-displaying-ct-scan-makie-jl/67756158#67756158
    
    function createMedicalImageColorSchemeB(min_shown_white,max_shown_black,truemax,truemin ) ::Vector{Any} 
    # println("max_shown_black - truemin + 1")
    # println(max_shown_black - truemin + 1)
    # println(" min_shown_white - max_shown_black - 1")
    # println( min_shown_white - max_shown_black - 1)
    # println("truemax - min_shown_white + 1")
    # println(truemax - min_shown_white + 1)
    
    return  [fill(colorant"black", max_shown_black - truemin + 1);
                   collect(make_colorscheme(identity, identity, identity,
                       length = min_shown_white - max_shown_black - 1));
                   fill(colorant"white", truemax - min_shown_white + 1)]
    
    end
    
    
    
    
    
    end #module
    
    ``@doc
    在图像查看器中负责帮助的函数-这些函数将在单独的进程中调用
    -并行
    ```
    使用DrWatson
    @快速激活“概率医学分段”
    模块图像查看器帮助器
    使用文档管理器
    使用颜色类型
    使用颜色、颜色模式工具
    使用Makie
    导出calculateMouseAndSetmask
    导出createMedicalImageColorSchemeB
    #使用抽象绘图
    ```@医生
    给定的鼠标事件会相应地修改掩码
    maskArr-与存储图像的主阵列的尺寸完全相同的三维位阵列
    事件-从Makie传递的鼠标事件
    sc-我们在Makie中使用的场景
    ```
    函数calculateMouseAndSetmask(maskArr、event、sc、dims、sliceNumb)
    #位置从左上角开始
    xMouse=Makie.to_world(sc,event.data)[1]
    yMouse=Makie.to_world(sc,event.data)[2]
    #关于布局中的高度和宽度的数据
    compBoxWidth=510
    compBoxHeight=510
    #图像尺寸-医学图像的像素数,例如ct扫描
    pixelsumbinx=dims[1]
    像素亮度=dims[2]
    #计算我们所使用的图像像素
    calculatedXpixel=转换(Int32,圆形((xMouse/compBoxWidth)*像素Mbinx))
    calculatedYpixel=转换(Int32,圆形((Y使用/compBoxHeight)*像素MB))
    sliceNumbConv=convert(Int32,圆形(sliceNumb[]))
    #在遮罩阵列中适当地修改所需像素
    返回markMaskArrayPatch(maskArr,CartesianIndex(calculatedXpixel,calculatedYpixel,sliceNumbConv),2)
    结束
    ```@医生
    maskArr-与存储图像的主阵列的尺寸完全相同的三维位阵列
    点-要将三维数组从0修改为1的点的笛卡尔坐标
    ```
    函数markMaskArrayPatch(maskArr,pointCart::CartesianIndex{3},patchSize::Int64)
    ones=笛卡尔指数(patchSize,patchSize,patchSize)#笛卡尔三维指数,用于计算以获得要分析的笛卡尔指数范围
    maskArrB=maskArr[]
    对于J英寸(点车1个):(点车+1个)
    diff=J-点车#相对于原点的尺寸差异
    
    如果cartesianTolinear(diff)可能有ColorSchemes.jl和ColorSchemeTools.jl的帮助?