Hi Susan,
Have a look at Example 25 from the ZOS-API Syntax Help. You can find it from the OpticStudio interface by clicking Programming...ZOS-API Help...ZOS-API Syntax Help. In the Help document, which just opened, click on the Examples menu, and select Example 25 > MATLAB.
This is a rather complex example, but the interesting bit is how you setup your Detector Color after you've run a raytrace:
% Creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer);
det_settings = det.GetSettings();
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor;
det.ApplyAndWaitForCompletion();
And how you can read its RGB values:
% Creates System.Single[] buffers to store pixel data
rData = NET.createArray('System.Single', (x_pixel * y_pixel));
gData = NET.createArray('System.Single', (x_pixel * y_pixel));
bData = NET.createArray('System.Single', (x_pixel * y_pixel));
% Loads RGB data into System.Single buffer
det_raw = det.GetResults().DataGridsRgb.Get(0);
det_raw.FillValues((x_pixel * y_pixel), rData, gData, bData);
% Converts buffer to RGB array; rotates & resizes RGB array
dData = zeros(y_pixel, x_pixel, 3) - 1;
dData(:,:,1) = rot90(reshape(rData.double ./ 255, x_pixel, y_pixel));
dData(:,:,2) = rot90(reshape(gData.double ./ 255, x_pixel, y_pixel));
dData(:,:,3) = rot90(reshape(bData.double ./ 255, x_pixel, y_pixel));
It calls for the GetResults().DataGridsRgb.Get(0) method, and not the GetAllDetectorData() method you used, which I think is confined to monochromatic data.
Let me know if this helps as I didn't try it myself with MATLAB (I don't own a licence at the moment).
PS: from what I know, the ZOS-API will retrieve your data in a Double-format with 64-bits precision in each color channel, and store it into a 'double' 3D MATLAB matrix (third dimension is RGB). It is up to you to downscale it to 8-bits before saving (let me know if you need help with that).
Take care,
David
I got a bit uncertain now. The question is if the images are rgb or not. I think i confused the format they are saved as. The images in ZEMAX looks black/gray/white. So I don't want the images in blue/green/yellow scale etc..
Do you think your code example above would be able to save those as gray-scale as well. Yes, checking i see that I have the Inverse Gray Scale as shown as in ZEMAX, so the images I save manually there are saved like that and later in MATLAB.
I have to check your code next week.
Hi Susan,
The image is stored as a 3D matrix in MATLAB, the first two dimensions are the pixels of your image, and the third one is the color channel. Index 0 is the red component, 1 is the green component, and 2 is the blue component.
You can use this matrix to save it as an rgb-jpeg, but you can also take the mean value along the third dimension to save a grayscale image. Does this make sense?
Let me know once you had a chance to look at the code, which is not from me by the way. Its an OpticStudio built-in example.
Take care,
David
Ok, I tried a bit before heading home.
I get error at:
% Loads RGB data into System.Single buffer
det_raw = det.GetResults().DataGridsRgb.Get(0);
MATLAB says;
Error using Analysis_infinity_v2>BeginApplication (line 130)
Attempting to access the property or method of an invalid object.
Error in Analysis_infinity_v2 (line 14)
r = BeginApplication(TheApplication, args);
My detector is at row 30.
Should I not define that somewhere?
I am comfused why it is zero at .Get(0).
I also tied with .Get(30). Same issue.
My MATLAB code:
Some initial code here ..
TheSystem.LoadFile(testFile,true);
% Initializes NCE and loads surfaces
% Non-sequential component editor
% Create result file
writeResultToFileTitle(resultDir);
xfoc = 75; % focallengths
for zPos = [100, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 1200, 2000, 3000,4000]
TheAnalyses = TheSystem.Analyses;
% Non-sequential component editor
TheNCE = TheSystem.NCE;
% change eye distace
o26 = TheNCE.GetObjectAt(26); % rad 26
% Moves the field stop infront of the Retina
writeZPosition(o26, zPos);
TheSystem.Save;
% Set focus
o30 = TheNCE.GetObjectAt(30); % rad 30
% Moves the field stop infront of the Retina writeZPosition(o30, xfoc);
% saves file to disk to expose all objects
TheSystem.Save;
% Run Ray Trace
runRayTrace(TheSystem);
% o30 = TheNCE.GetObjectAt(30);
% Do anlysis of the detector (30) Retina
o30_results = doRayTraceAnalysis(TheAnalyses, 30);
% Get the total power and plot the intensity
o30_totalPower = getTotalDetectorPower(o30_results, resultDir, zPos);
% Creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer);
det_settings = det.GetSettings();
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor;
det.ApplyAndWaitForCompletion();
% Setup detector color
x_width = 6;
y_width = 6;
x_pixel = 800;
y_pixel = 800;
close all;
figure('OuterPosition',[0, 250, 1000, 500])
% for a = 1:TheMCE.NumberOfConfigurations
% TheMCE.SetCurrentConfiguration(a);
a = 1;
% % Setup and run the ray trace
% NSCRayTrace = TheSystem.Tools.OpenNSCRayTrace();
% NSCRayTrace.ClearDetectors(0);
% NSCRayTrace.SplitNSCRays = false;
% NSCRayTrace.ScatterNSCRays = false;
% NSCRayTrace.UsePolarization = false;
% NSCRayTrace.IgnoreErrors = true;
% NSCRayTrace.SaveRays = false;
% NSCRayTrace.RunAndWaitForCompletion();
% NSCRayTrace.Close();
% fprintf('Finished ray trace\n');
%
%! [e25s06_m]
% Creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer);
det_settings = det.GetSettings();
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor;
det.ApplyAndWaitForCompletion();
%! [e25s06_m]
% Creates System.Single[] buffers to store pixel data
rData = NET.createArray('System.Single', (x_pixel * y_pixel));
gData = NET.createArray('System.Single', (x_pixel * y_pixel));
bData = NET.createArray('System.Single', (x_pixel * y_pixel));
%! [e25s07_m]
% Loads RGB data into System.Single buffer
det_raw = det.GetResults().DataGridsRgb.Get(30);
det_raw.FillValues((x_pixel * y_pixel), rData, gData, bData);
%! [e25s07_m]
% Converts buffer to RGB array; rotates & resizes RGB array
dData = zeros(y_pixel, x_pixel, 3) - 1;
dData(:,:,1) = rot90(reshape(rData.double ./ 255, x_pixel, y_pixel));
dData(:,:,2) = rot90(reshape(gData.double ./ 255, x_pixel, y_pixel));
dData(:,:,3) = rot90(reshape(bData.double ./ 255, x_pixel, y_pixel));
% Plots detector color values
subplot(1, double(TheMCE.NumberOfConfigurations), double(a))
imagesc(dData,'X',[-x_width x_width],'Y',[-y_width y_width]);
axis equal tight;colormap('jet');
% str = sprintf('Config = %i');
% title(str);
% Save and Close
TheAnalyses.CloseAllAnalyses;
TheSystem.SaveAs(testFile);
Hi Susan,
You do not need to specify where your detector is if you know the pixel size (to allocate the memory for the MATLAB matrix). Let me explain, what you do with this line:
TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
Is you effectively create and open a new Detector Viewer analysis window, and the Detector represented in the Detector Viewer is a setting of the Detector Viewer itself. You can also see this directly in OpticStudio, in a Detector Viewer window, you can press Settings...Detector, and see what Detector it picks its data from. If you have only one detector, it will use this one by default. If you have more than a single detector, it'll pickup the first one in the non-sequential data editor. It is not shown in this example, but you can change the Detector programatically with this line:
det_settings.Detector.SetDetectorNumber(30)
Which you would put just after the line where you retrieve the analysis settings:
det_settings = det.GetSettings()
In Example 25 though, they have their Detector Color in Object 5 (called o5 in the code). And they use it to setup the dimension of the detector in pixels. However, I don't think this is relevant for you, so you might want to ignore it at first.
You should not use:
det.GetResults().GetDataGridRgb(30)
Because, the integer parameter is not the detector number. This parameter correspond to the index of the data grid you are looking for. Most of the time, it'll be 0, because those analysis only return a single data grid, and in most langages (except MATLAB), the first index is zero.
You can check how many data grids are available with this line of code:
det.GetResults().NumberOfDataGridsRgb
If this returns anything other than 1 (based on your error, it probably returns 0), I'd suspect you might not have the right Detector in the settings. In which case, you can use the code I've proposed to change it to your Detector Color, perhaps something like:
# creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
det_settings = det.GetSettings()
# ensure detector viewer is true color to extract RGB data
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor
# specify detector color position
det_settings.Detector.SetDetectorNumber(30)
det.ApplyAndWaitForCompletion()
Let me know if this helps,
David
A potentially easier way is to simply use SAVEDETECTORDATA from the UI, ZPL or ZOS-API and then simply LOADDETECTORDATA and EXPORTGRAPHIC to get the graphic in the format you want. In fact, you could load the detector data into a Matlab array directly.
Ah, I see... problem is that I don't know how to use SAVEDETECTORDATA from the UI, ZPL or ZOS-AP.
I am totally a newbie to ZEMAX.
So, it return 0 .. but I guess
det_settings.Detector.SetDetectorNumber(30)
is not the row 30.
I have in total 12 detectors in the file.
I still get error 'Attempting to access the property or method of an invalid object.' at
det.GetResults().NumberOfDataGridsRgb
det_raw = det.GetResults().DataGridsRgb.Get(0);
used the code
% creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
det_settings = det.GetSettings()
det_settings.Detector.SetDetectorNumber(9) % out pf 12 detectors in the ZEMAX file
% ensure detector viewer is true color to extract RGB data
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor
% specify detector color position
det.ApplyAndWaitForCompletion()
I am not sure what the problem is?
the det_setting has the following properties
det_settings =
AS_DetectorViewer with properties:
Surface: [1×1 ZOSAPI.Analysis.AS_Surface]
Detector: [1×1 ZOSAPI.Analysis.AS_Detector]
ShowAs: TrueColor
Scale: Linear
DataType: PositionSpace
SymbolType: 0
Configuration: 1
ExtraProperty: 0
Smoothing: 0
RowCol: 0
Zplane: 0
MaxSpatialFrequency: 0
Contrast: 0
AngleList: [1×1 System.UInt16[]]
PlotScaleMinimum: 0
PlotScaleMaximum: 0
RayDatabaseFilename: [1×1 System.String]
Filter: [1×1 System.String]
OutFile: [1×1 System.String]
SuppressFrame: 1
NonsequentialSurfaces: [1×1 System.Collections.Generic.List>]
DetectorsOnSurface: [1×1 System.Collections.Generic.List>]
NumberOfNonSequentialSurfaces: 1
NumberOfDetectorsOnSurface: 12
NumberOfShowAsTypes: 6
Analysis: [1×1 ZemaxUI.ZOSAPI.Analysis.ZemaxAnalyses]
TheDataID: [1×1 ZOSAPI.Analysis.DataID]
IsValid: 1
IsActiveWindow: 1
Parent: [1×1 ZemaxUI.ZOSAPI.Analysis.RayTracing.A_DetectorViewer]
I now tried removing all the other detectors and just keeping the one I want to plot,
det_settings =
AS_DetectorViewer with properties:
Surface: [1×1 ZOSAPI.Analysis.AS_Surface]
Detector: [1×1 ZOSAPI.Analysis.AS_Detector]
ShowAs: TrueColor
Scale: Linear
DataType: PositionSpace
SymbolType: 0
Configuration: 1
ExtraProperty: 0
Smoothing: 0
RowCol: 0
Zplane: 0
MaxSpatialFrequency: 0
Contrast: 0
AngleList: [1×1 System.UInt16[]]
PlotScaleMinimum: 0
PlotScaleMaximum: 0
RayDatabaseFilename: [1×1 System.String]
Filter: [1×1 System.String]
OutFile: [1×1 System.String]
SuppressFrame: 1
NonsequentialSurfaces: [1×1 System.Collections.Generic.List>]
DetectorsOnSurface: [1×1 System.Collections.Generic.List>]
NumberOfNonSequentialSurfaces: 1
NumberOfDetectorsOnSurface: 1
NumberOfShowAsTypes: 6
Analysis: [1×1 ZemaxUI.ZOSAPI.Analysis.ZemaxAnalyses]
TheDataID: [1×1 ZOSAPI.Analysis.DataID]
IsValid: 1
IsActiveWindow: 1
Parent: [1×1 ZemaxUI.ZOSAPI.Analysis.RayTracing.A_DetectorViewer]
with code changes
%
% creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
det_settings = det.GetSettings()
det_settings.Detector.SetDetectorNumber(1) % detector 1 at row 22 , also tried (0)
% ensure detector viewer is true color to extract RGB data
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.GreyScale_Inverted
% specify detector color position
det.ApplyAndWaitForCompletion()
% Loads RGB data into System.Single buffer
det.GetResults().NumberOfDataGridsRgb
det_raw = det.GetResults().DataGridsRgb.Get(0);
det_raw.FillValues((x_pixel * y_pixel), rData, gData, bData);
still get error 'Attempting to access the property or method of an invalid object.' at 'det_raw = det.GetResults().DataGridsRgb.Get(0);'
Cannot figure out what the problem is.
Notice that i changed truecolor to Gray Scale Inverted since this is the one I use to plot the image. Not sure what to use as det.GetResults().DataGridsRgb.Get(0);' DataGrid when using show as 'gray inverted'.
I tried
det_raw = det.GetResults().DataGrids.Get(0);
and that worked but then i got error at line
det_raw.FillValues((x_pixel * y_pixel), rData, gData, bData);
Error says then, No appropriate method, property, or field 'FillValues' for class 'ZemaxUI.ZOSAPI.Analysis.AR_DataGrid'.
Ok, I got a little further. realised that rpg is 3 dimensional matrix. I think inverse_gray is only 1 dim.
% disp('get image');
tic
% Setup detector size
x_width = 6;
y_width = 6;
x_pixel = 800;
y_pixel = 800;
close all;
figure('OuterPosition',[0, 250, 1000, 500])
% for a = 1:TheMCE.NumberOfConfigurations
% TheMCE.SetCurrentConfiguration(a);
a = 1
%
% creates a new detector viewer window, changes to true color
det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
det_settings = det.GetSettings()
% det_settings.Detector.SetDetectorNumber(0) % detector 1 at row 22
% ensure detector viewer is true color to extract RGB data
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.GreyScale_Inverted
% specify detector color position
det.ApplyAndWaitForCompletion()
% Creates System.Single[] buffers to store pixel data
rData = NET.createArray('System.Single', (x_pixel * y_pixel));
% Loads RGB data into System.Single buffer
%det.GetResults().NumberOfDataGridsRgb
%det_raw = det.GetResults().DataGridsRgb.Get(0);
det_raw = det.GetResults().DataGrids.Get(0);
det_raw.FillValues((x_pixel * y_pixel), rData);
% Converts buffer to RGB array; rotates & resizes RGB array
dData = zeros(y_pixel, x_pixel, 1) - 1;
dData(:,:,1) = rot90(reshape(rData.double ./ 255, x_pixel, y_pixel));
% Plots detector color values
subplot(1, double(TheMCE.NumberOfConfigurations), double(a))
imagesc(dData,'X',[-x_width x_width],'Y',[-y_width y_width]);
axis equal tight;colormap('jet');
% str = sprintf('Config = %i');
% title(str);
still get error at line 'subplot(1, double(TheMCE.NumberOfConfigurations), double(a))', errror says
No appropriate method, property, or field 'FillValues' for class 'ZemaxUI.ZOSAPI.Analysis.AR_DataGrid'.
Any ideas what to do here?
Hi Susan,
I was a bit confused at your answers. I re-read the whole conversation, and here's what I think:
Detector.SetDetectorNumber(30) expects the Object Number as specified in the non-sequential editor. If your detector is in line 30, it should be 30. The system doesn't know how many detectors you have
This methods works for a Detector Color, it won't work for any other kind of detector
The reason I gave you this method is because you asked for a 'True Color' image, and the Detector Color is the only I know which can do that.
At this point, can I ask you to share your code, an example file, and an explanation as to what you are trying to achieve?
As I said, I don't own a MATLAB licence, and all I can do is try to guess what is going wrong. Regarding your last reply, I saw that you kept the part from the example about the Multi-Configuration Editor. If you have done so, you might want to check that it is setup accordingly in your lens design file, or if you don't have multi-configuration enabled, perhaps you might want to check that this part of the code is not interfering.
Take care,
David
Hi, a little update. I finally managed to solve the issue.
I am basically extracting the data, pixel by pixel, from the detector as inverted grayscale.
Thanks for the help.
My solution:
Set your detector to show as,.. in my case invested gray-scale or whatever u want. Just notice that the solution depends on the how the detector is to shown as. For example a color map gives the result in 3D matrix represented as red, green, blue and the first suggestion in this thread, in example 25 of the help section, should work well. In my case, the image is gray-scale which is a 1D matrix.
det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.GreyScale_Inverted;
Create a parameter to store your detector raw Data in and extract it. Before this I also pick which detector I want to extract data from.
det_settings.Detector.SetDetectorNumber(30); % pick detector, 30 here is the row no. in editor.
det_raw = det.GetResults();
dataGray = det_raw.DataGrids.Get(0);
and then extract data in a for-loop
imageM(i,j) = dataGray.ValueData.GetValueAt(i,j);
Thats it.
Hi Susan,
I'm glad to hear you are sorted. I hope this discussion helped you.
Don't hesitate to share your solution as well, if you think it can be helpful to someone else.
Take care,
David