Class: PhotoUtils::Scene

Inherits:
Object
  • Object
show all
Defined in:
lib/photo_utils/scene.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScene

Returns a new instance of Scene.



12
13
14
15
16
17
18
# File 'lib/photo_utils/scene.rb', line 12

def initialize
  {
    background_distance: Math::Infinity,
    sensitivity: 100,
    brightness: 100,
  }.each { |k, v| send("#{k}=", v) }
end

Instance Attribute Details

#background_distanceObject

Returns the value of attribute background_distance.



7
8
9
# File 'lib/photo_utils/scene.rb', line 7

def background_distance
  @background_distance
end

#brightnessObject

Returns the value of attribute brightness.



10
11
12
# File 'lib/photo_utils/scene.rb', line 10

def brightness
  @brightness
end

#cameraObject

Returns the value of attribute camera.



8
9
10
# File 'lib/photo_utils/scene.rb', line 8

def camera
  @camera
end

#descriptionObject

Returns the value of attribute description.



5
6
7
# File 'lib/photo_utils/scene.rb', line 5

def description
  @description
end

#sensitivityObject

Returns the value of attribute sensitivity.



9
10
11
# File 'lib/photo_utils/scene.rb', line 9

def sensitivity
  @sensitivity
end

#subject_distanceObject

Returns the value of attribute subject_distance.



6
7
8
# File 'lib/photo_utils/scene.rb', line 6

def subject_distance
  @subject_distance
end

Instance Method Details

#absolute_apertureObject



120
121
122
# File 'lib/photo_utils/scene.rb', line 120

def absolute_aperture
  @camera.lens.aperture.absolute(@camera.lens.focal_length)
end

#aperture_for_depth_of_field(near_limit, far_limit) ⇒ Object



41
42
43
44
# File 'lib/photo_utils/scene.rb', line 41

def aperture_for_depth_of_field(near_limit, far_limit)
  a = ((@camera.lens.focal_length ** 2) / circle_of_confusion) * ((far_limit - near_limit) / (2 * near_limit * far_limit))
  Aperture.new(a)
end

#blur_at_distance(d) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/photo_utils/scene.rb', line 107

def blur_at_distance(d)
  # http://en.wikipedia.org/wiki/Depth_of_field#Foreground_and_background_blur
  xd = (d - subject_distance).abs
  b = (@camera.lens.focal_length * magnification) / @camera.lens.aperture
  if d < subject_distance
    b *= xd / (subject_distance - xd)
  else
    b *= xd / (subject_distance + xd)
  end
  # diameter of blur disk, in mm
  Length.new(b.mm)
end

#circle_of_confusionObject



36
37
38
39
# File 'lib/photo_utils/scene.rb', line 36

def circle_of_confusion
  # http://en.wikipedia.org/wiki/Circle_of_confusion
  @camera.format.frame.diagonal / 1750
end

#depth_of_fieldObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/photo_utils/scene.rb', line 54

def depth_of_field
  h = hyperfocal_distance
  s = subject_distance
  dof = HashStruct.new
  dof.near = (h * s) / (h + s)
  if s < h
    dof.far = (h * s) / (h - s)
  else
    dof.far = Math::Infinity
  end
  dof.near = Length.new(dof.near)
  dof.far  = Length.new(dof.far)
  dof
end

#exposureObject



124
125
126
127
128
129
130
# File 'lib/photo_utils/scene.rb', line 124

def exposure
  Exposure.new(
    light: @brightness,
    sensitivity: @sensitivity,
    aperture: @camera.lens.aperture,
    time: @camera.shutter)
end

#far_distance_from_subjectObject



74
75
76
77
# File 'lib/photo_utils/scene.rb', line 74

def far_distance_from_subject
  d = (depth_of_field.far == Math::Infinity) ? Math::Infinity : (depth_of_field.far - subject_distance)
  Length.new(d)
end

#field_of_view(distance) ⇒ Object



84
85
86
87
# File 'lib/photo_utils/scene.rb', line 84

def field_of_view(distance)
  raise "Need focal length and format size to determine field of view" unless @camera.lens.focal_length && @camera.format
  @camera.format.field_of_view(@camera.lens.focal_length, distance)
end

#hyperfocal_distanceObject



46
47
48
49
50
51
52
# File 'lib/photo_utils/scene.rb', line 46

def hyperfocal_distance
  # http://en.wikipedia.org/wiki/Hyperfocal_distance
  raise "Need focal length, aperture, and circle of confusion to determine hyperfocal distance" \
    unless @camera.lens.focal_length && @camera.lens.aperture && circle_of_confusion
  h = ((@camera.lens.focal_length ** 2) / (@camera.lens.aperture * circle_of_confusion)) + @camera.lens.focal_length
  Length.new(h)
end

#magnificationObject



89
90
91
92
# File 'lib/photo_utils/scene.rb', line 89

def magnification
  # http://en.wikipedia.org/wiki/Depth_of_field#Hyperfocal_magnification
  @camera.lens.focal_length / (subject_distance - @camera.lens.focal_length)
end

#near_distance_from_subjectObject



69
70
71
72
# File 'lib/photo_utils/scene.rb', line 69

def near_distance_from_subject
  d = subject_distance - depth_of_field.near
  Length.new(d)
end


173
174
175
176
# File 'lib/photo_utils/scene.rb', line 173

def print(io=STDOUT)
  print_depth_of_field(io)
  print_exposure(io)
end


138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/photo_utils/scene.rb', line 138

def print_camera(io=STDOUT)
  io.puts "CAMERA:"
  io.puts "             name: #{@camera.name}"
  io.puts "           format: #{@camera.format} (35mm crop factor: #{@camera.format.crop_factor.format(10)})"
  io.puts "    shutter range: #{@camera.max_shutter} ~ #{@camera.min_shutter}"
  io.puts "   aperture range: #{@camera.lens.max_aperture} ~ #{@camera.lens.min_aperture}"
  io.puts "             lens: #{@camera.lens.name} - #{@camera.lens.focal_length} (#{
    %w{35 6x4.5 6x6 6x7 5x7}.map { |f| "#{f}: #{@camera.format.focal_length_equivalent(@camera.lens.focal_length, Format[f])}" }.join(', ')
  })"
  io.puts "    angle of view: #{@camera.angle_of_view}"
  io.puts "          shutter: #{@camera.shutter}"
  io.puts "         aperture: #{@camera.lens.aperture}"
  io.puts
end


157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/photo_utils/scene.rb', line 157

def print_depth_of_field(io=STDOUT)
  io.puts "FIELD:"
  io.puts "     subject dist: #{subject_distance.to_s(:imperial)}"
  io.puts "      subject FOV: #{field_of_view(subject_distance).to_s(:imperial)}"
  io.puts "      subject mag: #{'%.2f' % magnification}x"
  io.puts "      subject DOF: #{total_depth_of_field.to_s(:imperial)} (-#{near_distance_from_subject.to_s(:imperial)}/+#{far_distance_from_subject.to_s(:imperial)})"
  io.puts "  background dist: #{background_distance.to_s(:imperial)}"
  if background_distance != Math::Infinity
    io.puts "   background FOV: #{field_of_view(background_distance).to_s(:imperial)}"
    io.puts "  background blur: #{blur_at_distance(background_distance).to_s(:metric)}"
  end
  io.puts "  hyperfocal dist: #{hyperfocal_distance.to_s(:imperial)}"
  io.puts " working aperture: #{working_aperture}"
  io.puts
end


153
154
155
# File 'lib/photo_utils/scene.rb', line 153

def print_exposure(io=STDOUT)
  exposure.print(io)
end

#set_exposureObject



132
133
134
135
136
# File 'lib/photo_utils/scene.rb', line 132

def set_exposure
  exp = exposure
  @camera.lens.aperture = exp.aperture
  @camera.shutter = exp.time
end

#subject_distance_for_field_of_view(fov) ⇒ Object



94
95
96
97
98
# File 'lib/photo_utils/scene.rb', line 94

def subject_distance_for_field_of_view(fov)
  d_w = fov.width  / @camera.format.frame.width  * @camera.lens.focal_length
  d_h = fov.height / @camera.format.frame.height * @camera.lens.focal_length
  [d_w, d_h].max
end

#total_depth_of_fieldObject



79
80
81
82
# File 'lib/photo_utils/scene.rb', line 79

def total_depth_of_field
  d = (depth_of_field.far == Math::Infinity) ? Math::Infinity : (depth_of_field.far - depth_of_field.near)
  Length.new(d)
end

#working_apertureObject

AKA bellows factor



102
103
104
105
# File 'lib/photo_utils/scene.rb', line 102

def working_aperture
  # http://en.wikipedia.org/wiki/F-number#Working_f-number
  Aperture.new((1 - magnification) * @camera.lens.aperture)
end