如何从TVIPS相机导入tif校准到DM

问题描述 投票:1回答:1

我目前正在将TVIPS相机与EM菜单软件结合使用以获取TEM图像。当我使用DigitalMicrograph(DM)分析数据(TIF文件)时,会出现一些问题,因为DM无法进行校准。我知道以前已经回答过类似的问题:how to import tif calibration into DM。但是,TIF文件的校准以X分辨率和Y分辨率(比例类型,值相同)存储,这与FEI和Zeiss不同。我试图修改how to import tif calibration into DM中的代码,但是得到的是X分辨率和Y分辨率的偏移量,而不是实际值。我不熟悉如何将TIF文件中特定偏移量的值(在这种情况下,X分辨率的偏移量是82110,Y分辨率的偏移量是82118)分配给DM。以下是我从提到的问题中修改的代码。任何建议深表感谢。提供Raw TIF file以帮助解决该问题。

// 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()
image offset tiff calibration dm-script
1个回答
0
投票

好的,根据找到的信息hereXResolutionYResolution标签的ID分别为282和283。

使用上面的模板脚本,并在示例数据上运行时仅查看提供信息的文本,就会得到:

 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

因此您可以看到,您的TIFF图像具有15个目录条目,并且确实存在ID 282和283的标签并且类型为5。哪个(再次使用源here)应为rational]类型>,就像您在修改后的脚本中所做的评论一样。该类型定义为两个长(int32)值。

因此,整个TIFF结构浏览成功,您只需要修改读取标签的部分即可。您已经对类型5进行了过滤,但是最好也对ID值进行过滤。然后,您需要读出这些值。它们不再是text

,因此原始脚本使用了不正确的命令。本质上,代替
if ( 2 == typ ) // ASCII
{
    number currentPos = fStream.StreamGetPos()
    fStream.StreamSetPos( 0, dataOffset )
    string textField = fStream.StreamReadAsText( 0, count )
    txt+=textField
    fStream.StreamSetPos( 0, currentPos )
}     

您想做的

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 )
}   

注意,ReadValueOfType实际上只是脚本中定义的自制便捷命令。底层的DM脚本技术是创建特定类型的TagGroup对象,并将其用作TagGroupReadTagDataFromStream命令中的代理。原始脚本没有类型为[[long

的值,因此您需要扩展此功能,即:else if ( type == "long" ) { tg.TagGroupSetTagAsLong( type, 0 ) tg.TagGroupReadTagDataFromStream( type, fstream, byteOrder ) tg.TagGroupGetTagAsLong( type, val ) }

我想,您可能还需要稍微重组整个脚本,因为您不需要读出这些值,然后将它们转换为文本等。因此,经过精简的调整后脚本可能看起来像这样:

// 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()

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

X Resolution:3.90786e+08 Y Resolution:3.90786e+08
我不知道应该是哪个单位。该值似乎有点高,但是...? (但是X和Y都是一样的)
© www.soinside.com 2019 - 2024. All rights reserved.