Other versions of this page
Metering
We refer to metering as the act of gauging the scene luminosity, depth and color and adjusting the camera sensor settings for optimal results. It's what happens, for instance, when you tap on screen to focus on a certain subject.
The CameraMeter
APIs will help you implement things like "tap to focus" functionality and exposure, focus and/or white balance locking.
You can find them in the CameraMeter
class:
swiftlet device: CameraDevice = ...
guard let meter: CameraMeter = device.meter else { return } // Device is not open?
kotlinval device: CameraDevice = ...
val meter: CameraMeter = device.meter ?: return // Device is not open?
All APIs provide fine-grained metering control. For example, you may lock focus while running an exposure and white balance routine.
Default behavior
Continuous Metering
By default, camera sensors will continuously meter the scene to improve output. This may be disabled in certain scenarios:
- for exposure, it's always enabled
- for focus, it's always enabled as long as the device supports it (front cameras sometimes won't)
- for white balance, it's enabled if the device supports it and if
CameraConfiguration.whiteBalance
is set toWhiteBalance.Auto
WhiteBalance.auto
, which is the default value
Picture Metering
By default, when taking pictures, a special metering routine will take place to improve the output
and ensure maximum quality in terms of exposure, focus and white balance. This can be disabled by passing false
to
the meterIfNeeded
parameter, as explained in the pictures documentation.
Scanning
Whenever your application determines that a new metering routine should be started, you can use CameraMeter.scan()
.
This API should be used, for example, to implement "tap to focus" in your app.
kotlin// CameraMeter API
suspend fun scan(
center: Point?,
surface: String?,
lockDuration: Long = 6000,
exposure: Boolean = true,
focus: Boolean = true,
whiteBalance: Boolean = true,
throwIfUnsupported: Boolean = false,
) { ... }
swift// CameraMeter API
func scan(
center: Point?,
surface: String?,
lockDuration: TimeInterval = 6.0,
exposure: Bool = true,
focus: Bool = true,
whiteBalance: Bool = true,
throwIfUnsupported: Bool = false
) async throws { ... }
Let's go through the parameters:
center
: a x/y pair of normalized coordinates that you get from your gesture detection logic. Coordinates should be in the0...1
range, and you should make make sure that the exact name of the preview surface is passed tosurface
as well.surface
: the name of the preview surface thatcenter
refers to, very important for orientation calculations that are needed under the hood. If absent, engine will assume the first valid preview is the desired one.lockDuration
: in principle, metering only makes sense if the updated values are kept for a while. Pass an infinite or non-positive value to lock forever.exposure
: whether exposure should be adjusted.focus
: whether focus should be adjusted.whiteBalance
: whether white balance should be adjusted.throwIfUnsupported
: whether scan should throw an error if any of the routines (AE, AF, AWB) are unsupported by the device. You typically want to keep this false which in practical terms means "do your best".
The function returns after scan is complete, without waiting for the lock duration.
iOS does not currently support metering white balance to a certain point in the scene, so if a
center
is provided, it will only apply to exposure and focus routines.
Metering Modes
During device configuration, you can decide how scan()
calls will handle center
locations:
Mode | Meaning |
---|---|
MeteringMode.Uniform | Gauge the scene uniformly. Any Point passed to the scan function will be ignored. |
MeteringMode.Spot | Gauge the scene in the proximity of the given Point . Fallback to the scene's center if no point was provided. |
MeteringMode.Weighted | More advanced. Like Spot , but considers a larger area while giving more weight to the spot area. |
Mode | Meaning |
---|---|
MeteringMode.uniform | Gauge the scene uniformly. Any Point passed to the scan function will be ignored. |
MeteringMode.spot | Gauge the scene in the proximity of the given Point . Fallback to the scene's center if no point was provided. |
You can inspect which modes are supported by checking the device capabilities.
Locking and unlocking
In addition to the scan()
APIs, you can also lock - as with scan, with fine-grained routine control - the settings
to their current values, and unlock later. To lock:
kotlin// CameraMeter API
suspend fun lock(
duration: Long = -1L,
exposure: Boolean = true,
focus: Boolean = true,
whiteBalance: Boolean = true,
throwIfUnsupported: Boolean = false,
) { ... }
swift// CameraMeter API
func lock(
duration: TimeInterval = -1.0,
exposure: Bool = true,
focus: Bool = true,
whiteBalance: Bool = true,
throwIfUnsupported: Bool = false
) async throws { ... }
The duration
property determines how long the settings should be locked for. Non-positive or infinite values mean locking forever. To unlock:
kotlin// CameraMeter API
suspend fun unlock(
exposure: Boolean = true,
focus: Boolean = true,
whiteBalance: Boolean = true,
) { ... }
swift// CameraMeter API
func unlock(
exposure: Bool = true,
focus: Bool = true,
whiteBalance: Bool = true
) async throws { ... }
Scene state
Using any of the metering APIs will change the sensor's understanding of the scene, represented by CameraScene
.
Use CameraDevice.scene
to retrieve it:
kotlinval current: CameraScene? = device.scene.value
val flow: StateFlow<CameraScene?> = device.scene
swiftlet current: CameraScene? = device.scene
let publisher: AnyPublisher<CameraScene?, Never> = device.scenePublisher
In the scene, you'll find a status enum for each of the three parameters (exposure, focus and white balance). This can be used to implement things like touch-to-focus markers on screen, or deciding when to take a picture for best results.
Status | Description |
---|---|
CameraScene.Status.Diverged CameraScene.Status.diverged | The metering routine could not find a parameter compatible with the current scene. Picture quality can't be guaranteed. |
CameraScene.Status.Metering CameraScene.Status.metering | The metering routine is running, trying to adjust the parameters. |
CameraScene.Status.Converged CameraScene.Status.converged | The metering routine has found a good value, compatible with the current scene. |
CameraScene.Status.Locked CameraScene.Status.locked | Parameter is locked, metering routine is disabled. |