如何将 TVIPS 摄像头的 tif 校准导入 DM

Posted

技术标签:

【中文标题】如何将 TVIPS 摄像头的 tif 校准导入 DM【英文标题】:How to import tif calibration from TVIPS camera into DM 【发布时间】:2019-11-16 15:21:30 【问题描述】:

我目前正在使用带有软件 EM-menu 的 TVIPS 摄像头来获取 TEM 图像。当我使用 DigitalMicrograph (DM) 分析数据(TIF 文件)时,出现了一些问题,因为 DM 无法进行校准。我知道之前已经回答了类似的问题:how to import tif calibration into DM。但是TIF文件的标定是存储在X Resolution和Y Resolution(Rational类型,数值相同)中,与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()

【问题讨论】:

相关回答***.com/a/66974315/1302888 【参考方案1】:

好的,根据here找到的信息,XResolutionYResolution标签的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)应该是类型 理性,正如您在修改后的脚本中所评论的那样。该类型定义为两个长 (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

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


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

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] = ????

从图像中读出分辨率单位会得到:Resolution Unit:24576

【讨论】:

非常感谢您的快速回复和宝贵的信息。我稍微修改了你的脚本,它现在可以工作了。【参考方案2】:

感谢 BmyGuest,下面的脚本现在可以运行了。

我检查了 TIF 文件中的 X 分辨率(Y 分辨率)和 DM 中的比例(nm)之间的关系:比例 = 1e7 / X 分辨率。我相应地修改了 BmyGuest 的脚本并添加了单位“nm”。现在校准完美,与 ImageJ 的结果相匹配。

// Auxilliary method for stream-reading of values
// Modifed from BmyGuest's, 2019.11.17
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
    number PixelWidth = 0
    number PixelHeight = 0
    if ( ExtractRationalTagOfIDFromTiff( path, 282,  n1, n2, 1 ) )
    
        scaleX = n1/n2
        Pixelwidth =1e7/scaleX
        Result("\n X Resolution:" + Format( scaleX, "%g" ))
        Result("\n Pixel width:" + Format( PixelWidth, "%g" )+ " nm")

    
    else
    
        Result("\n X Resolution: NOT FOUND")
    
    if ( ExtractRationalTagOfIDFromTiff( path, 283,  n1, n2, 0 ) )
    
        scaleY = n1/n2
        PixelHeight =1e7/scaleY
        Result("\n Y Resolution:" + Format( scaleY , "%g" ))
        Result("\n Pixel height:" + Format( PixelWidth, "%g" )+ " nm")
    
    else
    
        Result("\n Y Resolution: NOT FOUND")
    
    if ( 0 != scaleX )
        imported.ImageSetDimensionScale( 0, PixelWidth )
        imported.ImageSetDimensionUnitString( 0, "nm" )
    if ( 0 != scaleY )
        imported.ImageSetDimensionScale( 1, PixelHeight )
        imported.ImageSetDimensionUnitString( 1, "nm" )


clearResults()
ImportCalibratedTVIPS_TIFF()

【讨论】:

以上是关于如何将 TVIPS 摄像头的 tif 校准导入 DM的主要内容,如果未能解决你的问题,请参考以下文章

如何检查多个文件夹并删除具有唯一文件名的任何文件?

使用数码相机进行相机校准

双目标定

使用opencv进行多摄像头校准:两个摄像头相互面对

是否必须校准相机才能与 StereoBM 一起使用?

在实时视频捕获应用程序中使用相机校准参数