PFM格式图像和读取middlebury 数据集
PFM格式图像
http://www.pauldebevec.com/Research/HDR/PFM/
https://linux.die.net/man/5/pfm
PFM (Portable Float Map),是一种浮点像素的图像格式,包含文件信息和文件二进制数据两部分内容。
图像格式
PFM中的文件信息称为header,二进制图像数据称为raster。
header 文件信息:
共有三行信息,并且以Unix风格的换行符“\n”的十六进制“0x0a”结尾。
- Identifier Line
值为“PF”或者“Pf”。- “PF”,说明是RGB三通道图像
- “Pf”,说明是单通道图像
- Dimensions Line
此行是图像的行列信息(不包含通道),中间以空格隔开 - Scale Factor / Endianness
缩放因子/字节顺序,该行写入的信息是全局浮点数缩放因子值,有正负之分。
如果是正值,说明图像的二进制数据是以大端序列存储,负值则为小端序列存储(不存在0值)。
只有获取depth map时才用到这个scale factor,需要disparity map的值除以这个scale factor。
raster图像数据区:
图像中每个像素值有4个字节,RGB通道则是以12个字节顺序存储,图像的像素点读取顺序按照由下到上从左至右的顺序进行读取。
Middlebury 2014数据集
http://vision.middlebury.edu/stereo/data/scenes2014/#description
数据集介绍
读取Middlebury数据集中视差图生成depth map
from pathlib import Path
import numpy as np
import csv
import re
import cv2
def read_calib(calib_file_path):
with open(calib_file_path, 'r') as calib_file:
calib = {}
csv_reader = csv.reader(calib_file, delimiter='=')
for attr, value in csv_reader:
calib.setdefault(attr, value)
return calib
def read_pfm(pfm_file_path):
with open(pfm_file_path, 'rb') as pfm_file:
header = pfm_file.readline().decode().rstrip()
channels = 3 if header == 'PF' else 1
dim_match = re.match(r'^(\d+)\s(\d+)\s$', pfm_file.readline().decode('utf-8'))
if dim_match:
width, height = map(int, dim_match.groups())
else:
raise Exception("Malformed PFM header.")
scale = float(pfm_file.readline().decode().rstrip())
if scale < 0:
endian = '<' # littel endian
scale = -scale
else:
endian = '>' # big endian
dispariy = np.fromfile(pfm_file, endian + 'f')
#
img = np.reshape(dispariy, newshape=(height, width, channels))
img = np.flipud(img).astype('uint8')
#
show(img, "disparity")
return dispariy, [(height, width, channels), scale]
def create_depth_map(pfm_file_path, calib=None):
dispariy, [shape,scale] = read_pfm(pfm_file_path)
if calib is None:
raise Exception("Loss calibration information.")
else:
fx = float(calib['cam0'].split(' ')[0].lstrip('['))
base_line = float(calib['baseline'])
doffs = float(calib['doffs'])
# scale factor is used here
depth_map = fx*base_line / (dispariy / scale + doffs)
depth_map = np.reshape(depth_map, newshape=shape)
depth_map = np.flipud(depth_map).astype('uint8')
return depth_map
def show(img, win_name='image'):
if img is None:
raise Exception("Can't display an empty image.")
else:
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
cv2.imshow(win_name, img)
cv2.waitKey()
cv2.destroyWindow(win_name)
def main():
pfm_file_dir = Path(r'middlebury\2014\Adirondack-imperfect')
calib_file_path = pfm_file_dir.joinpath('calib.txt')
disp_left = pfm_file_dir.joinpath('disp0.pfm')
# calibration information
calib = read_calib(calib_file_path)
# create depth map
depth_map_left = create_depth_map(disp_left, calib)
show(depth_map_left, "depth_map")
if __name__ == '__main__':
main()
结果: