Проблемы, когда я пишу массив np в двоичный файл, новый файл составляет только половину исходного

Я пытаюсь удалить верхние 24 строки необработанного файла, поэтому я открыл исходный необработанный файл (назовем его raw1.raw) и преобразовал его в nparray, затем я инициализировал новый массив и удалил верхние 24 строки, но после записи нового массив в новый двоичный файл (raw2.raw), я обнаружил, что raw2 составляет только 15,2 МБ, в то время как исходный файл raw1.raw равен 30,6 МБ, мой код:

import numpy as np
import imageio
import rawpy
import cv2


def ave():
    
    fd = open('raw1.raw', 'rb')
    rows = 3000 #around 3000, not the real rows
    cols = 5100 #around 5100, not the real cols
    f = np.fromfile(fd, dtype=np.uint8,count=rows*cols)
    I_array = f.reshape((rows, cols)) #notice row, column format
    #print(I_array)
   
    fd.close()

    im = np.zeros((rows - 24 , cols))
    for i in range (len(I_array) - 24):
        for j in range(len(I_array[i])):
            im[i][j] = I_array[i + 24][j]
            
    #print(im)

    newFile = open("raw2.raw", "wb")
    
    im.astype('uint8').tofile(newFile)
    newFile.close()


if __name__ == "__main__":
    ave()

Я пытался использовать im.astype('uint16') при записи в двоичный файл, но значение было бы неверным, если бы я использовал uint16.


person user916169    schedule 11.02.2021    source источник
comment
Не имеет отношения к вашему вопросу, но вы можете сделать im = I_array[24:,:], чтобы отрезать первые 24 строки.   -  person mtrw    schedule 11.02.2021
comment
да, но они одинаковые, что меня смущает, так это размер файла   -  person user916169    schedule 11.02.2021


Ответы (1)


Очевидно, что в вашем файле «raw1.raw» должно быть больше данных, которые вы не используете. Вы уверены, что этот файл не был создан с использованием данных «uint16», и вы просто извлекаете первую половину как данные «uint8»? Только что проверил запись случайных данных.

import os, numpy as np

x = np.random.randint(0,256,size=(3000,5100),dtype='uint8')
x.tofile(open('testfile.raw','w'))
print(os.stat('testfile.raw').st_size) #I get 15.3MB. 

Таким образом, «uint8» для 3000 на 5100 явно занимает 15,3 МБ. Я не знаю, как вы получили 30+.

############################ РЕДАКТИРОВАТЬ #########

Просто чтобы добавить больше разъяснений. Вы понимаете, что dtype не делает ничего, кроме изменения представления ваших данных? Это не влияет на фактические данные, которые сохраняются в памяти. Это также относится к данным, которые вы читаете из файла. Возьмем, к примеру:

import numpy as np

#The way to understand x, is that x is taking 12 bytes in memory and using
#that information to hold 3 values. The first 4 bytes are the first value, 
#the second 4 bytes are the second, etc. 
x = np.array([1,2,3],dtype='uint32') 

#Change x to display those 12 bytes at 6 different values. Doing this does
#NOT change the data that the array is holding. You are only changing the 
#'view' of the data. 
x.dtype = 'uint16'
print(x)

В общем (есть несколько особых случаев) изменение dtype не меняет базовые данные. Однако функция преобразования .astype() изменяет базовые данные. Если у вас есть какой-либо массив из 12 байтов, рассматриваемый как «int32», то запуск .astype('uint8') возьмет каждую запись (4 байта) и скроет ее (известную как приведение) к записи uint8 (1 байт). Новый массив будет иметь только 3 байта для 3 записей. Вы можете увидеть это буквально:

x = np.array([1,2,3],dtype='uint32')
print(x.tobytes())
y = x.astype('uint8')
print(y.tobytes())

Таким образом, когда мы говорим, что размер файла составляет 30 МБ, мы имеем в виду, что размер файла (за вычетом некоторой информации в заголовке) составляет 30 000 000 байтов, что равно uint8. 1 uint8 — это 1 байт. Если какой-либо массив имеет 6000x5100 uint8s (байт), то массив имеет 30 600 000 байт информации в памяти.

Аналогично, если вы читаете файл (НЕ ИМЕЕТ ВАЖНОГО ФАЙЛА) и пишете np.fromfile(,dtype=np.uint8,count=15_300_000), то вы говорите python читать ТОЧНО 15_300_000 байтов (опять же 1 байт равен 1 uint8) информации (15мб). Если ваш файл имеет размер 100 МБ, 40 МБ или даже 30 МБ, это будет совершенно неважно, потому что вы сказали python читать только первые 15 МБ данных.

person Bobby Ocean    schedule 11.02.2021
comment
Я имею в виду, что исходный необработанный файл составляет 30+ МБ, после того, как я открыл его с помощью uint 8 и записал в новый двоичный файл, он стал 15 МБ. - person user916169; 11.02.2021
comment
Но если вы открыли 15-мегабайтный файл и прочитали ровно 3000x5100 uint8, то вы, должно быть, прочитали только половину файла. Попробуйте сделать матрицу 6000х5100 и прочитать uint8 из этого файла. - person Bobby Ocean; 11.02.2021
comment
Я имел в виду 30 мб, а не 15 мб. - person Bobby Ocean; 11.02.2021
comment
Нет, файл именно 3000 * 5100, я просто прочитал его как форму uint8, я не знаю исходный тип значения, но я пытался использовать uint16, размер вывода правильный, но значение пикселя было неправильным, я я действительно смущен. - person user916169; 12.02.2021
comment
Я не знаю, что тебе сказать. Я ничего не знаю о вашем деле и о том, как оно было написано. Вы запускали мой код выше? Вы можете ясно видеть, что файл должен быть 15 МБ, если он был 3000x5100 uint8s. В вашем файле явно содержится 30 МБ данных, что составляет буквально 30 000 000 байт, что составляет примерно 6000x5100 uint8s (30 600 000 байт). Я не знаю, как это объяснить по-другому. - person Bobby Ocean; 12.02.2021
comment
Я добавил обновление, я думаю, что, возможно, dtype - это путаница. Не стесняйтесь поправлять меня, если я ошибаюсь. - person Bobby Ocean; 12.02.2021
comment
Спасибо за ваш ответ, но я только что обнаружил, что каждое значение пикселя может использовать 2 байта для сохранения, поэтому окончательный размер будет двойным, но мне интересно, как использовать 2 байта для сохранения на значение. - person user916169; 18.02.2021
comment
Два байта просто означают, что int16 или uint16 - это формат ваших данных. - person Bobby Ocean; 21.02.2021