Converting a .binary file into an image - matlab

I have a .binary file that contains Depth data from a kinect sensor.
I am trying to go through the .binary file and get back the actual image in MATLAB. So this is the MATLAB program that I came up with:
fid = fopen('E:\KinectData\March7Pics\Depth\Depth_Raw_0.binary');
col = 512; %// Change if the dimensions are not proper
row = 424;
frames = {}; %// Empty cell array - Put frames in here
numFrames = 0; %// Let's record the number of frames too
while (true) %// Until we reach the end of the file:
B = fread(fid, [col row],'ushort=>ushort'); %// Read in one frame at a time
if (isempty(B)) %// If there are no more frames, get out
break;
end
frames{end+1} = B.'; %// Transpose to make row major and place in cell array
numFrames = numFrames + 1; %// Count frame
imwrite(frames{numFrames},sprintf('Depth_%03d.png',numFrames));
end
%// Close the file
fclose(fid);
frm = frames{1};
imagesc(frm)
colormap(gray)
The above program works fine but it would not give me any image thats above 99.
That is, I would be processing the .binary file and the last image I obtained is Depth_099.png even though the full video has more than that.
Does anyone knows y?
Thanks

The reason why you're not getting the images above 99 is because of the way you are format specifying your integer as you are creating your file name string as you read in the file. Specifically, here:
imwrite(frames{numFrames},sprintf('Depth_%03d.png',numFrames));
%03d.png means that you are only specifying up to 3 digits of precision, and so 999 is the max you will get. If you surpass 999, then your characters for your file name will also expand in size, so Depth_1000.png or Depth_124141.png for example. The %03d in the formatting string ensures that your number has three digits of precision, zero-padding to the left of the number to ensure that you have that many digits. If you want to maintain the same number of characters for your file name, one fix is to probably increase the number of digits of precision, something like:
imwrite(frames{numFrames},sprintf('Depth_%05d.png',numFrames));
This way, the length of the string will be longer, and going with your convention, you'll get up to 'Depth_99999.png'. If you go beyond this, then your file names will increase in character count accordingly. If you specify %05d, you are guaranteed to have 5 digits of precision, zero-padding those numbers that have less than 5 digits accordingly.
Depending on how many frames your video contains, adjust the number accordingly.
However, given your comments below.... it could just be that you only have 99 frames of data :)... but the precision tip that I mentioned above should definitely be useful.

Related

Matlab: Find the result with accuracy of certain decimal place with minimum iterations

I'm using a numerical integration method to approximate an integral. I need to use a minimum number of iterations that give an answer correct to 5 decimal places.
I cannot seem to find a generalised way of doing this. I've only been able to get it working for some cases.
Here is what I'e tried:
%num2str(x,7) to truncate the value of x
xStr = num2str(x(n),7);
x5dp(n) = str2double(xStr); %convert back to a truncated number
%find the difference between the values
if n>1 %cannot index n-1 = 0
check = x5dp(n)-x5dp(n-1);
end
This will find the first instance at which the first 5dp are the same, it doesn't take into account that changes might occur beyond that point, which has happened, the iteration I am looking for was about 450, but it stopped at 178 due to this.
Then I tried this
while err>errLim & n<1000
...
r = fix(x(j)*1e6)/1e1 %to move the 6th dp to the 1stplace
x6dp = rem(r,1)*10 %to 'isolate' the value of the 6th dp
err = abs(x(j)-x(j-1)) % calculate the difference between the two
%if the 6th decimal place is greater than 5 and err<1e-6
% then the 6th decimal place won't change the value of the 5th any more
if err<errLim && x6dp<5
err=1;
end
...
end
This works for one method and function I tested it one. However when I pasted it into another method for another function, I get the iteration ending before the final result is achieved. the final 4 results are:
4.39045203734423 4.39045305948901 4.39045406364900 4.39045505024365
However, the answer I need is actually 4.39053, this has stopped the iteration about 300 steps too early.

'Find' function working incorrectly, have tried floating point accuracy resolution

I have vertically concatenated files from my directory into a matrix that is about 60000 x 15 in size (verified).
d=dir('*.log');
n=length(d);
data=[];
for k=1:n
data{k}=importdata(d(k).name);
end
total=[];
for k=1:n
total=[total;data{n}];
end
I am using a the following 32-iteration loop and the 'Find" function to locate row numbers where the final column is an integer corresponding to the integer iteration of the loop:
for i=1:32
v=[];
vn=[];
[v,vn]=find(abs(fix(i)-fix(total))<eps);
g=length(v)
end
I have tried to account for the floating point accuracy by using 'fix' on values of 'i' and values from matrix 'total', in addition to taking their absolute difference and checking it to be less than a tolerance of 'eps' (floating-point relative accuracy function), up to a tolerance of .99.
The 'Find' function is not working correctly. It is only working for certain integers (although it should be locating all of them (1-32)), and for the integers it does find the values are incomplete.
What is the problem here? If 'Find' is inadequate for this purpose, what is a suitable alternative?
You are getting a lot of zeros because you are looking not just at the 15th column of data but the entire data matrix so you are going to have a lot of non-integers.
Also, you're using fix on both numbers and since floating point errors can cause the number to be slightly above and below the desired integer, this will cause the ones that are below to round down an integer lower than what you'd expect. You should use round to round to the nearest integer instead.
Rather than using find to do this, I would use simple boolean logic to determine the value of the last column
for k = 1:32
% Compare column 15 to the current index
matches = abs(total(:,end) - k) < eps;
% Do stuff with these matches
g = sum(matches); % Count the matches
end
Depending on what you want to actually do with the data, you may be able to use the last column as an input to accumarray to perform an operation on each group.
As a side note, you can replace the first chunk of code with
d = dir('*.log');
data = cellfun(#importdata, {d.name}, 'UniformOutput', false);
total = cat(1, data{:});

The dlmread command

I am trying to load ascii files into Matlab which contain 1020 rows and two columns of spectral data. When I use dlmread like below, Matlab turns this into a matrix N, which is what I want:
N = dlmread('alummatrix.asc')
However, I want it to read only the first 80 rows of data and ignore the rest, and then do this for all .asc files in a directory.
Also, I want the decimal number not to change or get rounded. It's outputting my data 5 decimal figures to the left of the original data. Also, I'd like it to retain its original notation and not to round:
It gives me:
N =
1.0e+05 *
0.0384 0.3374
When I just want it to show up like:
N =
3838 33738
Use this line of code:
N = dlmread('alummatrix.asc','',[0 0 80 0]);
Good luck!

How does Labview save cluster data in a binary file and how do I read it out in MATLAB?

I have a very large number of files that were saved in binary in Labview, where each column is a timestamp cluster followed by a vector of singles.
I read each data file into Matlab r2013a using
fid = fopen(filename);
data = fread(fid,[N M],'*single',0,'b');
fclose(fid);
where I pre-calculate the size of the input array N,M. Since I know what the data is supposed to look like, I have figured out that data(1:5,:) is where the timestamp data is hidden, but it looks like something like this for M = 1:
[0 -842938.0625 -1.19209289550781e-07 0 4.48415508583941e-42]
The first element is always 0, the second element decreases monotonically with a constant step size, the third seems to be bistable, flipping back and forth between two very small values, the fourth is always 0, and the fifth is also constant.
I'm assuming it has something to do with how Labview encodes dates, but my google-fu has not helped me figure that out.
To make this a more general question, then:
How does Labview encode a timestamp cluster when it saves to a binary file, and how can I read it out and translate it into a meaningful number in another programming language, such as Matlab?
EDIT:
For posterity, here is my final code (appended to the code above):
datedata = data(5:-1:1,:);
data(1:5,:) = [];
dms = typecast(reshape(datedata(2:3,:),[],1),'uint64');
dsecs = typecast(reshape(datedata(4:5,:),[],1), 'int64');
timestamp = datenum(1904,1,1) + (double(dsecs) + double(dms)*2^-64)/(3600*24);
In the code #Floris posted from Mathworks, they typecast straight to double, but when I tried that, I got garbage. In order to get the correct date, I had to first convert to integer and then to double. Since my bottleneck is in the fread line (0.3 seconds to read off of an external disk), the extra typecast step is miniscule in the grand scheme of things.
The extra column, 4.5e-42, converts to an integer value of 3200, the number of values in the subsequent vector of singles.
This is not a complete answer, but it should help (I don't have either Labview or Matlab available at home so I can't check this right now).
There is an article at http://www.mathworks.com/matlabcentral/newsreader/view_thread/292060 that describes a similar question. Couple of useful bits of information I extracted from that:
Time stamp is a double (not single)
Need to flip the order of bytes (little vs big endian) to make sense of things
There is a useful comment:
Note that the LabView time convention is miliseconds since Jan 1 1904.
Here is one approach (may contain errors but will point you in the
right direction),
The following code snippet is also given:
%% Read in date information
[ fid, msg ] = fopen(FileName, 'r') ;
NColumns = 60 ; % Number of data columns - probably different for your
dataset!
[a, count] = fread(fid, [ NColumns Inf], '*single') ; % Force data to
be read into Matlab workspace as singles
a = a' ; % Convert to data in columns not rows
% The last two columns of a are the timestamp
b = fliplr(a(:, end-1:end)) ; % Must swap the order of the columns
d = typecast(reshape(b',[],1), 'double') ; % Now we can can convert to
double
time_local = datenum(1904, 1, 1) + d/(24*3600) ; % Convert from
seconds to matlab time format
fclose(fid) ;
It looks believable to me. Let me know if it works - if not, I may be able to help debug in the morning...
A LabVIEW timestamp is a 128-bit type consisting of a signed 64-bit integer measuring the offset in seconds since the LabVIEW epoch (January 1, 1904 00:00:00.00 UTC), and an unsigned 64-bit integer measuring the fractional second. Source: ni.com.
The byte order of the file however may be platform dependent. For example the time 8:02:58.147 AM July 3 2013 EDT may be stored as:
0x 00000000CDF9C372 25AA100000000000 (big/network)
or as
0x 000000000010AA25 72C3F9CD00000000 (little)

Conceptual problems - Trim "silence" at beginning/end of wav

I need to compute the length of a wav file by trimming off the "relative" silence at the beginning and end of the file then return the duration in milliseconds. I know you can find the duration of a wav file as such:
[w,fs] = wavread('file.wav');
length = length(w)/fs;
My logic is to use the first column of the waveform matrix (left channel), get an arbitrary threshold value, then traverse the matrix through sample windows. If the maximum value of these windows is greater than the threshold then I start counting time there. When the max of this window is less than the value I stop there. This is what I have so far:
%Just use the first column in the waveform matrix, 2 gives strange results
w = w(:,1);
%Get threshold value by multiplying max amplitude of waveform and
%predetermined percentage (this varies with testing)
thold = max(w) * .04;
Just need help on how to actually traverse the matrix through sampling windows.
I am not entirely certain what you want to achieve, but I think you can use your own suggestion (sort of):
soundIdx = find(abs(w) > thold)
total_time_w_sound = sum(abs(w) > thold)/fs;
time_from_first_sound_to_last = (soundIdx(end)-soundIdx(1))/fs;
Is it one of those you are trying to find?