Как визуализировать файл .pfm в виде изображения?

#image #image-processing #computer-vision #data-visualization

#изображение #обработка изображений #компьютерное зрение #визуализация данных

Вопрос:

У меня есть .pfm, который представляет собой файл (.PF / .pf). Я пытаюсь визуализировать его, но не могу этого сделать. Обычно файлы .pfm содержат заголовок формата.

  1. PF / pf
  2. ширина высота
  3. масштаб = 1

Но у моего файла есть этот заголовок.Я не могу визуализировать его как изображение, кто-нибудь может мне помочь. Любая помощь приветствуется

  1. Тип =Pic98::TPlane
  2. Строк = 750
  3. Столбцы = 1125
  4. Первая строка = 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()
     

Ответ №1:

Обновленный ответ

Я переписал свой ответ ниже в несколько ином, надеюсь, более понятном стиле.

 #!/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')
 

введите описание изображения здесь

Результат выглядит следующим образом:

 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
 

введите описание изображения здесь

Ключевые слова: Python, ImageMagick, обработка изображений, float, float32, Numpy, PFM

Комментарии:

1. Большое вам спасибо за помощь, и да, это ожидаемое изображение. У меня есть небольшой вопрос при сохранении изображения, которое вы использовали для масштабирования, как вы узнали масштабированное значение? Можете ли вы сказать мне, что я просто хочу знать, мне это интересно

2. Добро пожаловать. Код можно улучшить, но я оставлю это на ваше усмотрение — теперь, когда у вас есть что-то, с чем можно начать, это должно быть достаточно просто. Удачи с вашим проектом.

3. Большое вам спасибо за помощь и пожелания. И вам удачи

4. Что касается масштабирования, я только что сделал его полномасштабным, так что самый темный пиксель на вашем изображении получается черным, а самый яркий — белым, все остальное линейно посередине. Я получил диапазон значений в вашем изображении с np.ptp() помощью, который дает мне диапазон от пика до пика. Затем я масштабировал его на 16 бит (что лучше, чем 8 бит, которые вы получили бы в формате JPEG) и сохранил в формате PNG, потому что он поддерживает 16-битный формат и читается чем угодно. Сохраненный мной TIFF является более «верным» представлением, если вы хотите продолжить обработку, но менее доступным для простого просмотра.

5. Привет, при запуске кода на моем компьютере он показывает мне полное черное изображение