A depth inspection tool for inspecting values of depth maps.
An 8-bit depth image is typically stored using an unsigned 8-bit integer data type, also known as uint8. Here’s a breakdown of its properties:
- Range:
0to255 - Data Type:
uint8(8-bit unsigned integer) - Precision: No decimal places, as it only stores whole numbers within this range
The limited range of 0–255 is quite restrictive for depth data because:
- Range is Extremely Limited:
uint8only covers 256 possible values. This is usually insufficient for representing meaningful depth data across even small ranges, as it severely limits the measurable distances. - Precision Loss: When used for depth maps,
uint8images lose a lot of precision compared touint16orfloat32. For example, if you store depths in millimeters, you could only measure up to 255 mm (25.5 cm) with a 1 mm resolution.
Because of these limitations, uint8 depth images are rarely used in applications requiring accurate depth representation. When they are used, they’re typically scaled versions of the depth data for visualization purposes, such as for applying colormaps to display the depth image as a heatmap.
To represent larger depth ranges with uint8, the depth values are often normalized to fit within 0–255. This sacrifices depth accuracy but allows visual representation in applications where precise depth isn’t necessary.
- uint8: Not suitable for accurate depth storage, due to its limited range and precision.
- Common Use: Mostly used for visualizations after normalizing the depth data to fit within
0–255.
For depth data storage, uint16 or float32 are generally preferred over uint8 due to their significantly larger ranges and precision.
For uint16 (16-bit unsigned integer) depth images, the range and precision are limited compared to float32. Here’s what you need to know:
- Minimum value:
0 - Maximum value:
65535
This range allows uint16 images to store depth values from 0 up to 65535.
uint16values are integer-based, so there are no decimal places. Each value is a whole number within the range0–65535.- The precision depends on the scale or units used in the depth map:
- If values represent millimeters (mm), then
65535mm is the maximum depth that can be represented, which is approximately 65.5 meters. - If values represent centimeters (cm), the maximum depth is around 655.35 meters.
- If values represent meters (m), the maximum depth is 65535 meters.
- If values represent millimeters (mm), then
The choice of scale (mm, cm, or m) determines the depth precision:
- Millimeters (mm): Commonly used with
uint16depth maps. It provides depth measurements up to 65.5 meters with a 1 mm resolution. - Centimeters (cm): Can store depths up to 655.35 meters with a 1 cm resolution.
- Meters (m): Allows for very large ranges up to 65535 meters, but only with a 1 meter resolution, which is too coarse for most applications.
- Range:
float32can represent a vastly larger range thanuint16. - Precision:
float32can store fractional values, whileuint16can only store integer values, which meansfloat32is more suitable for applications that need very fine precision.
uint16 depth maps are commonly used in depth sensors because they provide a good balance of range and precision, especially when depths are stored in millimeters:
- Range up to 65.5 meters with 1 mm precision if using millimeters as the unit.
- Limited compared to
float32, which can represent much larger depths and fractional precision.
So, uint16 depth maps are ideal when working with depth values within 65.5 meters and when precision down to 1 mm is sufficient.
The float32 format, or 32-bit floating-point format, can represent a very large range of values, making it suitable for storing depth data with high precision. Here’s a breakdown of the range and precision it can handle:
- Smallest positive value: Approximately (1.4 \times 10^{-45}) (close to zero).
- Largest positive value: Approximately (3.4 \times 10^{38}).
This means float32 can hold depth values from extremely small (almost zero) to very large values, which is far more than what typical depth sensors require. For most practical purposes, you can comfortably store depths in the range of centimeters, meters, kilometers, or even astronomical distances, if needed.
float32has 23 bits of precision for the mantissa (significant digits), which means it can represent values with about 7 decimal digits of precision.- This is more than sufficient for depth measurements in most applications, especially when measuring distances in meters with precision down to millimeters or finer.
In typical applications:
- Indoor Depth Sensing: Ranges from about
0.3 meters(300 mm) to around10 meters, depending on the sensor.float32can handle these depths with high precision. - Outdoor or Long-range Depth Sensing: Can go up to hundreds or thousands of meters.
float32can still handle these ranges accurately.
For instance, if you store depths in meters, float32 can represent values down to sub-millimeter precision up to distances of several kilometers with acceptable accuracy.
- Precision: It allows for sub-millimeter precision, which is useful when storing depth values in meters.
- Range: It can represent a wide range of depths, making it versatile for various applications without the need for scaling.
float32 is capable of holding any practical depth value you might need, with sufficient precision for most applications.
The differences between uint16 and float32 depth maps, along with an example to illustrate how they differ in representing depth values.
-
uint16Depth Map:uint16is an unsigned 16-bit integer format, which means it can store integer values between0and65535.- Typically used when depth is stored in millimeters for higher resolution within this range. For example, a depth value of
1000represents1000 mm, or1 meter. - Since it’s an integer type, it cannot store decimal values, so there’s no fractional depth measurement.
-
float32Depth Map:float32is a 32-bit floating-point format, which can store a much broader range of values, including fractional (decimal) values.- Typically used when depth is stored in meters for precision. For example, a depth value of
1.234represents1.234 meters, or1234 mm. - The precision allows for more accurate depth measurements, especially at smaller scales.
Consider a depth map where we measure distances in both uint16 and float32 formats:
Let’s say we have three pixel values representing depth:
| Pixel Position | Depth (Meters) |
|---|---|
| (100, 100) | 1.234 |
| (150, 150) | 5.678 |
| (200, 200) | 10.123 |
With float32, these values can be stored directly:
| Pixel Position | Depth Value (float32) |
|---|---|
| (100, 100) | 1.234 |
| (150, 150) | 5.678 |
| (200, 200) | 10.123 |
These values can represent distances in meters precisely, retaining decimal values.
If we convert these values to millimeters and store them as uint16, we need to multiply by 1000 (to convert meters to millimeters) and round to the nearest integer, as shown below:
| Pixel Position | Depth Value (float32 in Meters) |
Converted to Millimeters | Depth Value (uint16) |
|---|---|---|---|
| (100, 100) | 1.234 | 1234 | 1234 |
| (150, 150) | 5.678 | 5678 | 5678 |
| (200, 200) | 10.123 | 10123 | 10123 |
When stored as uint16, the depth map has values like 1234, 5678, and 10123, which represent depths in millimeters. Note that we lose any values beyond millimeter precision.
- Precision:
float32retains decimal precision (e.g.,1.234 meters), whereasuint16rounds to the nearest integer millimeter (e.g.,1234 mm). - Range:
uint16is limited to a maximum value of65535mm (or 65.535 meters). If your depth values exceed this, they would be clipped.float32can represent values far beyond this range, allowing for larger depths. - File Size:
uint16depth maps are more compact in terms of file size compared tofloat32, as they use half the storage space per pixel (16 bits vs. 32 bits).
uint16Depth Maps: Commonly used for depth sensors that measure within a limited range, like indoor scenes where distances are within0–65 metersand where millimeter precision is sufficient.float32Depth Maps: Useful in applications needing high precision, such as 3D reconstruction, where small depth differences matter, or in outdoor scenes where depth values can exceed65 meters.
Here’s a simple example that demonstrates both types:
import numpy as np
# Example depth map in meters (float32)
depth_map_float32 = np.array([[1.234, 5.678, 10.123]], dtype=np.float32)
print("Depth map in float32 (meters):")
print(depth_map_float32)
# Convert to uint16 (millimeters)
depth_map_uint16 = (depth_map_float32 * 1000).astype(np.uint16)
print("\nDepth map in uint16 (millimeters):")
print(depth_map_uint16)
# Convert back to float32 to interpret as meters (for comparison)
depth_map_reconstructed = depth_map_uint16.astype(np.float32) / 1000
print("\nReconstructed float32 depth map (meters):")
print(depth_map_reconstructed)This example shows how the values are represented differently, and converting back can give approximate results but without the original precision if it was clipped.
A representative method to estimate metric-scale depth maps is to convert a stereo image’s disparity map into depth maps using the camera focal length f and baseline B (i.e. seperation between cameras). The disparity map encodes depth information of a scene by measuring the pixel displacement between corresponding points in stereo images. The conversion from disparity d to depth Z is given by:
The equation shown represents the formula for calculating the depth ( Z ) in stereo vision. It can be rewritten as:
If the principle points are not same for both the cameras and the camera intrinsics and camera baseline are known, disparity predictions can be converted to depth values using:
Note that the units of the focal length are pixels not millimeters. (cx1-cx0) is the x-difference of principal points.
PNG images can store uint16 values but cannot natively store float32 values. Here’s a breakdown:
- Supported: PNG files can store
uint16values (16-bit grayscale), and many image processing libraries (like OpenCV, Pillow, and imageio) can read and write these images. - Use Case:
uint16PNG images are often used for depth maps, where values are stored in millimeters or other integer-based depth values. - File Size:
uint16values are compact, requiring 2 bytes per pixel, making them efficient for storage.
- Not Supported Natively: PNG does not natively support
float32values, as it’s designed to store integer values (typicallyuint8oruint16for grayscale images). - Workarounds:
- Normalization: Convert
float32values to a range that fits withinuint16oruint8by scaling (e.g., map a range of depths to0–65535foruint16). This approach reduces precision and range but allows storage in a PNG format. - Alternative Formats: For storing
float32depth maps, alternative formats like.exr(OpenEXR) or.tiff(if it supportsfloat32) are often used, as these formats natively support floating-point data.
- Normalization: Convert
For a float32 depth map to be stored as a PNG, normalize it to fit within a uint16 range:
import numpy as np
import cv2
# Example float32 depth map with values in meters
depth_map_float32 = np.array([[1.234, 5.678, 10.123]], dtype=np.float32)
# Normalize to fit uint16 (assuming max depth value is 20 meters for this example)
normalized_depth_map = (depth_map_float32 / 20 * 65535).astype(np.uint16)
# Save as uint16 PNG
cv2.imwrite('depth_uint16.png', normalized_depth_map)Then, when reading back, convert it to float32 by reversing the normalization:
# Read back the uint16 PNG
loaded_depth_map = cv2.imread('depth_uint16.png', cv2.IMREAD_UNCHANGED)
# Convert back to float32 (assuming same max depth as above)
depth_map_float32_reconstructed = (loaded_depth_map.astype(np.float32) / 65535) * 20- PNG supports
uint16but notfloat32natively. - Alternative formats like OpenEXR or TIFF are more suitable for
float32depth data. - Normalization is required if you need to store
float32values in auint16PNG.






