如何将.pfm文件可视化为图像?

3

我有一个.pfm文件,它是一个(.PF/.pf)文件。我想可视化它,但我无法做到。通常.pfm文件包含格式的头信息。

  1. PF/pf
  2. 宽度 高度
  3. 比例=1

但我的文件具有以下头信息。因为无法将其作为图像进行可视化,所以请帮帮我。感谢任何帮助。

  1. Typ=Pic98::TPlane

  2. Lines=750

  3. Columns=1125

  4. FirstLine=0

  5. FirstColumn=0

    import re
    import numpy as np
    file = open("PF file.PF", 'rb')
    header = file.readline().rstrip().decode('utf-8')
    if header == 'PF':
       raise Exception('Only ONE channel image is supported.')
    elif header == 'Typ=Pic98::TPlane<float>':
        color = False
    else:
        raise Exception('Not a PFM file.')
    dim_match = re.match(r'(^(\w+).(\d+)$)\n(^(\w+).(\d+)\s$)', 
    file.readline().decode('ascii'))
    if dim_match:
      width, height = map(int, dim_match.groups())
    else:
      raise Exception('Malformed PFM header.')
    if header == 'Typ=Pic98::TPlane<float>':
      scale =1
      endian = '>'
    else:
      scale = -scale
      endian = '<'
    
    npImage = np.reshape(npImage, width,height)
    npImage = np.flipud(npImage)
    
    if ret_PIL:
      img = Image.fromarray(npImage, 'F')
      return img
    return npImage
    file.close()
    

我在Windows上制作了一个应用程序,链接为https://github.com/SiliconStudio/PfmViewer。 - v.oddou
2个回答

0

我在Mac和Ubuntu上使用这个cvkit工具https://github.com/roboception/cvkit。它非常适用于可视化“.pfm”文件(例如,保存为pfm文件的视差或深度图)。


0

更新的答案

我已经以稍微不同但更清晰的风格重新撰写了下面的答案。

#!/usr/bin/env python3

import re
import cv2
import numpy as np
from PIL import Image

def readPF(filename):
   """Read named PF file into Numpy array"""

   # Slurp entire file into memory as binary 'bytes'
   with open(filename, 'rb') as f:
      data = f.read()

   # Check correct header, return None if incorrect
   if not re.match(b'Typ=Pic98::TPlane<float>', data):
      return None
   
   # Get Lines and Columns, both must be present, else return None
   L = re.search(b'Lines=(\d+)',   data)
   C = re.search(b'Columns=(\d+)', data)
   if not (L and C):
      return None
   height = int(L.groups()[0])
   width  = int(C.groups()[0])
   print(f'DEBUG: Height={height}, width={width}')

   # Take the data from the END of the file in case other header lines added at start
   na = np.frombuffer(data[-4*height*width:], dtype=np.dtype('<f4')).reshape((height,width))

   # Some debug stuff
   min, max, mean = na.min(), na.max(), na.mean()
   print(f'DEBUG: min={min}, max={max}, mean={mean}')

   return na

################################################################################
# Main
################################################################################
na = readPF('PF file.PF')

################################################################################
# Use either of the following to save the image:
################################################################################
# Save with OpenCV as scaled PNG
u16 = (65535*(na - np.min(na))/np.ptp(na)).astype(np.uint16)  
cv2.imwrite('OpenCV.png', u16)

# Convert to PIL Image and save as TIFF
pi = Image.fromarray(na, mode='F')
pi.save('PIL.tif')

原始回答

不太确定我应该期望什么样的图像,但是这里有一个大概的想法:

#!/usr/bin/env python3

import re
import cv2
import numpy as np
from PIL import Image

file = open("PF file.PF", 'rb')
header = file.readline().rstrip().decode('utf-8')
if header == 'PF':
   raise Exception('Only ONE channel image is supported.')
elif header == 'Typ=Pic98::TPlane<float>':
    color = False
else:
    raise Exception('Not a PFM file.')

while True:
    line = file.readline().decode('ascii')
    match = re.match('(\w+)=(\d+)', line)
    n, v = match.groups()
    if n == 'Lines':
        height = int(v)
        print(f'Height: {height}')
    if n == 'Columns':
        width = int(v)
        print(f'Width: {width}')
        break

# Seek backwards from the end of the file in case any clown has added something to the header
file.seek(-height*width*4,2)

# Read remainder of file into Numpy array of floats and reshape
na = np.fromfile(file, dtype=np.float32).reshape((height,width))

# Some debug stuff
min, max, mean = na.min(), na.max(), na.mean()
print(f'DEBUG: min={min}, max={max}, mean={mean}')

################################################################################
# Use either of the following to save the image:
################################################################################
# Save with OpenCV as scaled PNG
u16 = (65535*(na - np.min(na))/np.ptp(na)).astype(np.uint16)  
cv2.imwrite('OpenCV.png', u16)

# Convert to PIL Image and save as TIFF
pi = Image.fromarray(na, mode='F')
pi.save('PIL.tif')

enter image description here

输出结果如下:

Height: 750
Width: 1125
DEBUG: min=0.0, max=127881704.0, mean=1618343.625

另一种可能性是使用ImageMagick将其转换为PNG格式,我得到了以下结果,ImageMagick默认为小端序,因此如果这是正确的话,您的图像就是小端序的。
magick -define quantum:format=floating-point -depth 32 -size 1125x750+80 gray:"PF file.pf"  -auto-level image.png

enter image description here

关键词: Python, ImageMagick, 图像处理, 浮点数, float32, Numpy, PFM


关于缩放,我将其设置为全比例,这样您图像中最暗的像素就会变成黑色,最亮的像素就会变成白色,其他所有像素都会线性地在两者之间。我使用 np.ptp() 获取了您图像的值范围,该函数给出了峰对峰范围。然后,我将其缩放到 16 位(这比 JPEG 的 8 位更好),并保存为 PNG,因为 PNG 支持 16 位,并且可以被任何程序读取。如果您想进一步处理图像,则保存为 TIFF 可以提供更加“真实”的表示,但不太适合简单查看。 - Mark Setchell
以下是相同的图像保存链接,1(https://drive.google.com/file/d/1_k2kIatdIxzqkskgle45NozuML9VPKZu/view?usp=sharing),2(https://drive.google.com/file/d/1lDNtmQvarsi8QhhRmkgU1QV8zXLfV2aJ/view?usp=sharing)。 - Blueman7
请问您能分享一下您得到的输出文件吗?可以使用Dropbox、Google Drive或类似的工具。 - Mark Setchell
这里我再次添加它们: 1(https://drive.google.com/file/d/1_k2kIatdIxzqkskgle45NozuML9VPKZu/view?usp=sharing),2(https://drive.google.com/file/d/1lDNtmQvarsi8QhhRmkgU1QV8zXLfV2aJ/view?usp=sharing) - Blueman7
非常感谢你,马克。哥们儿,我想向你学习并获取知识。祝你晚上愉快。祝你有美好的一天,注意安全。 - Blueman7
显示剩余28条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接