I am trying to read an uncompressed AVI file - basic uncompressed AVI are BGR bitmaps.
if(frame.format == AV_PIX_FMT_BGR24)
{
int data_size = frame.linesize[0]*frame.height;
my_data_ptr = new uint8_t [data_size];
memcpy(my_data_ptr, frame.data[0], data_size);
}
I would expect frame.linesize[0] to be width*3 but I find it is -width*3.
If manually set data_size so it is not negative the memcpy results in a seg fault.
Are packed pixel formats stored in a special way ?
The negative line size indicates that the frame is inverted (raw AVI are coded this way).
The data pointer points to the top line and if you add the negative linesize to the pointer you get to the next line. This means you are reading the image backwards, so using a non negative linesize for the memcpy in the code aboves means you will read the image forwards and go into unallocated memory after the first line.
Related
I am reading binary data from instrumentation using the Matlab udp() object.
I am surprised by the apparent lack of support for reading arbitrary length data types. How does one read a 24-bit integer? Or a 24-bit float? These are not that strange in instrumentation, and I have found only 8/16/32/64 data types in the documentation.
Have you looked tried help fread? The documentation shows it supports reading up to 64 bits at a time using bitN where N is a value between 1 and 64.
fid = udp(<your parameters here>); % use fopen to open the stream.
...
A = fread(fid,1,'bit24=>int32'); % stream 24 bits to a 32 bit integer.
B = fread(fid,1,'ubit24=>uint32'); % stream 24 bits to a 32 bit unsigned integer.
Since floating point specs vary, so this may or may not work for your situation:
C = fread(fid,1,'bit24=>float32'); % transcode 24bits to 32 bit float (MATLAB spec)
UPDATE
Seeing that the udp/fread implementation does not support this casting there are a couple, not-so-pretty, workarounds you can try.
Read in uchar data in multiples of three and then multiply it by their byte offsets directly. For example:
% First determine number of bytes on the stream and make sure you
% have at 3 or more bytes to read so you can calculate thirdOfBytesExpected.
[anMx3result, packetCount] = fread(fid,[thirdOfBytesExpected,3]);
unsigned20bitInt = anMx3result*(2.^(0:8:16))';
To be precise, the unsigned20bitInt is actually stored as a MATLAB double here. So if you need to write it elsewhere, you will need to bring it back to the individual uchar types it came from.
The not so pretty option is to eat the overhead of streaming the data back to a binary file format as an interim step so that you can then use the base fread method mentioned above. Not an ideal solution, but perhaps worth considering if you just need something to work.
% your original code for opening the udp handle
....
tmpFid = fopen('tmp.bin','rw');
[ucharVec, bytesRead] = fread(udpFid,bytesExpected,'uchar=>uchar');
bytesWritten = fwrite(tmpFid,ucharVec,'uchar');
% Do some quality control on bytes read vs written ...
fseek(tmpFid,-bytesWritten,'cof');
% in theory you should be able to just go to the beginning
% of the file each time like this fseek(tmpFid, 0, 'bof');
% provided you also reset to the beginning prior writing or after reading
% Read in the data as described originally
num24ByteIntsToRead = bytesWritten/3;
A = fread(tmpFid,num24BytsIntsToRead,'bit24=>int32');
I have a singe image.tiff file, a video sequence exported as 32 bit tiff. I would like to open it as an image stack in MATLAB, and be able to navigate frame by frame. I believe implay() is the way to do this in matlab. If I try this I get "Error occurred while attempting to read file: image.tiff Details of error: Incorrect chunk size information in AVI file." Does implay() only work with the .avi format? do I need to covert this 32 tiff to a .avi before i can use implay()? or is there maybe some other (non-implay()) way of opening this as a stack?
Thanks
You could try to create an image stack and use implay to view it. The function accepts multiple types of arguments, for grayscale images it should be provided with an array of size N x M x K where K is the number of frames, (N,M) is the image size. For color images an array of size NxMx3xK is expected.
To create the array for the case with multiple files, each containing a frame you have multiple options, the simplest is probably to use the cat function for concatenation:
image_stack = [];
for i = 1: num_frames
curr_image = imread(sprintf('frame_%04d_color.tif', i));
image_stack = cat(4, image_stack, curr_image);
end
implay(image_stack);
This solution is a bit slower, than if the image_stack is allocated beforehand though.
For your case with a single TIFF file, the frames need to be extracted in a manner suitable for the storage format, but this is a separate problem from the video replay.
I'm trying to read a text file chunk by chunk where every chunk has a size of 10KB for example..
How to do that in matlab??
BTW You can't control the content of the text file (which means you can't suggest adding a specific character to split the text file)
I believe you could start by using fread, and then specify that you want to read n bytes at a time- something like this, perhaps?
n = 10000
file = fopen(fileID)
A = zeros(n, 'uchar') --perhaps char*1 for a text file?
A = fread(file, size(A))
What this should do is read 10KB, and then leave the pointer where it read the last character. If you call fread again with the same parameters, it should give you the next n bytes. I'd double check this, but I don't have a copy of Matlab at the moment.
I am attempting to quantize a 16 bit .wav file to a lower bit rate using Matlab. I've opened the file using wavread() but I am unsure of how to proceed from here. I know that somehow I need to "round" each sample value to (for example) a 7 bit number. Here's the code that's reading the file:
[file,rate,bits] = wavread('smb.wav');
file is a 1 column matrix containing the values of each sample. I can loop through each item in that matrix like so:
for i=1 : length(file)
% not sure what to put here..
end
Could you point me in the right direction to quantize the data?
If you have int16 data, varying from -32768 to +32767, it can be as simple as
new_data = int8(old_data./2^8);
That won't even require a for loop.
For scaled doubles it would be
new_data = int8(old_data.*2^7);
The wavread documentation suggests that you might even be able retrieve the data in that format to begin with:
[file,rate,bits] = wavread('smb.wav','int8');
EDIT: Changing the bit rate:
After rereading the question, I realize that you also mentioned a lower bit rate which implies reducing the sample rate, not the quantization of the data. If that is the case, you should look at the documentation for downsample, decimate, and/or resample. They are all built in MATLAB functions that change the bit rate.
downsample(file,2)
would half the bit rate, for example.
I'd like to read heterogenious binary data into matlab. I do know from the beginning how much it is and in which datatype each segment is. For example:
%double %double %int32 ...
and then this get repeated about a million times. Easy enoug to handle with fread since the know the number of bites for each segment and can therefore calculate the skip value for each row.
But now the data segment looks something like this :
%double %int32%*char %double %double ...
Whereby the int prior to the *char is the length of the said string. This brings the problem that I cannot calculate the skip anymore and I'm stuck be reading in the whole file line by line therefore needing to make a lot more file access and slowing everthing down.
In order to get at least some speed up I wan't to read in all %double %double ... (Around 30 elements) at a time and then use those from a buffer to fill up the array's. In C this would be a rather easy task here, without memcpy and not so direct access to pointers...
Do you know any way to achive this, not using mex files?
You can't solve the problem that the record size is unknown, and thus you don't know how much to read ahead of time. But you can batch up the reads, and if you have a reasonable max size for the string, you can always read that amount, and ignore the unneeded bytes at the end. typecast is the trick:
readlen = 1024;
buf = fread(fid, readlen, '*uint8'); % the asterisk keeps the returned array as uint8
rec.val1 = typecast(buf(1:8), 'double');
string_len = typecast(buf(9:12), 'int32');
rec.str1 = typecast(buf(13:13+string_len-1), 'uint8');
pos = 13+string_len;
rec.val2 = typecast(buf(pos:pos+8-1), 'double');
You might wrap a simple function around this technique to track the current offset automatically.