Import Cbf Byte_offset compressed images
ilavsky
see: http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.3.3
for compression description and lots of other information. This compression is easy enough that it can be done in Igor Pro directly. Load time on 2M image on high level Macbook Pro (2013) is about 0.6 seconds. Tested on Pilatus 2M images (from PSI).
//*************************************************************************************************
// This function imports Cbf file with byte_offset compression
// see: http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.3.3
// for compression description and lots of other information.
// tested on Pilatus 2M images (from PSI)
//*************************************************************************************************
Function LoadCbfCompresedImage(PathName,FileNameToLoad, WaveNameToCreate)
string PathName, FileNameToLoad, WaveNameToCreate
//this function loads and uncompresses the Cbf byte_offset compressed file format with:
// conversions="x-CBF_BYTE_OFFSET";Content-Transfer-Encoding=BINARY;
//X-Binary-Element-Type="signed 32-bit integer";X-Binary-Element-Byte-Order=LITTLE_ENDIAN;
//Searches for start of binary data, checks how much data there should be and creates 1D wave output wave (stream)
// with uncompressed data in the current data folder.
variable SkipBytes
variable filevar
variable bufSize
variable sizeToExpect
string testLine
//locate start of the binary data
open /R/P=$(PathName) filevar as FileNameToLoad
testLine=""
testLine=PadString (testLine, 16800, 0x20)
FBinRead filevar, testLine
close filevar
SkipBytes=strsearch(testLine, "\014\032\004\325" , 0)+4 //this is string I found in test images
if(SkipBytes<5) //string not found...
SkipBytes=strsearch(testLine, "\012\026\004\213" , 0)+4 //this is per http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.2.2 what should be there. Go figure...
endif
if(SkipBytes<5)
Abort "Failed to find start of binary section in the Cbf file" //string still not found. This is problem.
endif
//Figure out now how much data are we expecting
// this header is quite messy, let's clean ti up a bit
testLine=ReplaceString("\r\n\r\n", testLine, ";")
testLine=ReplaceString("\r\n", testLine, ";")
testLine=ReplaceString("#", testLine, "")
testLine=ReplaceString(";;;;", testLine, ";")
testLine=ReplaceString(";;;", testLine, ";")
testLine=ReplaceString(";;", testLine, ";")
testLine = ReplaceString(":", testLine, "=")
sizeToExpect = NumberByKey("X-Binary-Number-of-Elements", testLine, "=", ";")
//read the data in binary free wave so we can use them here
Open /Z/R/P=$(PathName)/T="????" filevar as FileNameToLoad
if (V_flag)
close filevar
Abort "Cannot open file, something is wrong here" // could not open file
endif
FSetPos fileVar, SkipBytes //start of the image
FStatus fileVar
bufSize = V_logEOF-V_filePos //this is how mcuh data we have in the image starting at the binary data start
make/B/O/N=(bufSize)/Free BufWv //signed 1 byte wave for the data
make/O/N=(sizeToExpect)/Free ResultImage //here go teh converted singed integers. Note, they can be 8, 16, or 32 bits. 64bits not supported here.
FBinRead/B=1/F=1 fileVar, BufWv //read 1 Byte each into singed integers wave
close filevar
//and not decompress the data here
variable i, j, PixelValue, ReadValue
j=0 // j is index of the signed 1 byte wave (stream of data in)
PixelValue = 0 //value in current pixel in image.
For(i=0;i<(sizeToExpect);i+=1) //i is index for output wave
if(j>bufSize-1)
break //just in case, we run our of j. Should never happen
endif
ReadValue = BufWv[j] //read 1 Byte integer
if(ReadValue>-128) //this is useable value if +/- 127
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=1 // move to another j point
elseif(ReadValue==-128) // This is indicator that the difference did not fit in 1Byte, read 2 bytes and use those.
j+=1 // move to another point to start reading the 2 bytes
ReadValue = Conv2Bytes(BufWv[j],BufWv[j+1]) //read and convert 2 Bytes in integer
if(ReadValue>-32768) // This is useable value, use these two bytes
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=2 //move to another j point
elseif(ReadValue==-32768) // This is indicator that the difference did not fit in 2Bytes, read 4 bytes and use those.
j+=2 //move to another point to start reading the 4 bytes
ReadValue = Conv4Bytes(BufWv[j],BufWv[j+1], BufWv[j+2], BufWv[j+3]) //read and convert next 4 Bytes in integer
if(abs(ReadValue)<2147483648) //this is correct value for 32 bits
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=4 //move to another j point
else //abort, do not support 64 byte integers (no such detector exists...
abort "64 bits data are not supported"
endif
else
print "error"
endif
else
print "error"
endif
endfor
Duplicate/O ResultImage, $(WaveNameToCreate)
//create wave user requested. Note, this is 1D wave and needs to be redimensioned to 2D wave (image). Could be done here...
end
//*************************************************************************************************
//*************************************************************************************************
//*************************************************************************************************
static Function Conv2Bytes(B1,B2)
variable B1, B2
//takes two signed integer bytes, and converts them to 16 bit signed integer, little-endian, two's complement signed interpretation
//assume B1 is first byte for little-endian should be unsigned integer as it is the smaller part of the data
//assume B2 contains the larger values and sign
variable unsB1=(B1>=0) ? B1 : (256 + B1) //this should convert two's complement signed interpretation to Usigned interpretation
return unsB1 + 256*B2
end
//*************************************************************************************************
//*************************************************************************************************
static Function Conv4Bytes(B1,B2, B3, B4)
variable B1, B2, B3, B4
//takes four signed integer bytes, and converts them to 32 bit signed integer, little-endian, two's complement signed interpretation
//assume B1, B2, B3 are first bytes for little-endian should be unsigned integer as it is the smaller part of the data
//assume B4 contains the larger values and sign
variable unsB1=(B1>=0) ? B1 : (256 + B1) //this should convert two's complement signed interpretation to Usigned interpretation
variable unsB2=(B2>=0) ? B2 : (256 + B2) //this should convert two's complement signed interpretation to Usigned interpretation
variable unsB3=(B3>=0) ? B3 : (256 + B3) //this should convert two's complement signed interpretation to Usigned interpretation
return unsB1 + 256*unsB2 + 256*256*unsB3 + 256*256*256*B4
end
//*************************************************************************************************
//*************************************************************************************************
// This function imports Cbf file with byte_offset compression
// see: http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.3.3
// for compression description and lots of other information.
// tested on Pilatus 2M images (from PSI)
//*************************************************************************************************
Function LoadCbfCompresedImage(PathName,FileNameToLoad, WaveNameToCreate)
string PathName, FileNameToLoad, WaveNameToCreate
//this function loads and uncompresses the Cbf byte_offset compressed file format with:
// conversions="x-CBF_BYTE_OFFSET";Content-Transfer-Encoding=BINARY;
//X-Binary-Element-Type="signed 32-bit integer";X-Binary-Element-Byte-Order=LITTLE_ENDIAN;
//Searches for start of binary data, checks how much data there should be and creates 1D wave output wave (stream)
// with uncompressed data in the current data folder.
variable SkipBytes
variable filevar
variable bufSize
variable sizeToExpect
string testLine
//locate start of the binary data
open /R/P=$(PathName) filevar as FileNameToLoad
testLine=""
testLine=PadString (testLine, 16800, 0x20)
FBinRead filevar, testLine
close filevar
SkipBytes=strsearch(testLine, "\014\032\004\325" , 0)+4 //this is string I found in test images
if(SkipBytes<5) //string not found...
SkipBytes=strsearch(testLine, "\012\026\004\213" , 0)+4 //this is per http://www.bernstein-plus-sons.com/software/CBF/doc/CBFlib.html#3.2.2 what should be there. Go figure...
endif
if(SkipBytes<5)
Abort "Failed to find start of binary section in the Cbf file" //string still not found. This is problem.
endif
//Figure out now how much data are we expecting
// this header is quite messy, let's clean ti up a bit
testLine=ReplaceString("\r\n\r\n", testLine, ";")
testLine=ReplaceString("\r\n", testLine, ";")
testLine=ReplaceString("#", testLine, "")
testLine=ReplaceString(";;;;", testLine, ";")
testLine=ReplaceString(";;;", testLine, ";")
testLine=ReplaceString(";;", testLine, ";")
testLine = ReplaceString(":", testLine, "=")
sizeToExpect = NumberByKey("X-Binary-Number-of-Elements", testLine, "=", ";")
//read the data in binary free wave so we can use them here
Open /Z/R/P=$(PathName)/T="????" filevar as FileNameToLoad
if (V_flag)
close filevar
Abort "Cannot open file, something is wrong here" // could not open file
endif
FSetPos fileVar, SkipBytes //start of the image
FStatus fileVar
bufSize = V_logEOF-V_filePos //this is how mcuh data we have in the image starting at the binary data start
make/B/O/N=(bufSize)/Free BufWv //signed 1 byte wave for the data
make/O/N=(sizeToExpect)/Free ResultImage //here go teh converted singed integers. Note, they can be 8, 16, or 32 bits. 64bits not supported here.
FBinRead/B=1/F=1 fileVar, BufWv //read 1 Byte each into singed integers wave
close filevar
//and not decompress the data here
variable i, j, PixelValue, ReadValue
j=0 // j is index of the signed 1 byte wave (stream of data in)
PixelValue = 0 //value in current pixel in image.
For(i=0;i<(sizeToExpect);i+=1) //i is index for output wave
if(j>bufSize-1)
break //just in case, we run our of j. Should never happen
endif
ReadValue = BufWv[j] //read 1 Byte integer
if(ReadValue>-128) //this is useable value if +/- 127
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=1 // move to another j point
elseif(ReadValue==-128) // This is indicator that the difference did not fit in 1Byte, read 2 bytes and use those.
j+=1 // move to another point to start reading the 2 bytes
ReadValue = Conv2Bytes(BufWv[j],BufWv[j+1]) //read and convert 2 Bytes in integer
if(ReadValue>-32768) // This is useable value, use these two bytes
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=2 //move to another j point
elseif(ReadValue==-32768) // This is indicator that the difference did not fit in 2Bytes, read 4 bytes and use those.
j+=2 //move to another point to start reading the 4 bytes
ReadValue = Conv4Bytes(BufWv[j],BufWv[j+1], BufWv[j+2], BufWv[j+3]) //read and convert next 4 Bytes in integer
if(abs(ReadValue)<2147483648) //this is correct value for 32 bits
PixelValue += ReadValue //add to prior pixel value
ResultImage[i] = PixelValue //store in output stream
j+=4 //move to another j point
else //abort, do not support 64 byte integers (no such detector exists...
abort "64 bits data are not supported"
endif
else
print "error"
endif
else
print "error"
endif
endfor
Duplicate/O ResultImage, $(WaveNameToCreate)
//create wave user requested. Note, this is 1D wave and needs to be redimensioned to 2D wave (image). Could be done here...
end
//*************************************************************************************************
//*************************************************************************************************
//*************************************************************************************************
static Function Conv2Bytes(B1,B2)
variable B1, B2
//takes two signed integer bytes, and converts them to 16 bit signed integer, little-endian, two's complement signed interpretation
//assume B1 is first byte for little-endian should be unsigned integer as it is the smaller part of the data
//assume B2 contains the larger values and sign
variable unsB1=(B1>=0) ? B1 : (256 + B1) //this should convert two's complement signed interpretation to Usigned interpretation
return unsB1 + 256*B2
end
//*************************************************************************************************
//*************************************************************************************************
static Function Conv4Bytes(B1,B2, B3, B4)
variable B1, B2, B3, B4
//takes four signed integer bytes, and converts them to 32 bit signed integer, little-endian, two's complement signed interpretation
//assume B1, B2, B3 are first bytes for little-endian should be unsigned integer as it is the smaller part of the data
//assume B4 contains the larger values and sign
variable unsB1=(B1>=0) ? B1 : (256 + B1) //this should convert two's complement signed interpretation to Usigned interpretation
variable unsB2=(B2>=0) ? B2 : (256 + B2) //this should convert two's complement signed interpretation to Usigned interpretation
variable unsB3=(B3>=0) ? B3 : (256 + B3) //this should convert two's complement signed interpretation to Usigned interpretation
return unsB1 + 256*unsB2 + 256*256*unsB3 + 256*256*256*B4
end
//*************************************************************************************************
//*************************************************************************************************
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More