如何将 tif 校准从 TVIPS 相机导入 DM [英] How to import tif calibration from TVIPS camera into DM

查看:88
本文介绍了如何将 tif 校准从 TVIPS 相机导入 DM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用带有软件 EM 菜单的 TVIPS 相机来获取 TEM 图像.当我使用 DigitalMicrograph (DM) 分析数据(TIF 文件)时,出现了一些问题,因为校准对 DM 不可用.我知道之前已经回答过类似的问题:如何将 tif 校准导入马克.但是TIF文件的校准是以X分辨率和Y分辨率(Rational类型,数值相同)存储的,这与FEI和Zeiss不同.我尝试修改如何将tif校准导入DM,但我得到的是X分辨率和Y分辨率的偏移量,而不是实际值.我不熟悉如何将 TIF 文件中特定偏移量的值(在这种情况下,X 分辨率的偏移量为 82110,Y 分辨率为 82118)分配给 DM.下面是我从提到的问题中修改的代码.任何建议都非常感谢.提供了 原始 TIF 文件以帮助解决问题.

//流读取值的辅助方法//BmyGuest 2016 年 3 月 10 日的代码修改为读取 FEI TEM TIF//导入和校准 TVIPS Tiff 图像数字 ReadValueOfType(对象 fStream,字符串类型,数字字节顺序){数字 val = 0标签组 tg = NewTagGroup()if ( type == "bool" ){tg.TagGroupSetTagAsBoolean( type, 0 )tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsBoolean( type, val )}else if ( type == "uint16" ){tg.TagGroupSetTagAsUInt16(类型,0)tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsUInt16(类型,val)}else if ( type == "uint32" ){tg.TagGroupSetTagAsUInt32(类型,0)tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsUInt32(类型,val)}else Throw("无效的读取类型:"+type)返回值}字符串 ExtractTextFromTiff( 字符串路径){字符串 txt如果(!DoesFileExist(路径))throw("找不到文件.\n"+path)//打开流number fileID = OpenFileForReading( path )对象 fStream = NewStreamFromFileReference(fileID,1)//读取数据字节顺序.(1 = 大端,2 = Gatan 的小端)数值数字字节顺序 = 0val = fStream.ReadValueOfType("uint16", byteOrder)byteOrder = ( 0x4949 == val ) ?2 : ( 0x4D4D == val ? 1 : 0 )//Result("\n TIFF endian:"+byteOrder)//验证 TIFF 图像val = fStream.ReadValueOfType("uint16", byteOrder)if ( val != 42 ) Throw( "不是有效的 TIFF 图像")//浏览所有目录number offset = fStream.ReadValueOfType("uint32", byteOrder)while( 0 != 偏移量){fStream.StreamSetPos( 0, offset )//IFD 开始number nEntries = fStream.ReadValueOfType("uint16", byteOrder)for ( number e=0;e") + 2scaleend = scaletemp.find("</X>")scaleX = 1e7/val(scaletemp.mid(scalestart,scaleend-scalestart))}if (imported.GetStringNote("TIFF Tags:<Y unit", scaletemp)){unitY = "纳米"scalestart = scaletemp.find("\">") + 2scaleend =scaletemp.find("</Y>")scaleY = 1e7/val(scaletemp.mid(scalestart,scaleend-scalestart))}*//*if (imported.GetStringNote("TIFF Tags:Width", wStr ) ){number pos = find( wStr, " " )如果 ( -1 < pos ){scaleX = val( left(wStr,pos) )scaleX/=imported.ImageGetDimensionSize(0)unitX = right( wStr, len(wStr)-pos-1 )}}if (imported.GetStringNote("TIFF Tags:Height", hStr ) ){数字 pos = find( hStr, " " )如果 ( -1 < pos ){scaleY = val( left(hStr,pos) )scaleY/=imported.ImageGetDimensionSize(1)unitY = right( hStr, len(hStr)-pos-1 )}}*/如果 (0 < scaleX ){导入的.ImageSetDimensionScale(0,scaleX)导入的.ImageSetDimensionUnitString(0,unitX)}如果 (0 < scaleY ){导入的.ImageSetDimensionScale(1,scaleY)导入的.ImageSetDimensionUnitString(1,unitY)}结果("\n" + scaleX + "\n")结果(单位X)//导入的.ImageSetDimensionUnitString(0,unitX)}导入TIFFWithTags()

解决方案

好的,按照找到的信息此处XResolutionYResolution 标签的 ID 分别为 282 和 283.

使用上面的模板脚本并在运行示例数据时查看信息性文本输出,可以得到:

 entry # 0: ID[256] typ=4 count=1 offset @ 4096条目#1:ID[257] typ=4 count=1 offset @ 4096条目#2:ID[258] typ=3 count=1 offset @ 16条目#3:ID[259] typ=3 count=1 offset @ 1条目#4:ID[262] typ=3 count=1 offset @ 1条目 #5:ID[273] typ=4 count=4096 偏移 @ 50970条目#6:ID[278] typ=4 count=1 offset @ 1条目 #7:ID[279] typ=4 count=4096 偏移 @ 67354条目#8:ID[282] typ=5 count=1 offset @ 83738条目#9:ID[283] typ=5 count=1 offset @ 83746条目#10:ID[296] typ=3 count=1 offset @ 3条目#11:ID[339] typ=3 count=1 offset @ 1条目#12:ID[37706] typ=4 count=1 offset @ 83754条目#13:ID[37707] typ=1 count=1616 offset @ 49168条目 #14:ID[37708] typ=7 count=6312 偏移 @ 83754

因此您可以看到,您的 TIFF 图像有 15 个目录条目,并且确实存在 ID 为 282 和 283 的标签并且属于类型 5.其中(再次使用源 此处) 的类型应该是理性,正如您在修改后的脚本中所评论的那样.类型定义为两个长 (int32) 值.

那么,整体的TIFF结构浏览就成功了,你只需要调整读取标签的部分即可.您已经对类型 5 进行了过滤,但最好也对 ID 值进行额外过滤.然后你需要读出这些值.它们不再是文本,因此原始脚本使用了不正确的命令.本质上,而不是

if ( 2 == typ )//ASCII{数字 currentPos = fStream.StreamGetPos()fStream.StreamSetPos( 0, dataOffset )字符串 textField = fStream.StreamReadAsText( 0, count )txt+=文本字段fStream.StreamSetPos( 0, currentPos )}

你想做的

if ( 5 == typ )//Rational (2 int32 值){number currentPos = fStream.StreamGetPos()//记住流位置fStream.StreamSetPos( 0, dataOffset )//将Stream设置为指定的偏移值数 n1,n2if ( 282 == tag )//XResolution{n1 = fStream.ReadValueOfType( "long", byteOrder )//读长n2 = fStream.ReadValueOfType( "long", byteOrder )//继续读取下一个 longtxt += "XResoltion:" + n1 + "/" + n2}else if ( 283 == tag )//YResolution{n1 = fStream.ReadValueOfType( "long", byteOrder )n2 = fStream.ReadValueOfType( "long", byteOrder )txt += "Y分辨率:" + n1 + "/" + n2}fStream.StreamSetPos( 0, currentPos )}

请注意,ReadValueOfType 实际上只是脚本中定义的一个自制的便捷命令.底层 DM 脚本技术是创建特定类型的 TagGroup 对象,并将其用作 TagGroupReadTagDataFromStream 命令中的代理.对于 long 类型的值,原始脚本没有,所以你需要扩展这个函数,即:

else if ( type == "long" ){tg.TagGroupSetTagAsLong( type, 0 )tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsLong( type, val )}

<小时>

我想您可能还想稍微重组整个脚本,因为您不需要读出这些值然后将它们转换为文本等.因此,经过简化的调整后的脚本可能如下所示:

//流读取值的辅助方法数字 ReadValueOfType(对象 fStream,字符串类型,数字字节顺序){数字 val = 0标签组 tg = NewTagGroup()if ( type == "bool" ){tg.TagGroupSetTagAsBoolean( type, 0 )tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsBoolean( type, val )}else if ( type == "uint16" ){tg.TagGroupSetTagAsUInt16(类型,0)tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsUInt16(类型,val)}else if ( type == "uint32" ){tg.TagGroupSetTagAsUInt32(类型,0)tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsUInt32(类型,val)}else if ( type == "long" ){tg.TagGroupSetTagAsLong( type, 0 )tg.TagGroupReadTagDataFromStream(类型,fstream,byteOrder)tg.TagGroupGetTagAsLong( type, val )}else Throw("无效的读取类型:"+type)返回值}number ExtractRationalTagOfIDFromTiff(字符串路径,数字ID,数字&n1,数字&n2,数字ShowTIFFInfo){字符串 txt如果(!DoesFileExist(路径))throw("找不到文件.\n"+path)//打开流number fileID = OpenFileForReading( path )对象 fStream = NewStreamFromFileReference(fileID,1)//读取数据字节顺序.(1 = 大端,2 = Gatan 的小端)数值数字字节顺序 = 0val = fStream.ReadValueOfType("uint16", byteOrder)byteOrder = ( 0x4949 == val ) ?2 : ( 0x4D4D == val ? 1 : 0 )如果( ShowTIFFInfo )结果("\n TIFF endian:"+byteOrder)//验证 TIFF 图像val = fStream.ReadValueOfType("uint16", byteOrder)if ( val != 42 ) Throw( "不是有效的 TIFF 图像")//浏览所有目录number offset = fStream.ReadValueOfType("uint32", byteOrder)数字成功 = 0while( 0 != 偏移量){fStream.StreamSetPos( 0, offset )//IFD 开始number nEntries = fStream.ReadValueOfType("uint16", byteOrder)for ( number e=0;e" + n1 + "/" + n2 )}}offset = fStream.ReadValueOfType( "uint32", byteOrder)//根据规范,这是最后一个目录的 0000}返回成功}//导入和校准 TVIPS Tiff 图像void ImportCalibratedTVIPS_TIFF(){string path = GetApplicationDirectory("open_save",0)if (!OpenDialog(NULL,"Select TVIPS TIFF file",path, path)) exit(0)//导入数据导入的图像:= OpenImage(路径)导入的.ShowImage()//校准图像,存储为 XResolution 和 YResolution 标签数 n1,n2数字标度X = 0数字标度Y = 0if ( ExtractRationalTagOfIDFromTiff( path, 282, n1, n2, 1 ) ){scaleX = n1/n2结果("\n X 分辨率:" + Format( scaleX, "%g" ))}别的{结果(\n X 分辨率:未找到")}if ( ExtractRationalTagOfIDFromTiff( path, 283, n1, n2, 0 ) ){scaleY = n1/n2结果("\n Y 分辨率:" + Format( scaleY , "%g" ))}别的{结果("\n Y 解析:未找到")}如果 ( 0 != scaleX )导入的.ImageSetDimensionScale( 1, scaleX )如果 ( 0 != scaleY )导入的.ImageSetDimensionScale( 1, scaleY )}清除结果()导入校准TVIPS_TIFF()

在您的图像数据上运行脚本,我得到:

<块引用>

 X 分辨率:3.90786e+08是 分辨率:3.90786e+08

我不知道校准应该采用的单位,但该值似乎有点高...(特别是对于 TEM 图像)?但是,对于 X 和 Y,它与您指定的应该相同.

<小时>

顺便说一句,提供的 TIFF 图像似乎包含以下元信息:

<块引用>

ID[256] = 图片尺寸 XID[257] = 图像尺寸 YID[258] = 每样本位数ID[259] = 压缩ID[262] = 光度解释ID[273] = StripOffsetsID[278] = RowsPerStripID[279] = StripByteCountsID[282] = X分辨率ID[283] = Y分辨率ID[296] = 分辨率单位ID[339] = 样本格式ID[37706] = ????ID[37707] = ????ID[37708] = ????

从图像中读出分辨率单位给出:
分辨率单位:24576

I am currently using TVIPS camera with the software EM-menu to get TEM images. When I analyze the data (TIF files) using DigitalMicrograph (DM), some problem appears because the calibration is unavailable to DM. I am aware that a similar question has been answered before: how to import tif calibration into DM. But the calibrations of the TIF files are stored in X Resolution and Y Resolution (Rational type, the values are identical), which is different from FEI and Zeiss. I tried to modify the code in the how to import tif calibration into DM, but what I got is the offset of X Resolution and Y Resolution, instead of the real value. I am not familiar with how to assign the values of the specific offset (in this case, the offset is 82110 for X Resolution and 82118 for Y Resoltuion) in TIF files to DM. Below is the code I modified from the question noted. Any suggestion is much appreciated. Raw TIF file is provided to help address the question.

// Auxilliary method for stream-reading of values
// BmyGuest's March 10, 2016 code modified to read FEI TEM TIF
// Import and calibrate TVIPS Tiff images
number ReadValueOfType(object fStream, string type, number byteOrder)
{
    number val = 0
    TagGroup tg = NewTagGroup()
    if ( type == "bool" )
    {
        tg.TagGroupSetTagAsBoolean( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsBoolean( type, val )
    }
    else if ( type == "uint16" )
    {
        tg.TagGroupSetTagAsUInt16( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsUInt16( type, val )
    }
    else if ( type == "uint32" )
    {
        tg.TagGroupSetTagAsUInt32( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsUInt32( type, val )
    }
    else Throw("Invalid read-type:"+type)
    return val
}

string ExtractTextFromTiff( string path )
{
    string txt
    if ( !DoesFileExist(path) ) 
        Throw("File not found.\n"+path)

    // Open Stream 
    number fileID = OpenFileForReading( path )
    object fStream = NewStreamFromFileReference(fileID,1)

    // Read data byte order. (1 = big Endian, 2= little Endian for Gatan)
    number val
    number byteOrder = 0
    val = fStream.ReadValueOfType( "uint16", byteOrder )
    byteOrder = ( 0x4949 == val  ) ? 2 : ( 0x4D4D == val ? 1 : 0 )
    //Result("\n TIFF endian:"+byteOrder)

    // Verify TIFF image
    val = fStream.ReadValueOfType( "uint16", byteOrder )
    if ( val != 42 ) Throw( "Not a valid TIFF image" )

    // Browse all directories
    number offset = fStream.ReadValueOfType( "uint32", byteOrder )

    while( 0 != offset )
    {
        fStream.StreamSetPos( 0, offset ) // Start of IFD
        number nEntries = fStream.ReadValueOfType( "uint16", byteOrder )
        for ( number e=0;e<nEntries;e++)
        {
            number tag        = fStream.ReadValueOfType( "uint16", byteOrder )
            number typ        = fStream.ReadValueOfType( "uint16", byteOrder )
            number count      = fStream.ReadValueOfType( "uint32", byteOrder )
            number dataOffset = fStream.ReadValueOfType( "uint32", byteOrder )
            Result("\n entry # "+e+": ID["+tag+"]\ttyp="+typ+"\tcount="+count+"\t offset @ "+dataOffset)
            if ( 5 == typ ) // Rational
            {
                number currentPos = fStream.StreamGetPos()
                fStream.StreamSetPos( 0, dataOffset )
                string textField = fStream.StreamReadAsText( 0, count )
                txt+=textField
                fStream.StreamSetPos( 0, currentPos )
            }   
        }
        offset = fStream.ReadValueOfType( "uint32", byteOrder ) // this is 0000 for the last directory according to spec
    }

    return txt
}

String TruncWhiteSpaceBeforeAndAfter( string input )
{
    string work = input
    if ( len(work) == 0 ) return ""
    while ( " " == left(work,1) )
    {
        work = right( work, len(work) - 1 )
        if ( len(work) == 0 ) return "" 
    }
    while ( " " == right(work,1) )
    {
        work = left( work, len(work) - 1 )
        if ( len(work) == 0 ) return "" 
    }
    return work
}


// INPUT:  String with line-wise information
// OUTPUT: TagGroup
// Assumptions:  
//  - Groups are specified in a line in the format:             [GroupName]
//  - The string contains information line-wise in the format:  KeyName=Vale
TagGroup CreateTagsFromString( string input )
{
    TagGroup tg = NewTagGroup()
    string work = input

    string eoL          = "\n"
    string GroupLeadIn  = "["
    string GroupLeadOut = "]"
    string keyToValueSep= "="
    string groupName = ""

    number pos = find(work,eoL )
    while( -1 != pos )
    {
        string line = left(work,pos)
        work = right(work,len(work)-pos-len(eoL))
        number leadIn  = find(line,GroupLeadIn)
        number leadOut = find(line,GroupLeadOut)
        number sep = find(line,keyToValueSep)
        if ( ( -1 < leadIn ) && ( -1 < leadOut ) && ( leadIn < leadOut ) ) // Is it a new group? "[GROUPNAME]"
        {
            groupName = mid(line,leadIn+len(GroupLeadIn),leadOut-leadIn-len(GroupLeadOut))
            groupName = TruncWhiteSpaceBeforeAndAfter(groupName)
        }
        else if( -1 < sep )                                                 // Is it a value? "KEY=VALUE" ?
        {
            string key  = left(line,sep)
            string value= right(line,len(line)-sep-len(keyToValueSep))
            key   = TruncWhiteSpaceBeforeAndAfter(key)
            value = TruncWhiteSpaceBeforeAndAfter(value)
            string tagPath = groupName + ( "" == groupName ? "" : ":" ) + key
            tg.TagGroupSetTagAsString( tagPath, value )
        }
        pos = find(work,eoL)        
    }
    return tg
}

void ImportTIFFWithTags()
{
    string path = GetApplicationDirectory("open_save",0)
    if (!OpenDialog(NULL,"Select TIFF file",path, path)) exit(0)

    string extractedText = ExtractTextFromTiff(path)
    /*
    if ( TwoButtonDialog("Show extracted text?","Yes","No") )
        result(extractedtext)
    */

    tagGroup infoAsTags = CreateTagsFromString(extractedText )
    /*
    if ( TwoButtonDialog("Output tagstructure?","Yes","No") )
        infoAsTags.TagGroupOpenBrowserWindow(path,0)
    */
result(extractedtext)
//result(infoAsTags) 
// infoAsTags is blank. ZZ
    // Import data and add info-tags
    image imported := OpenImage(path)
    imported.ImageGetTagGroup().TagGroupSetTagAsTagGroup("TIFF Tags",infoAsTags)
    imported.ShowImage()

    // Calibrate image, if info is found
    // It seems FEI stores this value as [m] in the tags PixelHeight and PixelWidth
    // while ZEISS images contain the size of the FOV in the tags "Height" and "Width" as string including unit
    number scaleX = 0
    number scaleY = 0
    string unitX 
    string unitY
    string scaletemp
    number scalestart, scaleend
    string hStr
    string wStr
    if ( imported.GetNumberNote("TIFF Tags:XResolution", scaleX ) )
    {
        unitX = "nm"
        scaleX = 1e7/scaleX
    }
    if ( imported.GetNumberNote("TIFF Tags:YResolution", scaleY ) )
    {
        unitY = "nm"
        scaleY = 1e7/scaleY
    }
        /*
    if ( imported.GetStringNote("TIFF Tags:<X unit", scaletemp ) )
    {
        unitX = "nm"
        scalestart = scaletemp.find("\">") + 2
        scaleend = scaletemp.find("</X>")
        scaleX = 1e7/val(scaletemp.mid(scalestart,scaleend-scalestart))
    }
    if ( imported.GetStringNote("TIFF Tags:<Y unit", scaletemp ) )
    {
        unitY = "nm"
        scalestart = scaletemp.find("\">") + 2
        scaleend =scaletemp.find("</Y>")
        scaleY = 1e7/val(scaletemp.mid(scalestart,scaleend-scalestart))
    }
        */
        /*
    if ( imported.GetStringNote("TIFF Tags:Width", wStr ) )
    {
        number pos = find( wStr, " " )
        if ( -1 < pos )
        {
            scaleX = val( left(wStr,pos) )
            scaleX /= imported.ImageGetDimensionSize(0)
            unitX  = right( wStr, len(wStr)-pos-1 )
        }
    }
    if ( imported.GetStringNote("TIFF Tags:Height", hStr ) )
    {
        number pos = find( hStr, " " )
        if ( -1 < pos )
        {
            scaleY = val( left(hStr,pos) )
            scaleY /= imported.ImageGetDimensionSize(1)
            unitY  = right( hStr, len(hStr)-pos-1 )
        }
    }
        */
    if (0 < scaleX )
    {
        imported.ImageSetDimensionScale(0,scaleX)
        imported.ImageSetDimensionUnitString(0,unitX)
    }
    if (0 < scaleY )
    {
        imported.ImageSetDimensionScale(1,scaleY)
        imported.ImageSetDimensionUnitString(1,unitY)
    }

result("\n" + scaleX + "\n")
result(unitX)
// imported.ImageSetDimensionUnitString(0,unitX)
}
ImportTIFFWithTags()

解决方案

Okay, following the information found here, the XResolution and YResolution tags have the ID of 282 and 283, respectively.

Using the template script from above and just looking at the informative text output when running on your example data, one gets:

 entry # 0: ID[256] typ=4   count=1  offset @ 4096
 entry # 1: ID[257] typ=4   count=1  offset @ 4096
 entry # 2: ID[258] typ=3   count=1  offset @ 16
 entry # 3: ID[259] typ=3   count=1  offset @ 1
 entry # 4: ID[262] typ=3   count=1  offset @ 1
 entry # 5: ID[273] typ=4   count=4096   offset @ 50970
 entry # 6: ID[278] typ=4   count=1  offset @ 1
 entry # 7: ID[279] typ=4   count=4096   offset @ 67354
 entry # 8: ID[282] typ=5   count=1  offset @ 83738
 entry # 9: ID[283] typ=5   count=1  offset @ 83746
 entry # 10: ID[296]    typ=3   count=1  offset @ 3
 entry # 11: ID[339]    typ=3   count=1  offset @ 1
 entry # 12: ID[37706]  typ=4   count=1  offset @ 83754
 entry # 13: ID[37707]  typ=1   count=1616   offset @ 49168
 entry # 14: ID[37708]  typ=7   count=6312   offset @ 83754

So you can see, that your TIFF image has 15 directory entries, and that indeed tags with ID 282 and 283 exist and are of type 5. Which (again using the source here) should be of type rational, just as you've commented in the modified script. The type is defined as two long (int32) values.

So, the overall TIFF structure browsing is successful, and you just need to adapt the section of reading out the tag. You've already filtered for type 5, but it it is possibly better to additionally filter for the ID values as well. Then you need to read out the values. They are no longer text, so the original script uses the incorrect commands. Essentially, instead of

if ( 2 == typ ) // ASCII
{
    number currentPos = fStream.StreamGetPos()
    fStream.StreamSetPos( 0, dataOffset )
    string textField = fStream.StreamReadAsText( 0, count )
    txt+=textField
    fStream.StreamSetPos( 0, currentPos )
}     

your want to do

if ( 5 == typ ) // Rational (2 int32 values)
{
    number currentPos = fStream.StreamGetPos() // Remember Stream Pos
    fStream.StreamSetPos( 0, dataOffset ) // Set Stream to offset value as specified
    number n1,n2
    if ( 282 == tag )  // XResolution
    {
        n1 = fStream.ReadValueOfType( "long", byteOrder ) // Read long
        n2 = fStream.ReadValueOfType( "long", byteOrder ) // continue to read next long
        txt += "XResoltion:" + n1 + " / " + n2
    }
    else if ( 283 == tag )  // YResolution
    {
        n1 = fStream.ReadValueOfType( "long", byteOrder )
        n2 = fStream.ReadValueOfType( "long", byteOrder )
        txt += "YResoltion:" + n1 + " / " + n2
    }
    fStream.StreamSetPos( 0, currentPos )
}   

Note, that ReadValueOfType really is just a self-made convenience command defined in the script. The underlying DM-script technique is to create a TagGroup object of specific type and use that as a proxy in the TagGroupReadTagDataFromStream command. The original script didn't have that for values of type long, so you need to expand this function, i.e.:

else if ( type == "long" )
{
    tg.TagGroupSetTagAsLong( type, 0 )
    tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
    tg.TagGroupGetTagAsLong( type, val )
}


You possibly also want to restructure the whole script a bit, I guess, as you do not need to read out those values and then convert them into text etc. So a streamlined adjusted script might look something like this:

// Auxilliary method for stream-reading of values
number ReadValueOfType(object fStream, string type, number byteOrder)
{
    number val = 0
    TagGroup tg = NewTagGroup()
    if ( type == "bool" )
    {
        tg.TagGroupSetTagAsBoolean( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsBoolean( type, val )
    }
    else if ( type == "uint16" )
    {
        tg.TagGroupSetTagAsUInt16( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsUInt16( type, val )
    }
    else if ( type == "uint32" )
    {
        tg.TagGroupSetTagAsUInt32( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsUInt32( type, val )
    }
    else if ( type == "long" )
    {
        tg.TagGroupSetTagAsLong( type, 0 )
        tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) 
        tg.TagGroupGetTagAsLong( type, val )
    }
    else Throw("Invalid read-type:"+type)
    return val
}

number ExtractRationalTagOfIDFromTiff( string path, number ID, number &n1, number &n2, number ShowTIFFInfo )
{
    string txt
    if ( !DoesFileExist(path) ) 
        Throw("File not found.\n"+path)

    // Open Stream 
    number fileID = OpenFileForReading( path )
    object fStream = NewStreamFromFileReference(fileID,1)

    // Read data byte order. (1 = big Endian, 2= little Endian for Gatan)
    number val
    number byteOrder = 0
    val = fStream.ReadValueOfType( "uint16", byteOrder )
    byteOrder = ( 0x4949 == val  ) ? 2 : ( 0x4D4D == val ? 1 : 0 )
    if ( ShowTIFFInfo )
        Result("\n TIFF endian:"+byteOrder)

    // Verify TIFF image
    val = fStream.ReadValueOfType( "uint16", byteOrder )
    if ( val != 42 ) Throw( "Not a valid TIFF image" )

    // Browse all directories
    number offset = fStream.ReadValueOfType( "uint32", byteOrder )

    number success = 0
    while( 0 != offset )
    {
        fStream.StreamSetPos( 0, offset ) // Start of IFD
        number nEntries = fStream.ReadValueOfType( "uint16", byteOrder )
        for ( number e=0;e<nEntries;e++)
        {
            number tag        = fStream.ReadValueOfType( "uint16", byteOrder )
            number typ        = fStream.ReadValueOfType( "uint16", byteOrder )
            number count      = fStream.ReadValueOfType( "uint32", byteOrder )
            number dataOffset = fStream.ReadValueOfType( "uint32", byteOrder )
            if ( ShowTIFFInfo )
                Result("\n entry # "+e+": ID["+tag+"]\ttyp="+typ+"\tcount="+count+"\t offset @ "+dataOffset)

            if ( ( ID == tag )  && ( 5 == typ ) ) // Rational (2 long values)
            {               
                number currentPos = fStream.StreamGetPos()
                fStream.StreamSetPos( 0, dataOffset )
                n1 = fStream.ReadValueOfType( "long", byteOrder )
                n2 = fStream.ReadValueOfType( "long", byteOrder )
                success = 1
                fStream.StreamSetPos( 0, currentPos )

                if ( ShowTIFFInfo )
                    Result( " ==>" + n1 + " / " + n2 )
            }   
        }
        offset = fStream.ReadValueOfType( "uint32", byteOrder ) // this is 0000 for the last directory according to spec
    }

    return success
}

// Import and calibrate TVIPS Tiff images
void ImportCalibratedTVIPS_TIFF()
{
    string path = GetApplicationDirectory("open_save",0)
    if (!OpenDialog(NULL,"Select TVIPS TIFF file",path, path)) exit(0)

    // Import data 
    image imported := OpenImage(path)
    imported.ShowImage()

    // Calibrate image, stored as XResolution and YResolution tags
    number n1,n2
    number scaleX = 0
    number scaleY = 0
    if ( ExtractRationalTagOfIDFromTiff( path, 282,  n1, n2, 1 ) )
    {
        scaleX = n1/n2
        Result("\n X Resolution:" + Format( scaleX, "%g" ))
    }
    else
    {
        Result("\n X Resolution: NOT FOUND")
    }
    if ( ExtractRationalTagOfIDFromTiff( path, 283,  n1, n2, 0 ) )
    {
        scaleY = n1/n2
        Result("\n Y Resolution:" + Format( scaleY , "%g" ))
    }
    else
    {
        Result("\n Y Resolution: NOT FOUND")
    }
    if ( 0 != scaleX )
        imported.ImageSetDimensionScale( 1, scaleX )
    if ( 0 != scaleY )
        imported.ImageSetDimensionScale( 1, scaleY )
}

clearResults()
ImportCalibratedTVIPS_TIFF()

Running the script on your image data, I get:

 X Resolution:3.90786e+08
 Y Resolution:3.90786e+08

I don't know the unit that calibration is supposed to be in, but the value seems a bit high... (in particular for an TEM image)? It is, however, the same for X and Y as you've specified it should be.


As an aside, the provided TIFF images seems to contain the following meta-info:

ID[256] = Image Size X
ID[257] = Image Size Y
ID[258] = BitsPerSample
ID[259] = Compression
ID[262] = PhotometricInterpretation
ID[273] = StripOffsets
ID[278] = RowsPerStrip
ID[279] = StripByteCounts
ID[282] = XResolution
ID[283] = YResolution
ID[296] = ResolutionUnit
ID[339] = SampleFormat
ID[37706] = ????
ID[37707] = ????
ID[37708] = ????

Reading out the resolution unit from your image gives:
Resolution Unit:24576

这篇关于如何将 tif 校准从 TVIPS 相机导入 DM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆