AliceVision
Photogrammetric Computer Vision Framework
ExposureSetting.hpp
1 // This file is part of the AliceVision project.
2 // Copyright (c) 2023 AliceVision contributors.
3 // This Source Code Form is subject to the terms of the Mozilla Public License,
4 // v. 2.0. If a copy of the MPL was not distributed with this file,
5 // You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #pragma once
8 
9 #include <aliceVision/types.hpp>
10 #include <aliceVision/numeric/numeric.hpp>
11 
12 namespace aliceVision {
13 namespace sfmData {
14 
16 {
17  public:
18  ExposureSetting() {}
19 
20  ExposureSetting(double shutter, double fnumber, double iso)
21  : _shutter(shutter),
22  _fnumber(fnumber),
23  _iso(iso)
24  {}
25 
26  double _shutter{-1.0};
27  double _fnumber{-1.0};
28  double _iso{-1.0};
29 
30  bool hasShutter() const { return _shutter > 0.0 && std::isnormal(_shutter); }
31  bool hasFNumber() const { return _fnumber > 0.0 && std::isnormal(_fnumber); }
32  bool hasISO() const { return _iso > 0.0 && std::isnormal(_iso); }
33 
34  bool isFullyDefined() const { return hasShutter() && hasFNumber() && hasISO(); }
35 
36  bool isPartiallyDefined() const { return hasShutter() || hasFNumber(); }
37 
38  double getExposure(const double referenceISO = 100.0, const double referenceFNumber = 1.0) const
39  {
40  const bool validShutter = hasShutter();
41  const bool validFNumber = hasFNumber();
42 
43  if (!validShutter && !validFNumber)
44  return -1.0;
45 
46  const bool validRefFNumber = referenceFNumber > 0.0 && std::isnormal(referenceFNumber);
47 
48  double shutter = _shutter;
49  if (!validShutter)
50  {
51  shutter = 1.0 / 200.0;
52  }
53  double fnumber = _fnumber;
54  // Usually we should get a valid shutter speed, but we could have invalid fnumber.
55  // For instance, if there is a connection problem between the lens and the camera, all lens related option like fnumber could be invalid.
56  // In this particular case, the exposure should rely only on the shutter speed.
57  if (!validFNumber)
58  {
59  if (validRefFNumber)
60  fnumber = referenceFNumber;
61  else
62  fnumber = 2.0;
63  }
64  double lReferenceFNumber = referenceFNumber;
65  if (!validRefFNumber)
66  {
67  lReferenceFNumber = fnumber;
68  }
69 
70  const double iso = _iso;
71  /*
72  iso = qLt / aperture^2
73  isoratio = iso2 / iso1 = (qLt / aperture2^2) / (qLt / aperture1^2)
74  isoratio = aperture1^2 / aperture2^2
75  aperture2^2 = aperture1^2 / isoratio
76  aperture2^2 = (aperture1^2 / (iso2 / iso1))
77  aperture2^2 = (iso1 / iso2)
78  aperture2 = sqrt(iso1 / iso2)
79  */
80  double iso2Aperture = 1.0;
81  if (iso > 1e-6 && referenceISO > 1e-6)
82  {
83  // Need to have both iso and reference iso to use it
84  iso2Aperture = std::sqrt(iso / referenceISO);
85  }
86 
87  /*
88  aperture = f / diameter
89  aperture2 / aperture1 = diameter1 / diameter2
90  (aperture2 / aperture1)^2 = (area1 / pi) / (area2 / pi)
91  area2 = (aperture1 / aperture2)^2
92  */
93  double newFnumber = fnumber * iso2Aperture;
94  double expIncrease = (lReferenceFNumber / newFnumber) * (lReferenceFNumber / newFnumber);
95 
96  // If the aperture was more important for this image, this means that it received less light than with a default aperture
97  // This means also that if we want to simulate that all the image have the same aperture, we have to increase virtually th
98  // light received as if the aperture was smaller. So we increase the exposure time
99 
100  // If the iso is larger than the default value, this means that it received more light than with a default iso
101  // This means also that if we want to simulate that all the image have the same iso, we have to decrease virtually th
102  // light received as if the iso was smaller. So we decrease the exposure time or equivalent, increase the aperture value
103 
104  // Checks
105  // iso 20, f/2 = 2500
106  // iso 40, f/2.8 = 2500
107 
108  return shutter * expIncrease;
109  }
110  bool operator<(const ExposureSetting& other) const { return getExposure() < other.getExposure(); }
111  bool operator==(const ExposureSetting& other) const { return getExposure() == other.getExposure(); }
112 };
113 
114 inline std::ostream& operator<<(std::ostream& os, const ExposureSetting& s)
115 {
116  os << "shutter: " << s._shutter << ", fnumber: " << s._fnumber << ", iso: " << s._iso;
117  return os;
118 }
119 
120 inline bool hasComparableExposures(const std::vector<ExposureSetting>& exposuresSetting)
121 {
122  if (exposuresSetting.size() < 2)
123  return false;
124 
125  const bool hasShutter = exposuresSetting.front().hasShutter();
126  const bool hasFNumber = exposuresSetting.front().hasFNumber();
127  const bool hasISO = exposuresSetting.front().hasISO();
128  for (std::size_t i = 1; i < exposuresSetting.size(); ++i)
129  {
130  const ExposureSetting& s = exposuresSetting[i];
131  if (hasShutter != s.hasShutter())
132  return false;
133  if (hasFNumber != s.hasFNumber())
134  return false;
135  if (hasISO != s.hasISO())
136  return false;
137  }
138  return true;
139 }
140 
141 inline std::vector<double> getExposures(const std::vector<ExposureSetting>& exposuresSetting)
142 {
143  std::vector<double> output;
144  output.reserve(exposuresSetting.size());
145  for (const ExposureSetting& exp : exposuresSetting)
146  {
147  output.push_back(exp.getExposure());
148  }
149  return output;
150 }
151 
152 } // namespace sfmData
153 } // namespace aliceVision
aliceVision
Definition: checkerDetector.cpp:32
aliceVision::sfmData::ExposureSetting
Definition: ExposureSetting.hpp:15