запись двоичных данных с помощью tobytes() не может быть прочитана с помощью программного обеспечения в Windows

Я пытаюсь записать некоторые данные точки xyz в файл .ply, используя python.

Я использую этот скрипт, который в основном пишет панд DataFrame в двоичный формат с помощью метода recarry и numpy tobytes():

import pandas as pd
import numpy as np

pc = pd.read_csv('points.txt')

with open('some_file.ply', 'w') as ply:

    ply.write("ply\n")
    ply.write('format binary_little_endian 1.0\n')
    ply.write("comment Author: Phil Wilkes\n")
    ply.write("obj_info generated with pcd2ply.py\n")
    ply.write("element vertex {}\n".format(len(pc)))
    ply.write("property float x\n")
    ply.write("property float y\n")
    ply.write("property float z\n")
    ply.write("end_header\n")

    pc[['x', 'y', 'z']] = pc[['x', 'y', 'z']].astype('f4')

    ply.write(pc[['x', 'y', 'z']].to_records(index=False).tobytes())

Этот сценарий отлично работает на моем Mac, и такое программное обеспечение, как CloudCompare, может его прочитать; однако, когда я использую тот же сценарий на компьютере с Windows, CloudCompare может читать информацию заголовка, но упаковывает двоичное содержимое.

Когда я читаю версию текстового файла в CloudCompare и вывожу в виде двоичного файла, версии для Linux и Windows могут его читать, но содержимое файла отличается.

Вот версия, созданная вышеуказанным скриптом, здесь — версия, созданная CloudCompare для Windows, и здесь — необработанные данные.


person kungphil    schedule 02.10.2019    source источник
comment
Как он использует список в качестве индекса? Является ли pc каким-то пользовательским типом, который тайно манипулирует значениями индекса?   -  person artdanil    schedule 03.10.2019
comment
Я обновил код до полного примера, используя данные из загрузки. pc — это DataFrame pandas, список индексирует столбцы в pc.   -  person kungphil    schedule 03.10.2019


Ответы (2)


Разница между made_with_code.ply и made_with_windows.ply заключается в том, что в последнем все десятичные знаки округляются до 2 знаков после запятой, как вы можете видеть:

with open('windows.ply', 'rb') as f:
    np.core.records.fromfile(f, formats='f4,f4,f4,f4')

после извлечения части данных с помощью tail -c +274 made_with_windows.ply > windows.ply.

Следующий код создает файл, идентичный (в части данных) made_with_windows.ply:

import pandas as pd
import numpy as np

pc = pd.read_csv('points.txt')

with open('made_with_code_new.ply', 'wb') as ply:
    ply.write("ply\n")
    ply.write('format binary_little_endian 1.0\n')
    ply.write("comment Author: Phil Wilkes\n")
    ply.write("obj_info generated with pcd2ply.py\n")
    ply.write("element vertex {}\n".format(len(pc)))
    ply.write("property float x\n")
    ply.write("property float y\n")
    ply.write("property float z\n")
    ply.write("end_header\n")

    pc[['x', 'y', 'z', 'n']] = pc[['x', 'y', 'z', 'n']].round(2).astype('f4')

    ply.write(pc[['x', 'y', 'z', 'n']].to_records(index=False).tobytes())
person Stef    schedule 03.10.2019

Оказывается, мне нужно было указать, какое окончание строки использовать при открытии файла:

open(output_name, 'w', newline='\n')

После перезаписи для Python 3 файл необходимо записать дважды — один раз для заголовка и один раз для двоичного компонента, поэтому новая функция выглядит так:

import pandas as pd
import numpy as np

pc = pd.read_csv('points.txt')

with open(output_name, 'w', newline='\n') as ply:

    ply.write("ply\n")
    ply.write('format binary_little_endian 1.0\n')
    ply.write("comment Author: Phil Wilkes\n")
    ply.write("obj_info generated with pcd2ply.py\n")
    ply.write("element vertex {}\n".format(len(pc)))
    ply.write("property float x\n")
    ply.write("property float y\n")
    ply.write("property float z\n")
    ply.write("end_header\n")

with open(output_name, 'ab') as ply:
    pc[['x', 'y', 'z']] = pc[['x', 'y', 'z']].astype('f4')
    ply.write(pc[cols].to_records(index=False).tobytes()) 
person kungphil    schedule 24.02.2020