Using Zerene To Measure Rail Setup and Lens Telecentricity

Have questions about the equipment used for macro- or micro- photography? Post those questions in this forum.

Moderators: Pau, rjlittlefield, ChrisR, Chris S.

Posts: 1237
Joined: Wed Jul 01, 2015 3:38 pm
Location: California/Shenzhen

Using Zerene To Measure Rail Setup and Lens Telecentricity

Post by mjkzz »

Zerene is an amazing tool to do a lot of other thing than stacking. It has a log window (under menu Options->View Console Log). You can copy and paste (with log view open, Ctrl-A and Ctrl-C and open a Notepad and Ctrl-V) these log data into a notepad and do some analysis with it.

However, the log data contains enormous amount of information and I have been asked about how to analyze these data by several people already, so I decided to write a Python app to extract relevant info out of the log file. This is my VERY first python app, so excuse for any inefficient programming. The reason for me to choose Python is that it is ubiquitous and seemingly popular among tinkerers.

What you can do with it? Well, the app extracts xoffset, yoffset, scale and rotate values from the log file. Here is my understanding of them.

xoffset and yoffset are translational shifts, ie, moving up/down left/right.

scale is CUMULATIVE images size change in the stack. by cumulative, it means it is not between two consecutive images in the stack, but it is between the nth image and the very first image.

rotate is rotational shift between two images, I am not sure if it is cumulative or sequential (ie, between to consecutive images).

These parameters can be used to evaluate a stacking setup. But very important usage (for me) is evaluation of telecentricity using scale factor, which seems to be rather difficult test without Zerene. For a "true" telecentric lens, the scale value should be between 0.9998 and 1.0002 between two images one DOF apart. But I have been doing at least 4 samples, some time 8, between one DOF apart.

Anyways, here is one example of output (running Ubuntu)


In above picute, it looks like I have a mis-alignment between optical axis and motion axis, the xoffset keep increasing (or decreasing as it is a negative number). See my other post on how to estimate correction.

To run the code, you must have Python (free) installed on your system and this code was developed using IDLE.

Code: Select all

# written by Peter Y Lin
# rev 0.1
# use it at your own risk
# this is a Python program thst reads Console output from Zerene
# stacker and writes out a .csv file that contains X, Y alignment
# information so that you can use it with Excel to analyse data
# this Python app is rather simple, the input file, "zerene.txt"
# must be in the same directory as the Python app and the output
# file will be written to the same directory with name of
# "zerene.csv"

sensor_w = 5184     # sensor width in pixels
sensor_h = 3456     # sensor height in pixels

strXOffset = "xoffset = "   # these appears in the log file for all xoffset
strYOffset = "yoffset = "   # these appears in the log file for all yoffset
strRotate  = "rotate = "
strScale   = "scale = "     
strXValue  = ""
strYValue  = ""
strRValue  = ""
strSValue  = ""
strCSV     = ""
sIndex  = 0
eIndex  = 0

# open text file for processing
ftxt = open("zerene.txt", "r");
# create csv file for output
fcsv = open("zerene.csv", "w");

# write out column names
fcsv.write("'xoffset', 'yoffset', 'scale', 'rotate'\n\r");

for line in ftxt:
    strCSV = "";
    sIndex = line.find(strXOffset);
    if sIndex >= 0 :
        # found beginning of xoffset, now find the end
        eIndex = line[sIndex+len(strXOffset):].find(",");
        if eIndex >= 0:
            # found xoffset
            strXValue = line[sIndex+len(strXOffset): sIndex+len(strXOffset) + eIndex];            
            sIndex = line.find(strYOffset);
            if sIndex >= 0:
                # found beginning of yoffset, now find the end
                eIndex = line[sIndex+len(strYOffset):].find(",");
                if eIndex >= 0:
                    # found yoffset
                    strYValue = line[sIndex+len(strYOffset): sIndex+len(strYOffset) + eIndex];
                    sIndex = line.find(strScale);
                    if sIndex >= 0:
                        eIndex = line[sIndex+len(strScale):].find(",");
                        if eIndex >= 0:
                            # found scale factor
                            strSValue = line[sIndex+len(strScale): sIndex+len(strScale) + eIndex];
                            sIndex = line.find(strRotate);
                            if sIndex >= 0:
                                # found beginning of rotate, now find the end
                                eIndex = line[sIndex+len(strRotate):].find("\n");
                                if eIndex >= 0:
                                    # found rotate
                                    strRValue = line[sIndex+len(strRotate): sIndex+len(strRotate) + eIndex];
                                    # assemble CSV string to write out
                                    strCSV = "'" + strXValue + "','" + strYValue + "','" + strSValue + "','" + strRValue + "'\n";
                                    # strCSV = strXValue + "," + strYValue + "," + strRValue + "\n";
                                    # write to comma separated value file


Site Admin
Posts: 21278
Joined: Tue Aug 01, 2006 8:34 am
Location: Richland, Washington State, USA

Post by rjlittlefield »

All of the numbers in the log and the .zsj project file are cumulative, that is, each image against the first.

The meaning of the values is explained at ... 201#134201 .


Posts: 1237
Joined: Wed Jul 01, 2015 3:38 pm
Location: California/Shenzhen

Post by mjkzz »

thanks, Rik

Post Reply Previous topicNext topic