2014-06-09 3 views
4

"myfile.dat"로 이름이 바뀐 MNIST 이미지 데이터베이스의 이진 파일이 있습니다. 이것은 4 개의 부호없는 32 비트 정수로 구성되며 그 뒤에 부호없는 8 비트 정수 체인이옵니다. 나는이 파일을 읽고 그 내용을 배열로 저장하려고한다. 여기 내 코드입니다 :MATRIAB에서 MNIST 이미지 데이터베이스 이진 파일 읽기

file_id = fopen('myfile.dat', 'rb'); 
data = fread(file_id, 'int'); 
size(data) 
class(data) 

그리고 출력은 예상대로

ans = 

    2502   1 


ans = 

double 

의 크기 (2502, 1)입니다. 그러나 그것이 내가 int으로 지정되었을 때 데이터가 double 인 것을 나에게 말하는 이유는 무엇입니까?

처음 몇 개의 숫자가 있어야하며 출력 데이터가 예상과 다를 것이라고 알고 있습니다. 나는 또한 int32, uintuint32 같은 문제가있는 시도했다.

+0

설명서를 보면 'int'한정자가 올바른 결과를 보장하지 않습니다. 'int32'로 지정하십시오. 또한 데이터를 표시 할 때 예상되는 모든 데이터가 있습니까? 모든 숫자가 정확합니까? 그렇다면, 진행하기 전에 단순히'int32'로 변환하면됩니다. – rayryeng

+0

예, 저는 uint와 uint32와 함께 int32도 시도했습니다. 내가 아는 모두는 이진 파일이 32 비트 정수이지만, 직접 만들지는 않았다. 출력 데이터는 내가 예상했던대로는 아니며, 처음 몇 자리가 무엇인지 알아야합니다. – EddyJ

+0

어딘가에 그 파일을 게시 할 수 있습니까? 우리는 추가로 – rayryeng

답변

3

MATLAB이 한 번에 4 개의 정수로 읽는 방법은 little-endian 형식이며 MNIST 데이터베이스 파일의 파일 형식은 big-endian입니다. 따라서 파일의 처음 4 바이트를 읽을 때 바이트는 0x00, 0x00, 0x08, 0x03으로 예상됩니다. 그러나 MATLAB은 이것을 0x03, 0x08, 0x00, 0x00으로 읽을 것입니다. 이것을 정수로 변환 할 때 우리는 실제로 우리가 원하는 것이 아닌 50855936을 얻을 것입니다.

이 문제를 해결하기위한 해킹은 한 번에 여러 바이트를 읽을 필요가있을 때 데이터 유형을 uint8으로 지정해야합니다. 이렇게하면 각 바이트가 배열의 개별 요소로 저장됩니다. 그런 다음 각 바이트를 지정된 양만큼 비트 이동 한 다음 결과를 합산하여 필요한 수를 계산할 수 있습니다. 데이터 파일의 처음 몇 바이트에 대해이 작업을 수행해야합니다.

또는 의견에 명시된대로 swapbytes 메서드를 사용할 수 있습니다. 그러면 정확히 똑같은 결과가 나타납니다. uint32 유형의 1 바이트를 읽은 다음 바이트의 순서를 스왑하여 바이트가 big-endian 형식이되도록합니다. uint32으로 데이터를 읽었을 때도 숫자는 double으로 MATLAB에 저장되므로 swapbytes으로 들어가기 전에 숫자를 캐스팅해야한다는 것을 명심해야합니다.

일단 실제 이미지 데이터에 도달하면 numRows x numCols 바이트 단위로 읽을 수 있고 어레이가 이미지가되도록 배열을 바꿀 수 있습니다. 각 이미지를 셀 배열에 저장할 수 있습니다. 더 이상 신경 쓰지 않고 여기에 코드가 있습니다.

clear all; 
close all; 

%//Open file 
fid = fopen('t10k-images-idx3-ubyte', 'r'); 

%//Read in magic number 
%//A = fread(fid, 4, 'uint8'); 
%//magicNumber = sum(bitshift(A', [24 16 8 0])); 

%//OR 
A = fread(fid, 1, 'uint32'); 
magicNumber = swapbytes(uint32(A)); 

%//Read in total number of images 
%//A = fread(fid, 4, 'uint8'); 
%//totalImages = sum(bitshift(A', [24 16 8 0])); 

%//OR 
A = fread(fid, 1, 'uint32'); 
totalImages = swapbytes(uint32(A)); 

%//Read in number of rows 
%//A = fread(fid, 4, 'uint8'); 
%//numRows = sum(bitshift(A', [24 16 8 0])); 

%//OR 
A = fread(fid, 1, 'uint32'); 
numRows = swapbytes(uint32(A)); 

%//Read in number of columns 
%//A = fread(fid, 4, 'uint8'); 
%//numCols = sum(bitshift(A', [24 16 8 0])); 

%// OR 
A = fread(fid, 1, 'uint32'); 
numCols = swapbytes(uint32(A)); 

%//For each image, store into an individual cell 
imageCellArray = cell(1, totalImages); 
for k = 1 : totalImages 
    %//Read in numRows*numCols pixels at a time 
    A = fread(fid, numRows*numCols, 'uint8'); 
    %//Reshape so that it becomes a matrix 
    %//We are actually reading this in column major format 
    %//so we need to transpose this at the end 
    imageCellArray{k} = reshape(uint8(A), numCols, numRows)'; 
end 

%//Close the file 
fclose(fid); 

당신이 (numRows, numCols로 저장) 행과 열의 수 (magicNumber로 저장) 마법 번호와 (totalImages로 저장) 이미지의 총 수를 선택하면,이 2051, 28, 28 같아야한다 및 각각 10000. 이 코드 다음에 kth 요소 인 imageCellArraykth 자릿수를 MNIST 데이터베이스에 저장합니다. imshow(imageCellArray{k});을 입력하는 경우 k1에서 10000 사이의 정수입니다. 숫자를 볼 수 있어야합니다.

또 하나의 마지막 참고 사항 : 행렬 데이터를 읽는 것이 double 일 때 이미지가 데이터베이스에서 해당 유형이므로 uint8이되도록 캐스팅해야합니다.

행운을 빈다.

+0

감사합니다. 그것은 지금 잘 작동합니다 :). 당신의 방법에 기반을 둔 또 다른 해결책은 swapbytes 함수를 사용하는 것입니다 :'magic_num = swapbytes (uint32 (data (1))) etc ....' – EddyJ

+0

@EddyJ : Cool! 이걸 알면 다행이야! 내 게시물을 수정하겠습니다. – rayryeng

+0

@EddyJ : 완료. 좋은 일은'swapbytes'와 내 게시물을 수락 해 주셔서 감사합니다. 행운을 빕니다! – rayryeng