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?)
One way of doing this - by iterating over x individual acquisitions is a straight forward expansion of the F1 help examples:
// 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:
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