Search code examples
dm-script

Reading in multiple STEM signals into multiple datacubes


I've written a through focus STEM acquisition script that reads in an image using the DSAcquire function, where I specify the signal to be read in with DSAcquireData(img, signalindex, etc.).

The nice thing about the above is that I can read in the image without it appearing on screen, copy it into a datacube, and then acquire the next one in the series, etc.

If I want to use two signals instead of one (eg HAADF and BF), it looks like the only way to do this is to use DSStartAcquisition after setting the digiscan parameters?

How should I go about copying signals into two preallocated image stacks (stack1, stack2)? Preferably without tens of images cluttering the screen (but ideally with some measure of progress?)


Solution

  • One way of doing this - by iterating over x individual acquisitions is a straight forward expansion of the F1 help examples:

    enter image description here

    // Acquire 2 signals simultaneously, e.g. HAADF and BF detector
    
    
    number paramID
    number width    = 512 // pixel
    number height   = 512 // pixel
    number rotation = 0   // degree
    number pixelTime= 2   // microseconds
    number lSynch   = 1   // activated
    paramID = DSCreateParameters( width, height, rotation, pixelTime, lSynch )
    
    number signalIndex, dataType, selected, imageID
    signalIndex = 0
    dataType    = 2 // 2 byte data
    selected    = 1 // acquire this signal
    
    image img1 := IntegerImage( "Signal 1", dataType, 0, width, height )
    img1.ShowImage()
    imageID     = img1.ImageGetID() // use displayed image
    DSSetParametersSignal( paramID, signalIndex, dataType, selected, imageID )
    
    signalIndex = 1
    dataType    = 2 // 2 byte data
    selected    = 1 // acquire this signal
    
    image img2 := IntegerImage( "Signal 1", dataType, 0, width, height )
    img2.Showimage()
    imageID     = img2.ImageGetID() // use displayed image
    DSSetParametersSignal( paramID, signalIndex, dataType, selected, imageID )
    
    number continuous  = 0 // 0 = single frame, 1 = continuous
    number synchronous = 1 // 0 = return immediately, 1 = return when finished
    
    // Create stack to copy data to
    number nplanes = 10
    image stack1 := img1.ImageClone()
    stack1.ImageResize(3,width,height,nplanes)
    stack1.SetName("Signal 1 (stack)")
    stack1.ShowImage()
    
    image stack2 := img2.ImageClone()
    stack2.ImageResize(3,width,height,nplanes)
    stack2.SetName("Signal 2 (stack)")
    stack2.ShowImage()
    
    //Quickly arrange image
    EGUPerformActionWithAllShownImages("arrange")
    
    // Iterated acquisition
    for( number i=0; i<nPlanes; i++ )
    {
        DSStartAcquisition( paramID, continuous, synchronous )
        // Copy data
        stack1.slice2(0,0,i, 0,width,1, 1,height,1) = img1
        stack2.slice2(0,0,i, 0,width,1, 1,height,1) = img2
    }
    DSDeleteParameters( paramID ) // remove parameters from memory
    

    However, this will restart a new Digiscan acquisition at each frame. You might want to prefer doing this with a continuous acquisition and an image listener instead.

    For this, you would most likely hook up an image-listener as described in the F1 help here: enter image description here

    The Digiscan acquisition - depending on the speed - will update the image several times per frame, so you will need some check if it's end-of-frame.

    One way to do this would be to use a data_value_changed event and then check if the last pixel in the image has changed value. Another option would be to use the tags_changed event, as apparently the tags of the acquisition image are update once per frame. Both options have some potential issues, though.

    See also this very relevant recent question on this topic: Fastest way to see which pixel has changed when using a listener