Skip to content

Commit 6f9083d

Browse files
authored
Merge pull request #37 from LidkeLab/thorcam_dc
copy slm thorcam_csc and add thorcam_dcx
2 parents 88e9ede + 5ce4070 commit 6f9083d

30 files changed

Lines changed: 7583 additions & 98 deletions

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["klidke@unm.edu"]
44
version = "1.0.0-DEV"
55

66
[deps]
7+
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
78
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
89
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
910
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
@@ -17,6 +18,7 @@ Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
1718
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1819

1920
[compat]
21+
CEnum = "0.5.0"
2022
julia = "1.10"
2123

2224
[extras]

dev/test_thorcamdcx.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Revise
2+
using MicroscopeControl
3+
4+
# Test the saving function of Red Laser
5+
using MicroscopeControl.HardwareImplementations.ThorCamDCx
6+
7+
cam = ThorcamDCXCamera()
8+
initialize(cam)
9+
10+
gui(cam)
11+
12+
cam.exposure_time = 0.01 # s
13+
cam.roi.x_start = 100
14+
cam.roi.y_start = 100
15+
cam.roi.width = 200
16+
cam.roi.height = 300
17+
18+
data = capture(cam);
19+
20+
21+
cam.sequence_length = 10
22+
sequence(cam)
23+
data = getdata(cam);
24+
25+
abort(cam)
26+
27+
shutdown(cam)

src/MicroscopeControl.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ using .HardwareImplementations.TransmissionDaqControl
2929
using .HardwareImplementations.CrystaLaserControl
3030
using .HardwareImplementations.VortranLaserControl
3131
using .HardwareImplementations.OK_XEM
32+
using .HardwareImplementations.ThorCamDCx
3233

3334
# # Export all HardwareImplementations modules
3435
# export DCAM4, SimulatedCamera, SimulatedStage, PI, MadCityLabs, PI_N472, ThorCamCSC
@@ -39,7 +40,7 @@ using .HardwareImplementations.OK_XEM
3940
export save_h5, save_attributes_and_data
4041

4142
# Re-export camera implementations
42-
export SimCamera, DCAM4Camera, ThorCamCSC
43+
export SimCamera, DCAM4Camera, ThorCamCSCCamera, ThorCamDCXCamera
4344
export start_sequence, start_live
4445
export getlastframe, capture, live, sequence, abort, getdata
4546
export setexposuretime, settriggermode, setroi!, setexposuretime!

src/hardware_implementations/HardwareImplementations.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ include("mcl_stage/MadCityLabs.jl")
1313
include("pi_N472/PI_N472.jl")
1414

1515
include("thorcam_csc/ThorCamCSC.jl")
16+
include("thorcam_dcx/ThorCamDCx.jl")
1617
include("simulated_light/SimulatedLight.jl")
1718
include("nidaq/NIDAQcard.jl")
1819
include("tcube_laser/TCubeLaserControl.jl")
1920
include("daq_transmission_light/TransmissionDaqControl.jl")
2021
include("crysta_laser_561/CrystaLaserControl.jl")
2122
include("vortran_laser_488/VortranLaserControl.jl")
2223
include("ok_xem/OK_XEM.jl")
23-
24+
include("meadowlark_slm/Meadowlark.jl")
2425

2526
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module Meadowlark
2+
3+
using ...MicroscopeControl.HardwareInterfaces.SLMInterface
4+
using GLMakie, Images
5+
6+
import ...MicroscopeControl.HardwareInterfaces.SLMInterface: SLM
7+
import ...MicroscopeControl: export_state, initialize, shutdown
8+
9+
export MLSLM, Pupil, Sequence
10+
export displayimage, displayzernike, displayblaze
11+
export genblazed!, genzernike!
12+
13+
include("types.jl")
14+
include("meadowlark_sdk.jl")
15+
include("meadowlark_dev.jl")
16+
include("gen_patterns.jl")
17+
18+
end
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
2+
#TODO: Create blazed pattern for any angle and using MLSLM structure instead of an inputted phase array
3+
4+
5+
function genblazed!(slm::MLSLM, is_vert::Bool=true, period::Int=32; blaze_start::Int=1, blaze_end::Int=-1) #Units are pixels
6+
#Create array of size of SLM
7+
width = slm.width
8+
height = slm.height
9+
10+
#Create array of size of SLM
11+
phase_pattern = zeros(Float64, width, height)
12+
13+
if period == 1
14+
blaze_values = zeros(2)
15+
else
16+
blaze_values = LinRange(1, 0, period) #creates a range from 0 to 1 with the period specified
17+
end
18+
19+
if is_vert
20+
pattern_start::Int = (blaze_start)
21+
22+
if blaze_end < 0. || (blaze_end) > height
23+
blaze_end = height
24+
else
25+
pattern_end::Int = (blaze_end)
26+
end
27+
28+
for j in pattern_start:pattern_end
29+
phase_pattern[:, j] .= blaze_values[(j-1)%period+1]
30+
end
31+
else
32+
pattern_start = (blaze_start)
33+
34+
if blaze_end < 0. || (blaze_end) > width
35+
blaze_end = width
36+
else
37+
pattern_end = (blaze_end)
38+
end
39+
40+
for i in pattern_start:pattern_end
41+
phase_pattern[i, :] .= blaze_values[(i-1)%period+1]
42+
end
43+
end
44+
slm.phase = phase_pattern
45+
end
46+
47+
function genzernike!(slm::MLSLM, radial_order::Int, coefficients::Vector{Float64}, radius::Int, x_center::Int, y_center::Int)
48+
phase_array = zeros(Float64, slm.width, slm.height)
49+
50+
x_zernike = LinRange(-1,1, radius*2)
51+
y_zernike = LinRange(-1,1, radius*2)
52+
53+
zernike_array = [(x^2 + y^2 > 1 ? 0.0 : (zernike_sum(x, y, radial_order, coefficients))) for x in x_zernike, y in y_zernike]
54+
55+
reverse!(zernike_array, dims=2) #Reverses along the x axis, so the pattern is drawn correctly on the SLM
56+
57+
zernike_array = zernike_array .% 2pi #Ranges from -2pi to 2pi
58+
59+
for j in 1:size(zernike_array)[2] #Converts negative phase to positive phase
60+
for i in 1:size(zernike_array)[1]
61+
if zernike_array[i, j] < 0
62+
zernike_array[i, j] = 2pi + zernike_array[i, j]
63+
end
64+
end
65+
end
66+
67+
zernike_array = zernike_array ./ 2pi
68+
#TODO: Handle if radius is too large, only draw area that is on SLM
69+
if x_center - radius < 1 || x_center + radius - 1 > slm.width || y_center - radius < 1 || y_center + radius - 1 > slm.height
70+
71+
if x_center-radius < 1
72+
slm_x_start = 1
73+
zernike_x_start = 2 + radius-x_center
74+
else
75+
slm_x_start = x_center-radius
76+
zernike_x_start = 1
77+
end
78+
79+
if x_center + radius - 1 > slm.width
80+
slm_x_end = slm.width
81+
zernike_x_end = radius * 2 + (slm.width - (x_center + radius - 1))
82+
else
83+
slm_x_end = x_center + radius - 1
84+
zernike_x_end = radius*2
85+
end
86+
87+
if y_center-radius < 1
88+
slm_y_start = 1
89+
zernike_y_start = 2 + radius-y_center
90+
else
91+
slm_y_start = y_center-radius
92+
zernike_y_start = 1
93+
end
94+
95+
if y_center + radius - 1 > slm.height
96+
slm_y_end = slm.height
97+
zernike_y_end = radius * 2 + (slm.height - (y_center + radius - 1))
98+
else
99+
slm_y_end = y_center + radius - 1
100+
zernike_y_end = radius*2
101+
end
102+
103+
println( slm_x_start, " ", slm_x_end)
104+
println( slm_y_start, " ",slm_y_end)
105+
println( zernike_x_start, " ", zernike_x_end)
106+
println( zernike_y_start, " ",zernike_y_end)
107+
108+
phase_array[slm_x_start:slm_x_end, slm_y_start:slm_y_end] = zernike_array[zernike_x_start:zernike_x_end, zernike_y_start:zernike_y_end]
109+
else
110+
phase_array[x_center-radius:x_center+radius-1, y_center-radius:y_center+radius-1] = zernike_array[:,:]
111+
end
112+
slm.phase = phase_array
113+
end
114+
115+
116+
#=
117+
This function will use the reccurence reltaions defined in "Efficient and robust recurrence relations for the Zernike circle polynomials and their derivatives in Cartesian coordinates"
118+
It will return an array of values corresponding to the values of a specified number of zernike polynomials.
119+
These are in the order of OSA Zernike polynomials
120+
=#
121+
function zernike_recurs(x, y, order::Int)
122+
number_functions::Int = ((order + 1) * (order + 2)) / 2
123+
zern_polys = Array{Float64,1}(undef, number_functions)
124+
#Value of x and y lies inside unit disk
125+
zern_polys[1] = 1
126+
zern_polys[2] = y
127+
zern_polys[3] = x
128+
129+
if order > 1
130+
#values useful for indexing
131+
cur_indx = 4 #Index in array
132+
ps_indx = 2 #Index for for first polynomial of previous radial power (n-1)
133+
tps_indx = 1 #Index for for first polynomial of second revious radial power (n-2)
134+
for n = 2:order #Note: values of n = 0 and n=1 are given, the rest are calculated using the formulas in the paper
135+
for m = 0:n
136+
if m == 0
137+
zern_polys[cur_indx] = x * zern_polys[ps_indx+(0)] + y * zern_polys[ps_indx+(n-1)]
138+
elseif m == n
139+
zern_polys[cur_indx] = x * zern_polys[ps_indx+(n-1)] - y * zern_polys[ps_indx+(0)]
140+
elseif m == n / 2
141+
zern_polys[cur_indx] = 2 * x * zern_polys[ps_indx+(m)] + 2 * y * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)]
142+
elseif m == (n - 1) / 2
143+
zern_polys[cur_indx] = y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)]
144+
elseif m == ((n - 1) / 2) + 1
145+
zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)]
146+
else
147+
zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)]
148+
end
149+
cur_indx += 1
150+
end
151+
tps_indx += n - 1
152+
ps_indx += n
153+
end
154+
end
155+
return zern_polys
156+
end
157+
158+
#=
159+
Given an order of zernike polynomials, calculate an array containing their normalization coefficients
160+
=#
161+
function zernike_norm(order)
162+
#we will use the equation described in the paper to calculate the normalization coefficients
163+
number_functions::Int = ((order + 1) * (order + 2)) / 2
164+
norm_coef = Array{Float64,1}(undef, number_functions)
165+
index = 1
166+
for n = 0:order
167+
for m = 0:n
168+
if n == 2m
169+
norm_coef[index] = sqrt(n + 1)
170+
else
171+
norm_coef[index] = sqrt((2)(n + 1))
172+
end
173+
index += 1
174+
end
175+
end
176+
return norm_coef
177+
end
178+
179+
#=
180+
Sums the value of each zernike polynomial multiplied by their respecitve normilaztion coefficient and weight
181+
=#
182+
function zernike_sum(x, y, order, weights::Vector{Float64})
183+
return sum(zernike_recurs(x, y, order) .* zernike_norm(order) .* weights)
184+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#=
2+
These functions generate images using the write single image function in the Meadowlark SDK
3+
=#
4+
5+
function SLMInterface.displayimage(slm::SLM)
6+
writesingleimage(slm)
7+
end
8+
9+
function SLMInterface.displayimage(slm::SLM, phase::Array{Float64,2})
10+
SLM.phase = phase
11+
return displayimage(slm)
12+
end
13+
14+
function SLMInteface.displayzernike(slm::SLM, zernike::Vector{Float64})
15+
phase = zernike_to_phase(zernike, slm)
16+
return displayimage(slm, phase)
17+
end
18+
19+
function SLMInterface.displayblaze(slm::SLM, is_vert::Bool = false , period::Int = 8; blaze_start::Int=1, blaze_end::Int=1024)
20+
genblazed!(slm, is_vert, period, blaze_start=blaze_start, blaze_end=blaze_end)
21+
return displayimage(slm)
22+
end
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function loadlut() #TODO: Input LUT path
2+
#This works, now must load the LUT
3+
lut_path = "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\LUT Files\\1024x1024_linearVoltage.LUT"
4+
loaded_lut = @ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Load_LUT_file(1::Cuint, lut_path::Ptr{UInt8})::Cint
5+
6+
end
7+
8+
function writesingleimage(slm::MLSLM)
9+
single_image = slm.phase .* 255 #Converting 0 to 1 to scaled values between 0 and 255
10+
single_image = round.(Int, single_image) #Converting to integers
11+
single_image = convert(Array{UInt8}, single_image)
12+
13+
board_number = 1
14+
wait_for_trigger::Cuint = 0
15+
flip_immediate::Cuint = 0
16+
output_pulse_image_flip::Cuint = 0
17+
output_pulse_image_refresh::Cuint = 0
18+
trigger_timout_ms::Cuint = 5000
19+
image_size::Cint = slm.height * slm.width
20+
21+
#=
22+
single_image = reshape(single_image, 1, image_size)
23+
new_image = zeros(UInt8, image_size) #Issues with Column vs Row major order
24+
new_image[:] .= single_image[1, :]
25+
=#
26+
new_image = reshape(single_image, image_size)
27+
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Write_image(board_number::Cuint,
28+
new_image::Ptr{Cint}, image_size::Cint, wait_for_trigger::Cuint, flip_immediate::Cuint, output_pulse_image_flip::Cuint,
29+
output_pulse_image_refresh::Cuint, trigger_timout_ms::Cuint)::Cint
30+
31+
end
32+
33+
function writesequence(slm::MLSLM)
34+
@error "Not implemented"
35+
end
36+
37+
function selectsequenceimage(slm::MLSLM)
38+
@error "Not implemented"
39+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function initializesdk()
2+
# Initialize the SLM
3+
#First Create variables needed to create SDK
4+
bit_depth::Cuint = 12
5+
n_boards_found = Ref{Cuint}(0)
6+
constructed_ok = Ref{Cuint}(1)
7+
is_nematic_type::Cuint = 1
8+
ram_write_enable::Cuint = 1
9+
use_gpu::Cuint = 1
10+
max_transient_frames::Cuint = 10
11+
12+
#Creating the SDK
13+
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Create_SDK(bit_depth::Cuint,
14+
n_boards_found::Ref{Cuint}, constructed_ok::Ref{Cuint}, is_nematic_type::Cuint, ram_write_enable::Cuint, use_gpu::Cuint,
15+
max_transient_frames::Cuint, 0::Cuint)::Cvoid
16+
17+
println(n_boards_found[])
18+
println(constructed_ok[])
19+
end
20+
21+
function closesdk()
22+
# Close the SLM
23+
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Delete_SDK()::Cvoid
24+
end

0 commit comments

Comments
 (0)