二维脑片配准插件开发
具体步骤
在Eclipse中配置Maven环境 Window → Preferences → Maven → Installations → Add → 找到Maven安装路径
创建Maven项目 File → New → Other → Maven Project → Create a simple project
编写组件并合理布局(FlowLayout和BoxLayout结合)
编写选择按钮 和确认按钮 的触发事件
编写降采样按钮 、配准 、合并通道 和保存 的触发事件
整理目录结构:
input
文件夹存放原始脑片,output
文件夹存放配准合并完成的图片,params
文件夹存放配准参数,registration
文件夹存放中间处理过程得到的图片以及配准文件Run as Maven build
生成jar包
效果展示
问题记录
- 为什么编写了按钮的触发事件后,运行程序时点击按钮没有反应?
答:需要调用event()函数! - 想获取tempImage.tif中某一张图片,但是总报错说out of range
答:不能在使用tempStack.getProcessor(tempIndex)
之前使用tempImage.close()
,但手动关闭是不影响的。 - Java中string转int
1
int tempIndex = Integer.valueOf(tempNum.getText());
- 运行命令行输出的内容如何动态打印到JTextArea
- 如何获取
resources
下的文件?ChatGPT:1
this.getClass().getClassLoader().getResource("tempImage.tif").getPath()
当你在执行命令行时,使用Runtime.getRuntime().exec()方法或ProcessBuilder类的start()方法会创建一个新的进程来运行命令。这个新的进程与你的Java程序是独立的,它在操作系统中运行,并与你的Java程序并行执行。这意味着在主线程中执行命令行时,主线程将会被阻塞(即暂停执行),直到命令行执行完毕。
如果命令行的输出量较大,或者命令行执行时间较长,主线程被阻塞的时间会很长,可能导致你的界面无响应,因为界面的更新和事件处理通常也是在主线程中进行的。
通过创建一个新的线程来执行命令行,我们实现了并发执行。这意味着在主线程中调用registration()方法时,新线程会被启动,然后在新线程中执行命令行,而主线程会继续执行接下来的代码,保持界面的响应。这样,即使命令行执行时间很长,主线程也不会被阻塞,界面仍然可以响应用户的交互。
在新线程中,我们使用BufferedReader来读取命令行的输出流,并实时将输出内容追加到JTextArea中,通过调用pluginMain.logMessage.repaint()来强制刷新文本区域,使得输出内容在JTextArea中动态显示。
使用新线程来执行耗时操作,如命令行执行、网络请求等,是一种常见的做法,它能够有效地保持界面的响应性,提升用户体验。在Java中,你可以通过创建Thread对象,或者使用ExecutorService等高级并发工具来管理线程的执行。
- 如何获取
- 调用transform方法时,JTextArea中的内容为什么没有更新
ChatGPT:
根据你提供的Registration类中的registration()和transform()方法,我注意到在调用transform()方法之前,你通过创建线程来执行了elastix命令。在这种情况下,可能出现elastix命令尚未执行完成,就开始执行transform()方法。由于两个命令都是通过独立的线程执行的,所以在elastix命令执行期间,可能会同时执行transform()方法。因此,你可能会看到命令输出结果交错显示,甚至transform()方法的输出可能会被elastix命令的输出覆盖。
为了确保elastix命令执行完毕后再执行transform()方法,你可以在registration()方法中等待elastix命令执行完成后再调用transform()方法。可以使用Process对象的waitFor()方法,该方法会阻塞当前线程,直到命令执行完成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public void registration() {
String elastixUrl = "D:/Desktop/brainPro/elastix";
String brainUrl = "D:/Desktop/brainPro/registration/resizedImage.tif";
String regisTempUrl = "D:/Desktop/brainPro/registration/regisTemp.tif";
String cmd = elastixUrl + " -f " + brainUrl + " -m " + regisTempUrl + " -out " + output_1 + " -p " + GlobalPath+"params/para-Standard_bspline.txt";
new Thread(() -> {
try {
Process ps = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
pluginMain.logMessage.append(line + "\n");
pluginMain.logMessage.setCaretPosition(pluginMain.logMessage.getDocument().getLength()); // 滚动到文本末尾
pluginMain.logMessage.repaint(); // 强制刷新文本区域
}
ps.waitFor(); // 等待命令执行完成
transform(); // 在elastix命令执行完成后调用transform()方法
} catch (Exception e) {
e.printStackTrace();
}
}).start();
} - 如何确定配准全部完成后再执行接下来的程序?
ChatGPT:
当我们在Java中定义一个接口,实际上是在创建一种契约,定义了一组方法的签名,而不包含方法的实现。其他类可以实现这个接口并提供实际的方法实现,从而达到对某种功能或行为的规范和约束。在这里,我们要使用接口来实现回调机制,回调机制是一种异步通信的方式,允许一个对象在特定事件发生时通知另一个对象执行特定的操作。首先,我们定义一个接口RegistrationCallback,其中包含方法:onTransformCompleted()。
这个接口中并没有实现任何方法,只是规定了这两个方法的签名。现在我们将在Registration类中使用这个接口。在Registration类中添加一个私有成员变量callback,用于保存实现了RegistrationCallback接口的对象。
在registration()方法中,我们可以接收一个实现了RegistrationCallback接口的对象,并将它保存在callback变量中。
在transform()方法中的合适时机调用回调方法。在onTransformFinished()方法中,我们会首先检查callback是否为null,如果不为null,则调用回调对象的对应方法。
现在,当我们在pluginMain类的registrationBtn监听器中调用Registration类的registration()方法时,我们可以传递一个实现了RegistrationCallback接口的对象。这样,在配准和转换完成后,Registration类会调用回调方法,并在回调方法中执行相应的操作。
这样可以确保在配准和转换都完成后再执行相关操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87// 新建一个接口RegistrationCallback.java
public interface RegistrationCallback {
void onTransformCompleted();
}
// Registration.java
public class Registration {
private RegistrationCallback callback;
public String GlobalPath = "D:/Desktop/brainPro/";
public String output_1= "D:/Desktop/brainPro/registration/temp1";
public void registration(RegistrationCallback callback) {
this.callback = callback;
String elastixUrl = "D:/Desktop/brainPro/elastix";
String brainUrl = "D:/Desktop/brainPro/registration/resizedImage.tif";
String regisTempUrl = "D:/Desktop/brainPro/registration/regisTemp.tif";
String cmd = elastixUrl + " -f " + brainUrl + " -m " + regisTempUrl + " -out " + output_1 + " -p " + GlobalPath+"params/para-Standard_bspline.txt";
new Thread(() -> {
try {
Process ps = Runtime.getRuntime().exec(cmd);
// ps.getInputStream() 获取进程的输出流
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
pluginMain.logMessage.append(line + "\n");
pluginMain.logMessage.setCaretPosition(pluginMain.logMessage.getDocument().getLength()); // 滚动到文本末尾
pluginMain.logMessage.repaint(); // 强制刷新文本区域
}
ps.waitFor();
transform();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public void transform() {
String transformixUrl = "D:/Desktop/brainPro/transformix";
String outputDir = "D:/Desktop/brainPro/registration/temp2";
String regisAnnoUrl = "D:/Desktop/brainPro/registration/regisAnno.tif";
String cmd = transformixUrl + " -in " + regisAnnoUrl + " -out " + outputDir + " -tp " + output_1 + "/TransformParameters.0.txt";
new Thread(() -> {
try {
Process ps = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
pluginMain.logMessage.append(line + "\n");
pluginMain.logMessage.setCaretPosition(pluginMain.logMessage.getDocument().getLength()); // 滚动到文本末尾
pluginMain.logMessage.repaint(); // 强制刷新文本区域
}
ps.waitFor();
onTransformFinished();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
private void onTransformFinished() {
if (callback != null) {
callback.onTransformCompleted();
}
}
}
// pluginMain.java
registrationBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Registration().registration(new RegistrationCallback() {
public void onTransformCompleted() {
// TODO Auto-generated method stub
regisAnno = new ImagePlus("D:/Desktop/brainPro/registration/temp2/result.tif");
logMessage.append("4. 配准已完成");
}
});
}
});