自迁移出 MediaWiki 以来,本页内容尚未经过审查。如果您愿意帮忙,请查看帮助指南!
|
|
|
| 来源 |
将 3View 蒙太奇导入 TrakEM2:概述
该插件的目的是创建一个文本文件,其中包含来自 Gatan’s 3View 蒙太奇图像堆栈的文件列表。然后可以使用该文本文件将所有图像按原样存储在原始目录中自动导入 TrakEM2。
在蒙太奇模式下,Gatan’s DigitalMicrograph软件将每个图块的文件保存在各自的目录中。以具有10个z片的2x3蒙太奇为例,在作业结束时将创建6个文件夹,每个文件夹有10个文件。这些文件夹按照Montage_xxx模式命名,其中xxx是一个数字(从0000开始)。
该插件将读取文件夹内的所有Gatan文件(.dm3),并以适合直接从原始目录导入TrakEM2的格式在文本文档(.txt)中创建文件列表。当然,您可以将父目录从激烈的计算机移动到任何合适的位置。该插件尝试从文件中读取元数据,以自动蒙太奇配置(x和y包含多少个图),并根据大小图像和重叠提供图像定位的粗坐标。此信息为图像大致保留在TrakEM2工作完成区域中的位置,更快地下一步(图像拼接)。
安装说明
第 Jython plugin installation rules 条适用。您必须 download 放置 3view_import_list.py 和 MakeImportList4TrakEM2.py 一起复制到同一目录中。第三个文件 TrakEM2_import_list.py 是可选的(参见下面的第 3 点)。如果您想从自己的代码调用脚本,则只需要第二个文件。仅作为建议,您可以按照以下步骤操作:
1.将3view_import_list.py和MakeImportList4TrakEM2.py复制到斐济目录...\Fiji.app\plugins\Scripts\Plugins\Utilities中。
- 要使插件选择出现在菜单中,您可以Help › Refresh Menus、Plugins › Scripting › Refresh Jython Scripts或重新启动斐济。然后菜单项“3View import list”将出现在Import › Import from text file…下(第一个Utilities文件夹…)
- 另外:如果您需要使用除文件类型.dm3、其他目录名称之外的其他设置或更改最终文本文件的名称,您可以将
TrakEM2_import_list.py复制到同一文件夹,从同一菜单位置选择具有此名称的插件。
如何使用
1.从斐济菜单中选择插件后:
2、选择所有Montage_xxx文件夹所在的父目录;
3.可能,插件会尝试生成最终的文本文件,而需要用户进一步输入,使用图像文件中的元数据计算图块配置和重叠,此功能目前无法运行。但请参见下面的粗体文字。
4.斐济日志和斐济窗口中的状态消息将显示当前发生的情况的阶段信息。整个操作底座几干预。您可以通过网络连接使用此插件,但实际的导入作业(下面的步骤6)应使用放置在本地硬盘驱动器中的文件或通过极快的数据连接来完成,以获得最佳性能。
- 文本文件将保存在用户最初选择的相同目录中。
6.实际使用文本文件,请右键单击 TrakEM2 工作区(黑色区域)中的各个位置,然后选择§§§4§§选择文件后,您会看到一个窗口,询问一些选项。这些应保留默认值,确保“列间隔符”指示“制表符”。然后 TrakEM2 询问要导入文件的位置,您应该提供所有
Montage_xxx父目录所在的文件夹 - 当您在运行插件时选择几个目录。然后TrakEM2 将导入列表中的每个文件并创建小地图以进行快速加载/缩放。这可能需要一段时间。
小字:允许的内容和已知的限制
- 目前无法从元数据读取坐标版本。这意味着用户将始终被要求提供图块配置和重叠。
2.您可以在蒙太奇目录的相同级别拥有其他目录(例如 TrakEM2 完整数据目录)。此外,您可以创建的那些蒙太奇目录的任何子目录内容及其将被忽略。但是,父目录中的目录不应遵循相同的
Montage_xxx模式,而实际上不属于数据集的一部分。 3.您可以将其他文件格式与.dm3文件一起使用,这些文件格式将被忽略。 4.蒙太奇目录中的所有.dm3文件都将添加到列表中。 5.插件不检查/关心每个目录中的文件数量是否相同;强制要求是第一个、第二个和最后一个目录中至少有一个文件。 6.如果由于某种原因需要更改目录的编号,只需确保它们保持相同的顺序即可。非连续编号不是问题;目录将简单地按升序读取。 7.无法读取阶段位置值或计算出的图块配置与检测到的文件夹数量如果不匹配,则插件将询问用户 x 和 y 图块数量以及重叠百分比。 8.您计划在采集目录中或修改文件,例如,您因为需要合并采集的作业,则必须修改文件名的最后4位数字与堆栈中图像添加的z位置匹配。如果没有从元数据中读取Z位置,以适应这种情况。 Tip: doing this by hand is tedious and error prone; there are however free software applications that can automate this file renaming job easily. 9.您运行稍作的版本“TrakEM2导入列表”,选择可以.dm3以外的其他文件格式、选择其他修改文件夹模式(这些是Regular Expression模式)或文本最终文件的不同文件名。,图像文件仍然需要具有单位相同的舞台坐标和像素尺寸(大小)的元数据,方便您自动计算工作。目前我没有任何“非自动”版本可以供用户获取所有序列的信息。 Note 1: The numbering in the files must have 4 digits. I may fix this in the future.
Note 2: The file format input is case sensitive: ‘.tif’ is not the same as ‘.TIF’ - 要从其他脚本自动化或调用插件,您需要提供上一点中提到的详细信息。有关示例,请参阅文件
TrakEM2_import_list.py。 11.插件假设所有文件具有相同的像素尺寸(大小)。 - 插件假设像素是适配器并且x和y上的重叠。
13.插件应该独立于操作系统(Linux、Windows、Mac)工作。感谢您的反馈。
14.由于3View阶段中FoV和X/Y轴之间的角度为45°,如果提供接近零的角度(即从另一个系统/阶段)获取行为的数据集,此插件可能会失败。由于第7点中指出的,从任何阶段位置元数据中切断文件将是规避此限制的一种方法。
15.作为奖励,您还可以使用此插件为单个位置 z 堆栈创建导入文件;在这种情况下,图像来自哪里并不重要,因为需要蒙太奇计算。
Note 1: selecting the ‘main’ plugin for a situation like this using .dm3 files, you still must have the folder name match the pattern
Montage_xxx.
Note 2: to create a single-position file list of images in another file format (.tif files for example) using the ‘alternate’ ‘TrakEM2 import list’ plugin, you don’t need to modify the directory name where you keep the files in the options dialog. You can just submit this name in the ‘Directory RegExp’ field (no Regular Expression special patterns are necessary). However, you must choose its parent directory in the ‘Choose directory’ dialog, as you would in every case. As an example, if you have your image files inC:\data\images\stack1, you should select the directoryC:\data\images\and submit ‘stack1’ as the ‘Directory RegExp’ value in the ‘Import parameters’ dialog. ##代码3view_import_list.py
import sys
from ij import IJ
from ij.io import DirectoryChooser
from java.lang.System import getProperty
sys.path.append(getProperty("fiji.dir") + "/plugins/Scripts/plugins/Utilities")
from MakeImportList4TrakEM2 import make_list
dc = DirectoryChooser('Select 3View dataset base directory')
folder = dc.getDirectory()
if folder is None:
IJ.log('User canceled the folder selection!')
else:
dir_RegExp = 'Montage_\d{3}'
list_filename = 'TrakEM2_import.txt'
filetype = '.dm3'
how_many = make_list(filetype, folder, dir_RegExp, list_filename)
IJ.showProgress(1,1) #in case there is an error, the progress bar still disappears
IJ.showStatus('Completed. Files added to import list: ' + str(how_many))
TrakEM2_import_list.py
import sys
from ij import IJ
from ij.io import DirectoryChooser
from ij.gui import GenericDialog
from java.lang.System import getProperty
sys.path.append(getProperty("fiji.dir") + "/plugins/Scripts/plugins/Utilities")
from MakeImportList4TrakEM2 import make_list
def getParameters():
gd = GenericDialog("Import parameters")
gd.addStringField("Import list name", "TrakEM2_import.txt")
gd.addStringField("Directory RegExp", "Montage_\d{3}")
gd.addStringField("Filetype filter", ".tif")
gd.showDialog()
#
if gd.wasCanceled():
print "User canceled dialog!"
return
# Read out the options
list_name = gd.getNextString()
reg_exp = gd.getNextString()
ftype = gd.getNextString()
return list_name, reg_exp, ftype
dc = DirectoryChooser('Select 3View dataset base directory')
folder2 = dc.getDirectory()
if folder2 is None:
IJ.log('User canceled the folder selection!')
else:
param = getParameters()
if param is not None:
list_name, reg_exp, ftype = param
how_many = make_list(ftype, folder2, reg_exp, list_name)
IJ.showProgress(1,1) #in case there is an error, the progress bar still disappears
IJ.showStatus('Completed. Files added to import list: ' + str(how_many))
MakeImportList4TrakEM2.py
import os, re, math, sys
from ij import IJ
from ij.gui import GenericDialog
from loci.formats import ImageReader, MetadataTools
def read_meta(filen2):
rf = ImageReader()
meta = MetadataTools.createOMEXMLMetadata()
rf.setMetadataStore(meta)
rf.setId(filen2)
# get stage position:
planeCount = meta.getPlaneCount(0)
for p in range(planeCount):
posX = float(str(meta.getPlanePositionX(0, p)))
posY = float(str(meta.getPlanePositionY(0, p)))
try:
posX, posY
except NameError:
posX = posY = 0
return rf, meta, posX, posY
def getOptions(X, Y, Ol, mnts):
IJ.showStatus('Asking user for input...')
gd = GenericDialog("Montage configuration")
gd.addNumericField("Number of tiles in X", X, 0) # show 0 decimals
gd.addNumericField("Number of tiles in Y", Y, 0) # show 0 decimals
gd.addNumericField("Overlap (%)", Ol, 1) # show 1 decimal
gd.showDialog()
if gd.wasCanceled():
IJ.log('User canceled dialog. Text file not created')
return
# Read the input into variables
pos_x = int(gd.getNextNumber())
pos_y = int(gd.getNextNumber())
if (pos_x * pos_y) != mnts:
IJ.log('The configuration you provided (' + str(pos_x) + 'X by ' + str(pos_y) + 'Y) and number of detected directories (' + str(mnts) + ') do not match.\nText file not created.')
IJ.showMessage('The configuration you provided and number of detected directories do not match.\nText file not created.')
return
overlp = gd.getNextNumber()
return pos_x, pos_y, overlp
def make_list(filetype, folder, dir_RegExp, list_filename):
IJ.log('--- Begin creating 3View file list for TrakEM2 import ---')
IJ.showStatus('Starting...')
x_now = y_now = counter1 = 0
import_list = ''
try:
f = open(folder + list_filename, 'w') # Save the text file for importing in same root folder, auto overwrite
except IOError:
IJ.log('Error: can\'t create file in selected directory')
return
else:
IJ.showStatus('Reading directories...')
subdirs = sorted(os.walk(folder).next()[1]) # create list with the contents of the directory, selecting only 1st level directories and sorting them ascending. Sorting is fundamental for correctly reading of stage position values and for correct positioning os the tiles in each montage
subdirs[:] = [sd for sd in subdirs if re.match(dir_RegExp, sd, flags=0)] # filter the dirs that match the RegExp. For 3View the name is 'Montage_xxx'. This allows for some flexibility: users can have other folders together with the stack folders such as TrakEM2 minimaps folder
montage_size = len(subdirs) # count how many dirs were selected - to calculate configuration of montage and progress reporting
if montage_size == 0:
IJ.log('Error: No directories found matching RegExp pattern \'' + dir_RegExp + '\' in ' + folder)
return
try:
scnd_dir = subdirs[1] # check if there is more than one folder, setting at the same time the variable for the second (folder in the list) index position - [1]
except IndexError:
# since there is only one folder, move on with settings to create a file list for just one position. The whole else: part below will be skipped
IJ.log('Only one directory detected. Creating file list for single position z-stack')
x_coord = y_coord = 1
x_now = y_now = x_img_size = y_img_size = overlap = 0
else:
IJ.log(str(montage_size) + ' matching directories found in ' + folder)
# get values for calc of montage configuration and overlap
files_2nd_dir = os.listdir(os.path.join(folder,scnd_dir))
files_2nd_dir[:] = [fn1 for fn1 in files_2nd_dir if os.path.isfile(os.path.join(folder,scnd_dir,fn1))and fn1.endswith(filetype)]
IJ.showStatus('Reading stage coordinates 1/3...')
try: # stop if no files are found in the 2nd folder:
r1, meta1, pos2_Xstage, pos2_Ystage = read_meta(os.path.join(folder, scnd_dir, files_2nd_dir[0])) # pick a file from the second folder to read metadata
r1.close()
except IndexError:
IJ.log('Error: the 2nd directory in the list does not contain any files of type ' + filetype)
return
last_dir = subdirs[-1] # pick one file from the last folder to read metadata
files_lastdir = os.listdir(os.path.join(folder,last_dir))
files_lastdir[:] = [fn2 for fn2 in files_lastdir if os.path.isfile(os.path.join(folder,last_dir,fn2))and fn2.endswith(filetype)]
IJ.showStatus('Reading stage coordinates 2/3...')
try:
r2, meta2, posLast_Xstage, posLast_Ystage = read_meta(os.path.join(folder, last_dir, files_lastdir[0]))
r2.close()
except IndexError:
IJ.log('Error: the last directory in the list does not contain any files of type ' + filetype)
return
for d, dirs in enumerate(subdirs):
filenames = sorted(os.listdir(os.path.join(folder,dirs))) # the sorting is just to try and hide the darker, overlap areas of the image to be in front when displaying the montage in TrakEM2. This is probably not necessary if some contrast homogenization is performed after importing
filenames[:] = [fn3 for fn3 in filenames if os.path.isfile(os.path.join(folder,dirs,fn3))and fn3.endswith(filetype)] # make sure there are no dirs ending in desired filetype (one never knows~) and filter for the filetype
filenames_size = len(filenames) # for progress bar only
for p, filen in enumerate(filenames):
try: # check if metadata was read already and extract metadata info from the 1st file on the list - if it was not, get this info by executing the except clause. This makes the metadata routine run only once in the beginning. Being nested inside the else: stm above, metadata is only read if it's not a single position acquisition - in this case it wouldn't be necessary. Also, complete calc of overlap and montage configuration
overlap
except NameError:
IJ.showStatus('Reading stage coordinates 3/3...')
try:
r3, meta3, pos1_Xstage, pos1_Ystage = read_meta(os.path.join(folder, dirs, filen))
except IndexError:
IJ.log('Error: the first directory in the list does not contain any files of type ' + filetype)
r3.close()
return
IJ.showStatus('Reading more metadata...')
x_img_size = r3.getSizeX()
y_img_size = r3.getSizeY()
r3.close()
pSizeX = float(str(meta3.getPixelsPhysicalSizeX(0))) # getPixelsPhysicalSizeX(0) it's an object, and needs both str and float before it can be used in calculations
pSizeY = float(str(meta3.getPixelsPhysicalSizeY(0)))
IJ.log('Read image size ' + str(x_img_size) + ' X ' + str(y_img_size))
IJ.log('Read pixel dimensions ' + str(round(pSizeX * 1000, 1)) + ' X ' + str(round(pSizeY * 1000, 1)) + ' nm')
# next 2 are needed to calculate overlap:
deltaX1 = pos2_Xstage - pos1_Xstage
deltaY1 = pos2_Ystage - pos1_Ystage #only for single column montage
# if deltaX1=0 then something went wrong with the metadata reading and the user has to manually input the coordinate values. note that for the case of a single folder deltaX1 would theoretically also be =0 (but this code doesn't even allow for that, since it requires at least 2 folders for the calculation)
#(or close to zero - most likely in a case of 'multiple ROI' acquisition (there would be stage movement) instead of 'montage') but that situation was already covered above and at that step the overlap var was initiated; in that situation this whole except NameError: is skipped and no deltaX1 calc is ever performed
if deltaX1 == 0:
IJ.log('Warning: Could not read stage position from files. Asking for user input')
options1 = getOptions(0, 0, 0, montage_size)
if options1 is None:
overlap = 0 # to prevent "UnboundLocalError: local variable 'overlap' referenced before assignment". Rrom http://docs.python.org/2/reference/simple_stmts.html : "When return passes control out of a try statement with a finally clause, that finally clause is executed before really leaving the function."
return
x_coord, y_coord, ovlap1 = options1
overlap = 1 - (ovlap1 / 100)
IJ.log('User provided montage configuration ' + str(x_coord) + 'X by ' + str(y_coord) + 'Y and ' + str(ovlap1) + '% overlap')
# if deltaX1 > 0 means the second position(dir) is in the X axis(to the right instead of down); otherwise the next folder is in the Y axis and therefore a single column montage# this is because the stage is at an angle (45 without scan rotation) with the montage axis This check is not robust enough to accomodate a 0 deg stage (it may not work with images acquired without a significant axis angle in relation to the images, ie, not with 3View)# also: assumes the coordinate system is always the same in relation to the images; if there are invertions, then this check needs to be reworked
elif deltaX1 > 0:
IJ.showStatus('Calculating parameters...')
overlap = round(math.hypot(deltaX1, deltaY1) / float(x_img_size) * pSizeX, 1) # assumes overlap and pixel size to be the same in x and y
IJ.log('Calculated overlap: ' + str((1 - round(overlap, 1)) * 100) + '%')
# calc max stage movement distance measured between 1st and last montage 'positions'
deltaX2 = posLast_Xstage-pos1_Xstage
deltaY2 = posLast_Ystage-pos1_Ystage
# then to 'convert' the stage distance into 'real' montage span distances some more trig needs to be applied because the 45 deg rotation of the axis relative to the image acquisition (FoV)
bigger_angle = math.atan(deltaY2 / deltaX2) # arc tangent in radians
smaller_angle = bigger_angle - math.radians(45)
# hypotenuse of the rectangle formed between the 1st and the last stage position
montage_hyp = math.hypot(deltaX2, deltaY2)
# it's a rectangle, the hypotenuse angle will vary. Calcs for x length is 'adjacent side', so cos(x) and calcs for y is 'opposite side', so sin(x)
montage_Xlenght = round(math.cos(smaller_angle) * montage_hyp, 3)
montage_Yheight = round(math.sin(smaller_angle) * montage_hyp, 3)
# and finally calculate the number of tiles in the x and y axis, assuming stage movement is reasonably accurate
x_coord = int(round(montage_Xlenght / (x_img_size * overlap), 0)) + 1
y_coord = int(round(montage_Yheight / (y_img_size * overlap), 0)) + 1
IJ.log('Montage configuration calculated to be ' + str(x_coord) + 'X by ' + str(y_coord) + 'Y')
if (x_coord * y_coord) != montage_size:
# create dialog to get user input because the calculated configuration doesn't match the number of folders
IJ.log('Warning: Calculated montage configuration and total number of folders found do not match')
options2 = getOptions(x_coord, y_coord, overlap, montage_size)
if options2 is None:
overlap = 0 # to prevent UnboundLocalError: local variable 'overlap' referenced before assignment
return
x_coord, y_coord, ovlap2 = options2
overlap = 1 - (ovlap2 / 100)
IJ.log('User provided montage configuration ' + str(x_coord) + 'X by ' + str(y_coord) + 'Y and ' + str(ovlap2) + '% overlap')
else:
# The alternative is a single column montage and for that case the calculations are more simple
IJ.showStatus('Calculating parameters...')
overlap = round(math.hypot(deltaX1, deltaY1) / (y_img_size * pSizeY), 1)
IJ.log('Calculated overlap: ' + str((1 - overlap) * 100) + '%')
x_coord = 1
y_coord = montage_size
IJ.log('Montage configuration should be ' + str(x_coord) + 'X by ' + str(y_coord) + 'Y')
finally:
IJ.showStatus('Adding files to import list...')
reg_expr4_zval = '.+(\\d{4})\\' + filetype + '$' # RegExp to get the z position (number) from the filename
find_zval = re.match(reg_expr4_zval, filen, flags=0) # get the last 4 digits from the filename
z_now = int(find_zval.group(1)) # should be the z order/position of the file in the stack. int() removes leading zeros
# append the file info to the list ASCII 13=Enter ; 92=\ ; 9=TAB
import_list = os.path.join(dirs, filen) + chr(9) + str(int(x_now*x_img_size*overlap)) + chr(9) + str(int(y_now*y_img_size*overlap)) + chr(9) + str(z_now) + chr(13) + import_list
counter1 += 1
progress = int(((((p + 1)/ float(filenames_size)) + d) * 100))
IJ.showProgress(progress, montage_size * 100)
x_now += 1 # gone through the contents of one folder; before moving to the next, move the montage position counters
if (x_now == x_coord): # if all x positions in a row are recorded, reset x and move to next row (y position)
y_now += 1
x_now = 0
f.write(import_list.strip())
f.close()
IJ.log(str(counter1) + ' entries were written to the file ' + f.name)
return counter1
联系方式
非常欢迎所有意见、问题或建议。请发送电子邮件至 nuno.dias(emez.ethz.ch)或 ngdias(ibmc.up.pt)。
##致谢
- Curtis Rueden
- This page 由阿尔伯特·卡多纳 (Albert Cardona) 编写
- This other page 由阿尔伯特·卡多纳 (Albert Cardona) 编写
- 很多人在互联网上提出并回复有关Python的问题
另请参阅
- Importing list文本文件应该思考子。