Tile image acquisition in ZENcore

In this subforum specific Topics concerning ZEN Core, e.g workbenches, are discussed
CarlZeissMicroscopy3
Posts: 180
Joined: Wed May 20, 2020 10:10 am

Re: Tile image acquisition in ZENcore

Post by CarlZeissMicroscopy3 »

This is a very general question so I can only guess the answer.

imgage.CreateSubImage(...)

or

Zen.Processing.Utilities.CreateSubset(...)

are most probably the functions that you expect.

The latter has more capabilities and corresponds with Processing function "Create Image Subset" in the Zen GUI.

There are already proposals in the forum how to use it.
Andrei Poliakov
Posts: 13
Joined: Tue Jan 19, 2021 7:46 am

Re: Tile image acquisition in ZENcore

Post by Andrei Poliakov »

Just to make sure we understand each other correctly... my question was not about accessing individual tiles within the stitched tile image, but rather about accessing the stitched tile image itself. Does it exist as a programmatically accessible image object upon the execution of the experiment within the script, and how can I refer to it? Or should I rely on something like the experiment auto-saving the stitched image and then identifying and loading that saved file? The latter didn't seem to quite work on my first attempts but I will try again and also explore your latest suggestions, but will also greatly appreciate your answering the questions above. Thank you!
CarlZeissMicroscopy3
Posts: 180
Joined: Wed May 20, 2020 10:10 am

Re: Tile image acquisition in ZENcore

Post by CarlZeissMicroscopy3 »

Hello Andrei Poliakov,

accessing the stitched tile image 'itself' is not possible as a czi image does not work like this. One of the main reasons for that is the limit of 2 GB per image that comes from the .Net framework. Therefore tiles are always kept as tiles within the CZI.

One approach is to export the image as a whole, e.g. Processing tab, Method 'Image Export', Parameters: 'Use full set of dimensions'. Please keep in mind that the 2 GB restriction is valid for export as well.

Again, to provide reasonable support the complete workflow has to be revealed a bit ; - )
Andrei Poliakov
Posts: 13
Joined: Tue Jan 19, 2021 7:46 am

Re: Tile image acquisition in ZENcore

Post by Andrei Poliakov »

Thanks, I will try to get a better understanding of tiled czi images and come back. It was "kind of" easier with zvi, where a MosaiX image before stitching was indeed an ordered collection of tiles but after stitching would become pretty much a normal, just larger, image for most purposes I can think of. I will post with more details depending on my progress.

A question that remains though: I can perform tile acquisition in Zen manually and then save the result. It will be a single czi file with file size roughly X x Y times more than a singular image taken by an ordinary snap. Let us ignore the internal structure of that czi for the time being. Let us also assume the 2GB limit is not an issue right at this stage and we are not trying to reach or bypass it. How can I access that larger object in my code after performing a Tiles experiment programmatically (I am assuming here it is a ZenImage, which I understand now is not necessarily correct) and/or save it as one czi file for future use? Thank you!
CarlZeissMicroscopy3
Posts: 180
Joined: Wed May 20, 2020 10:10 am

Re: Tile image acquisition in ZENcore

Post by CarlZeissMicroscopy3 »

It was "kind of" easier with zvi, where a MosaiX image before stitching was indeed an ordered collection of tiles but after stitching would become pretty much a normal, just larger, image for most purposes I can think of.
You are obviously in the lucky position that the zvi working mechanism is still valid in your working environment. Generally speaking images tend to 'explode' in size and this is the reason why Zeiss had to move away from zvi and created the czi file format.

From my understanding you search for a solution to work differently than czi and Zen does. I would not generally recommend the following code but if your images are handy enough you can access the image via pixels/bytes.

Code: Select all

# Code Snippet - Works only for 'small' and 'simple' images

imageTiles = Zen.Application.ActiveDocument

width = int(imageTiles.Metadata.Width)
height = int(imageTiles.Metadata.Height)
pixelType = imageTiles.Metadata.PixelType

bytes = imageTiles.CopyPixelsToArray(pixelType)
imageComplete = ZenImage(width, height, pixelType)
imageComplete.CopyPixelsFromArray(bytes,pixelType)

Zen.Application.Documents.Add(imageComplete)
The resulting 'imageComplete' seems to be what you want (no tiles).
You can save 'imageComplete' as czi but I would recommend to keep the original czi images as well.
Andrei Poliakov
Posts: 13
Joined: Tue Jan 19, 2021 7:46 am

Re: Tile image acquisition in ZENcore

Post by Andrei Poliakov »

Hello again,

I managed to spend some time on this project recently and unfortunately am still having significant issues preventing me from progressing with automated tile acquisition. At the same time there are some findings relevant to our earlier discussion. Thus, this fairly large post. I am trying to be logical and at the same time clearly separate subtopics. The questions I have are also clearly marked and I will be extremely grateful if you can answer them for me.

1. Code that is proven to work

The code obtains a matrix set of single images over the sample area, saves them using prescribed filename format and logs the process. The small portion of code where the acquisition and saving actually occurs is:

Code: Select all

        stage.MoveTo(x_orig - float(i) * step_x, y_orig - float(j) * step_y)
        Zen.Acquisition.FindAutofocus(0)
        image = Zen.Acquisition.AcquireImage(True) # This is where acquisition happens !!!
        count = count + 1
        imagename = prefix + "_" + str(count) + "_x" + str(i+1) + "_y" + str(j+1) + ".czi"
        image.Save(path + imagename)
        Zen.Application.ActiveDocument = image
2. Attempting to acquire Tiles image instead of single images

The following code is supposed to replace the “acquisition line” (the one with comment) above:

Code: Select all

ze = ZenExperiment()
ze.Load(path + "3x4 Auto1.czexp")
Zen.Acquisition.Execute(ze)
#image = WHAT???
The experiment above is a Tiles experiment recorded in ZEN Blue, with coordinates in <TileRegions> and <SingleTileRegions> massaged to fit the calculated stage position (I am not trying other adjustments yet, no point as proof of concept doesn't work). When executed the code seems to perform stage movement corresponding to the desired tile acquisition. But… I don’t understand how to refer to the resulting image! I expect to be able to have a line of code similar to image = Zen.Acquisition.AcquireImage(True) but what would it be???

Q1: How to refer to the image that is the result of the experiment in the code?

This particular experiment in ZEN Blue actually is configured to auto-save the resulting image. I hoped to use that, but when the experiment is executed in ZENcore macro no saving seems to occur, the experiment result simply goes nowhere.

Q2: Is auto-save meant to work in this context? If yes, why it doesn’t work for me? If no, I guess it sends me back to Q1.

3. Converting from Tiles to single image

The code you supplied seems to work in general, although the resulting image displays much darker and loses scaling. I assume some metadata also need to be copied across, however at the moment it looks like there is no need for that, as the Tiles image behaves as expected during analysis (I used a manually acquired Tiles image for testing). That means if I can acquire Tiles images in automated mode no further conversion will be required. At least some good news, but I still need help with the questions above.

4. (Possibly) converting from a set of tiles to a Tiles image???

One thing that came to my mind during those trials: would it be possible instead of using a pre-recorded experiment and massaging it into a different setup (doesn’t sound terribly reliable) to actually acquire a set of overlapping single images and then somehow send them to a Tiles image? The stage movement formula seems to be fairly trivial, I can see that the software estimates the Tiles image size precisely as pixel_size * (N - (N - 1) * overlap) * scaling. I can certainly take the images at the required positions and in the required meander order. It looks like I can access Zen.Processing.Transformation.Geometric.Stitching() but it takes only one image (presumably a Tiles image already) as input.

Q3: Is there a mechanism to build a Tiles image from properly acquired individual images?

Please consider those questions and give me the answers where they make sense, or any other guidance to point me in the right direction. Many thanks in advance!
CarlZeissMicroscopy3
Posts: 180
Joined: Wed May 20, 2020 10:10 am

Re: Tile image acquisition in ZENcore

Post by CarlZeissMicroscopy3 »

Hello Andrei Poliakov,

1. Code that is proven to work

Yes, very basic way, possible but not really recommended when proceeding in Zen.

2. Attempting to acquire Tiles image instead of single images

As e.g. intelliSens tells the Execute-Command returns a ZenImage

zenImage = Zen.Acquisition.Execute(zenExperiment)

There is no need to use auto-save as ZenImage has a Save-Command.
I hope this answers your foremost question(s) ; - )

3. Converting from Tiles to single image

if I can acquire Tiles images in automated mode no further conversion will be required
Yes, this is the ‘normal’ way to go on in Zen

4. (Possibly) converting from a set of tiles to a Tiles image???

I would not really recommend that. There are two alternatives.

First, modifying the XML file of the ‘experiment’, kind of ‘hard core’.

Second, there is a good support within the Experiment setting of OAD.

After selecting your experiment in the GUI of Zen run
experiment = Zen.Acquisition.Experiments.ActiveExperiment
after this please type
experiment.tile while IntelliSense will show you the capabilities related to tiles e.g.
like Add, Clear, Modify etc.
with blockIndex most likely always 0 in your case.
Andrei Poliakov
Posts: 13
Joined: Tue Jan 19, 2021 7:46 am

Re: Tile image acquisition in ZENcore

Post by Andrei Poliakov »

Many thanks for your help, I seem to have moved ahead at last. The script can now take the pre-defined experiment file, make some changes (mostly by manual editing at this stage, but see below) execute it and save results. I spent some time struggling to get the proper ImageOrientation for correct stitching (appears to be 3 for 180 degree rotation). My other issue, still unresolved, is the behaviour of the lamp. It seems to go to standby mode every time the stage moves between tile positions even after I have changed all lamp-related settings in the file to “Manual” and “50”. This seems to be of a concern: as the lamp keeps jumping between nearly 0 and 50 I cannot rely on the illumination being stable; also it is probably not good for the lamp’s lifetime. Can you suggest the setting that will prevent the lamp from going standby?

Later I tried to do some programmatic changes to the experiment using ClearTileRegionsAndPositions() followed by AddRectangleExperimentRegion(). I assume similar result can be achieved by a combination of ModifyTileRegionsSize() and ModifyTileRegionsWithXYZOffset(), haven’t fully tested it yet. Once again, the results are mixed. Apparently I can change the region size and starting XYZ position, good. But I cannot change tile matrix parameters this way. I assumed these parameters can be derived by the system from the region size, which kind of proved to be the case – but the behaviour is not to my expectations. For example, when I set up (each dimension) to be:

pixel_size * 5.5 * scaling (where 5.5 = 6 – 5 * 0.1)

I expect the system to take 6 images per dimension with 10% overlap. It takes 7! With the same 10% overlap, so the overall image size is noticeably larger than the region size. When I set it to:

pixel_size * 5 * scaling (where 5 = 6 – 5 * 0.2)

I expect 6 images per dimension with 20% overlap. Now I get those 6 images, but once again with 10% overlap, so the image is also larger than requested.

There probably is some logic in how the system decides on the tile parameters as they don’t really look random, the logic just keeps evading me. I mean, it looks like I always get 10% overlap and I can live with it, I just need to understand what region size to ask for to get the result I actually want. Almost looks like “ask for 20% expecting to get 10”, but who knows? Alternatively I can do the “hardcore” experiment file editing and explicitly supply matrix dimensions, that may work correctly. But do you have a better idea?
CarlZeissMicroscopy3
Posts: 180
Joined: Wed May 20, 2020 10:10 am

Re: Tile image acquisition in ZENcore

Post by CarlZeissMicroscopy3 »

Happy to hear that you have moved ahead.

I’m not a ‘Tiles&Position’ expert so I can give you just some general hints how to go on:

First of all, yes there is some logic ‘inside’. From my understanding it is the same as coming from the GUI. E.g. if a region is added to a Tiles Experiment then Zen calculates the tiles that are needed to cover the region. You will also find that the overlap is defined in the GUI as well so the given overlap will be part of the calculation. So understanding how the GUI works is a key to work with the functions of OAD as OAD tries to ‘imitate’ the actions from the GUI as much as possible.
Again, from my understanding a given region will be ‘covered’ by tiles according to overlap, objective etc. but the region is not the boundary (width/height) of the resulting image.

Second, ZenExperiment has a SaveAs so you can save the changed Experiment with another name and load it in Zen to get a visual representation or have a ‘direct’ look inside the xml-file.
Post Reply