Tiff: algorithm to decode PackBits - image-processing

While working on a routine to open TIFF files generated by a microscope software in Matlab I got stuck on reading compressed images. At this point it's a matter of honour for me to understand how to decode tiff data in the PackBits format.
With little experience in real computer science, I have troubles understanding the guidelines in the TIFF documentation, more specifically:
In the inverse routine, it is best to encode a 2-byte repeat run as a
replicate run except when preceded and followed by a literal run. In
that case, it is best to merge the three runs into one literal run.
Always encode 3-byte repeats as replicate runs. That is the essence of
the algorithm. Here are some additional rules:
• Pack each row
separately. Do not compress across row boundaries.
• The number of uncompressed bytes per row is defined to be (ImageWidth + 7) / 8. If the uncompressed bitmap is required to have an even number of bytes per row, decompress into word-aligned buffers.
• If a run is larger than 128 bytes, encode the remainder of the run as one or more additional replicate runs.
source: https://www.fileformat.info/format/tiff/corion-packbits.htm
I understand how to implement the pseudocode, and decode a sample string compressed with PackBits in Matlab. However, I'm lost during parsing a chunk of 16 bit, greyscale Tiff file. My question is how do I go about it? I don't really understand what it means in replicate run, neither what is a word-aligned buffer.
When I start decoding the data form form the first byte, I just get nonsense.
Help with understanding the logic of decompression will be appreciated, also a link to code decompressing the Tiff PackBits will be helpful.
~Jakub
Edit: I got the decompression algorithm to work, my error was to interpret the bytes wrongly, here is a code, if anyone will be interested in a similar problem in the future.
Tiff_file = 'compressed.tiff';
%open and read tiff file file
imInfo = imfinfo(Tiff_file);
fId = fopen(Tiff_file);
im = fread(fId);
fclose(fId);
%parse the file
output = zeros(1,imInfo.Width * imInfo.Height * 2);%preallocate
thisLoc = 1;
for strip = 1:length(imInfo.StripOffsets)
thisLength = imInfo.StripByteCounts(strip);
thisOffset = imInfo.StripOffsets(strip);
thisStrip = im(thisOffset + 1 : thisOffset + thisLength);
pntr = 1; %start at the first byte
%loop throught the coded data
while pntr < thisLength
key = thisStrip(pntr);
if key >= 129
key = 257 - key;
datTmp = repmat(thisStrip(pntr+1), [1 key]);
output(thisLoc:thisLoc+key-1) = datTmp;
thisLoc = thisLoc+key;
pntr = pntr + 2;
elseif key == 128 %nope
pntr = pntr + 1;
else
datTmp = thisStrip(pntr + 1 : pntr + 1 + key);
output(thisLoc:thisLoc+key) = datTmp;
thisLoc = thisLoc + key+1;
pntr = pntr + key + 2;
end
end
end
im = typecast(uint8(output),'uint16');
%reshape decoded data.
im = reshape(im,[imInfo.Width imInfo.Height])';

Related

How to cut and convert bytes in micropython

I am trying to decode Can frames with micropython. I miss a lot of functions from python 3.x. I get 8 hex long bytes from the Rx SPI buffer of an MCP2515. For information, I'm on openMV IDE. I would like to extract the 1st and 2nd to make an integer, the 3rd and 4th to make another one, etc...
Along my researches, I found a function that convert a byte to signed integer (as the sign=True argument is not implemented in the from_byte function).
The main problem is that the solutions provided on others python's forum are only concerning python 3.x for pc but not micropython and a lot of solutions end with "function doesn't exist".
byte = b'\x12\x34\x56\x78\x9A\xBC\xDE\xFF'
def byte2int(bList, signed:bool=False):
if signed :
r = 0
for i in range(2):
d = 32 - ((i + 1) * 8)
r += bList[i] << d
return r
else : return int.from_bytes(byte, 'big')
Moreover, I don't think that I can trust the print function as print(b) return :
> print(b)
b'\x124Vx\x9a\xbc\xde\xff'
I don't understand why does the 3 vanished and was replaced by a 'V' after the 4 ! Sometime, my MCP2515 return some '|', '?', '.', '>', '<' or '=' when I print the can frames which are not hex characters !?
My hypothesis is that these are corrupted frames or SPI transmission.
Please, can someone help me to understand why micropython give me these messy results ?
Thank you very for your help.
I wrote something. Maybe not the best optimization possible, but I have to deal with micropython which is not as advanced than Python 3.x
This is a solution (surely not the most optimal). But it seems to work.
byte = b'\xFF\xC8\x56\x78\x9A\xBC\xDE\xFF'
byte2 = b'\x00\x00\x00#\x00\x00\x00\x00'
def extract(trame, signed:bool=False):
r = [0,0,0,0]
trame = [int(x) for x in bytearray(byte)]
for i in range(len(trame)/2):
val = (trame[i*2]<<8)+trame[i*2+1]
if signed and val > 0x8000 :
r[i] = -(65535-int(val)+1)
else :
r[i] = int(val)
return r
print(extract(byte, True))

Reliably identifying a JPG?

For the purpose of identifying and comparing JPG images taken from cameras I want to calculate a MD5 hash of the scan portion of the image inside the JPG. My idea is to take the bytes between the SOS and the EOI marker and perform a hash on those bytes based on the assumption that these bytes will never change unless the actual image is processed and altered.
Apparently this question has come up already several times 1,2, 3. Rather complicated solutions have been suggested, a fact that I find irritating looking at my rather simple but apparently effective approach. (Or is it too simple to be true?)
I know there can be multiple pairs of SOS ($FFDA) and EOI ($FFD9) in a JPG file, in my present files there are 3: A thumbnail, the actual image and an additional 1920x1080 image (Sony). My present approach is to parse the stream and locate the next SOS, then look for EOI, calculate the size and assume the actual image if the size exceeds 50% of the file size.
This approach works with my present files. I stripped all metadata from a JPG file with exiftool -all= image.jpg and found the MD5 hash to be identical. Yet the algorithm seems rather coarse to me.
So here are my questions:
Is there any risk that simply examining the space between SOS and EOI can fail? I have read this, but am still not sure.
Parsing every byte from the SOS of the actual image takes a lot of time. I take it from here that there is no shortcut to finding the end of the compressed data. But I might just leap forward 80% or so from the second SOS marker. I am talking about images from a camera - how much can I rely on the fact that there will be a thumbnail coming first and the actual image after it?
Should I start 6 Bytes after SOS (here?)
Any ideas for a better approach?
After doing some research and running an bunch of tests here I present my solution to my question.
First, I want to make clear that we are not talking about a forensic investigation. There are possibly ways to manipulate a JPG image in a way that markers appear where they shouldn't and do not appear where would have to according to the specs.
We are not talking about image identity or similarity, either. If you losslessly rotate a JPG you still have the very same image information, but not the identical image any more. We're not talking, either, about images that have been resized, optimized or altered in any other way.
What we are talking about is identifying simple duplicates or JPGs that have been renamed or where metadata has been modified or removed, but where the image itself has never been processed or tampered with in any way.
Is a hash of the bytes between the SOS and the EOI markers a reliable way to uniquely identify an image?
Yes, it is. Within bounds of reason there is no way two files with identical MD5 checksums of the image scan data can contain non-identical images and vice versa.
I examined sample photos taken with cameras from 12 different makers and edited/stripped the metadata. Actually, this wasn't really necessary, because from the specs and the code you know that all metadata resides in separate blocks (that's why you can hide all kind of stuff in a JPG) and the scan data will never be touched by metadata operations, but yes, identical MD5 checksums all over the place.
Is there any way to quickly locate the (right) SOS marker?
Definitely. The JPG specs are a mess and a punishment. After trying quite a few pieces of code I found NativeJPG by Nils Haeck to be the most straightforward.
This has been adapted from sdJpegImage:
function FindSOSPos(S: TStream): Cardinal;
var
B, MarkerTag, BytesRead: byte;
Size,W: word;
const
mkNone = 0; mkSOF0 = $c0; mkSOF1 = $c1; mkSOF2 = $c2; mkSOF3 = $c3; mkSOF5 = $c5;
mkSOF6 = $c6; mkSOF7 = $c7; mkSOF9 = $c9; mkSOF10 = $ca; mkSOF11 = $cb; mkSOF13 = $cd;
mkSOF14 = $ce; mkSOF15 = $cf; mkDHT = $c4; mkDAC = $cc; mkSOI = $d8; mkEOI = $d9; mkSOS = $da;
mkDQT = $db; mkDNL = $dc; mkDRI = $dd; mkDHP = $de; mkEXP = $df; mkAPP0 = $e0; mkAPP15 = $ef; mkCOM = $fe;
begin
Repeat
Result := 0;
// Read markers from the stream, until a non $FF is encountered
If S.Read(B, 1) = 0 then
exit;
// Do we have a marker?
if B = $FF then
begin
BytesRead := S.Read(MarkerTag, 1);
while (BytesRead > 0) and (MarkerTag = $FF) do
begin
MarkerTag := mkNone;
BytesRead := S.Read(MarkerTag, 1);
end;
Size := 0;
if MarkerTag in [mkAPP0..mkAPP15, mkDHT, mkDQT, mkDRI,
mkSOF0, mkSOF1, mkSOF2, mkSOF3, mkSOF5, mkSOF6, mkSOF7, mkSOF9, mkSOF10, mkSOF11, mkSOF13, mkSOF14, mkSOF15,
mkCOM, mkDNL] then
begin
// Read length of marker
If S.Read(W, 2) = 2 then
Size := Swap(W) - 2
else exit;
end else
If MarkerTag = mkSOS
then break;
S.Position := S.Position + Size;
end else
begin
// B <> $FF is an error, we try to be flexible
repeat
BytesRead := S.Read(B, 1);
until (BytesRead = 0) or (B = $FF);
if BytesRead = 0 then
exit;
S.Seek(-1, soFromCurrent);
end;
Until (MarkerTag = mkSOS) or (MarkerTag = mkNone);
Result := S.Position;
end;
Omit the first 6 Bytes after the SOS marker?
I decided to hash everything between SOS and EOI excluding the markers themselves.
Is there a fast way to locate the trailing EOI marker?
No. But this is irrelevant, since for performing a hash you have to read every single byte anyway.
How reliable is this approach?
As I said, I believe that within bounds of reason the chance that this approach will render no false positives is practically 100%. As to locating the right image: NativeJPG has been around for more than 10 years and you find very few complaints, if any they deal with decoding the image, not missing it.
In my application I offer the option to store the original filename, the EXIF DateTimeDigitized, the camera make, the GPS coordinates and MD5 hashes of the scan data (full and first 16 kB) in the UserComment field. I'm pretty confident that this will allow to lateron identify the file under most conditions (if the UserComment has remained intact).
Is there any risk that simply examining the space between SOS and EOI can fail?
Yes, for your purpose if you are only doing a checksum of the scan data. There could be multiple SOS markers and other markers in between them.

Output of Erlang bit packing

I am not able to understand bit packing in erlang.
Suppose:
R=4, G=6 and B=8
then why is the output like this:
<< R:5,G:5,B:6 >>
output: <<33,136>>.
I don't get it. Can anyone please explain?
<< R:5,G:5,B:6 >>
This record we allocate 5,5 and 6 bits, and the result is a 2-byte binary sequence. To better understand why this happens, start the reverse conversion. Transform numbers 33 and 136 in binary form:
integer_to_list(33,2).
integer_to_list(136,2).
"100001"
"10001000"
We get the following lines. Since each segment of the binary sequence is a multiple of 8, supplement the presentation of 33 zeros to the left.
L2=lists:append("00",lists:append(integer_to_list(33,2),integer_to_list(136,2))).
"0010000110001000"
Proceed to the decoding of. The third argument indicates the number of bits
V1 = list_to_integer(lists:sublist(L2,5),2).
V2 = list_to_integer(lists:sublist(L2,6,5),2).
V3 = list_to_integer(lists:sublist(L2,11,6),2).
4
6
8
Sorry for my English,hope I explained clearly.

Erlang Bit Syntax: How does it knows that it's 3 components?

I've been reading book about Erlang to evaluate if it's suitable for my project, and struble upon the bit syntax part of Learn You Some Erlang for Great Book.
Simply put, here's the code:
1> Color = 16#F09A29.
15768105
2> Pixel = <<Color:24>>.
<<240,154,41>>
What's confusing me is this: the Color variable is 24 bits, but how could Erlang knows that it has to divide the variable (in line 2) into three segments? How is the rule read?
I've tried to read the rest of the chapter, but it's getting more and more confusing me, because I don't understand how it divides the numbers. Could you please explain how the bit syntax works? How can it know that it's 3 segments, and how can it becomes <<154, 41>> when I do this:
1> Color = 16#F09A29.
15768105
2> Pixel = <<Color:16>>.
<<154,41>>
Thanks before.
Color = 16#F09A29 is an integer that can be written as 15768105 in decimal representation, as well as
00000000111100001001101000101001
in binary representation.
when you define a binary Pixel = << Color:24 >>. it just means that you say "Match the 24 less significant bits of Color with the binary Pixel". so Pixel is bounded to
111100001001101000101001,
without any split! when the shell prints it out, it does it byte per byte in decimal representation that is:
11110000 = 15*16 = 240, 10011010 = 9 * 16 + 10 = 154, 00101001 = 2 *
16 + 9 = 41 => << 240,154,41 >>
in the same way, when you define Pixel = << Color:16 >>, it takes only the 16 less significant bits and assign them to the binary =
1001101000101001,
which is printed 10011010 =
9 * 16 + 10 = 154, 00101001 = 2 * 16 + 9 = 41 => << 154,41 >>.
In the case of <> the binary equals now
100001001101000101001
( the 21 less significant bits) and when the shell prints them, it starts as usual, dividing the binary into bytes so
10000100 = 8*16 + 4 = 132, 11010001 = 13 *16 +1 = 209, as it remains only 5 bits 01001, the last chunk of data is printed 5:9 to tell us that the size of the last value is not 8 bits = 1 byte as usual, but only 5 bits =>
<< 132,209,5:9 >>.
The nice thing with binaries, is that you can "decode" them using size specification (maybe it is more clear with the example bellow).
(exec#WXFRB1824L)43> Co=16#F09A29.
15768105
(exec#WXFRB1824L)44> Pi = <<Co:24>>.
<<240,154,41>>
(exec#WXFRB1824L)45> <<R:8,V:8,B:8>> = Pi.
<<240,154,41>>
(exec#WXFRB1824L)46> R.
240
Erlang doesn't really "divide" anything. Binaries are just continuous blocks of data. It's the default human-readable representation that is printed by REPL is a comma-separated list of byte values.
It's just showing the 8-bit bytes that make up the binary. You're telling it to get 24 bits, and it's rendering them in the numeric representation (0-255) of each individual byte.

Size of the array that Fortran can handle

I have 30000 files to process each file has 80000 x 5 lines. I need to read all files and process them finding the average of each line. I have written the code to read and extract all data from the file. My code is in Fortran. There is an array of (30000 X 800000) My program could not go over (3300 X 80000). I need to add the 4th column of each file in 300 file steps, I mean 4th column of 1st file with 4th column of 301st file, 4th col of 2nd file with 4th col of 302nd file and so on .Do you think this is because of the limitation of the size of array that Fortran can handle? If so, is there any way to increase the size of the array that Fortran can handle? What about the no of files? My code looks like this:
This program runs well.
implicit double precision (a-h,o-z),integer(i-n)
dimension x(78805,5),y(78805,5),den(78805,5)
dimension b(3300,78805),bb(78805)
character*70,fn
nf = 3300 ! NUMBER OF FILES
nj = 78804 ! Number of rows in file.
ns = 300 ! No. of steps for files.
ncores = 11 ! No of Cores
c--------------------------------------------------------------------
c--------------------------------------------------------------------
!Initialization
do i = 0,nf
do j = 1, nj
x(j,1) = 0.0
y(j,2) = 0.0
den(j,4) = 0.0
c a(i,j) = 0.0
b(i,j) = 0.0
c aa(j) = 0.0
bb(j) = 0.0
end do
end do
c-------!Body program-----------------------------------------------
iout = 6 ! Output Files upto "ns" no.
DO i= 1,nf ! LOOP FOR THE NUMBER OF FILES
write(fn,10)i
open(1,file=fn)
do j=1,nj ! Loop for the no of rows in the domain
read(1,*)x(j,1),y(j,2),den(j,4)
if(i.le.ns) then
c a(i,j) = prob(j,3)
b(i,j) = den(j,4)
else
c a(i,j) = prob(j,3) + a(i-ns,j)
b(i,j) = den(j,4) + b(i-ns,j)
end if
end do
close(1)
c ----------------------------------------------------------
c -----Write Out put [Probability and density matrix]-------
c ----------------------------------------------------------
if(i.ge.(nf-ns)) then
do j = 1, nj
c aa(j) = a(i,j)/(ncores*1.0)
bb(j) = b(i,j)/(ncores*1.0)
write(iout,*) int(x(j,1)),int(y(j,2)),bb(j)
end do
close(iout)
iout = iout + 1
end if
END DO
10 format(i0,'.txt')
END
It's hard to say for sure because you haven't given all the details yet, but your problem is quite possibly that you are using a 32 bit compiler producing 32 bit executables and you are simply running out of address space.
Although your operating system supports 64 bit address space, your 32 bit process is still limited to 32 bit addresses.
You have found a limit at 3300*78805*8 which is just under 2GB and this supports my theory.
No matter what is the cause of your immediate problem, your fundamental problem is that you appear to be loading everything into memory at once. I've not closely studied your algorithm but on first inspection it seems likely that you could re-arrange it to avoid having everything in memory at once.

Resources