This tutorial was written in 2010-11, and contains out-of-date or no-longer-accurate information. A potential alternative for using OpenCL in ImageJ is CLIJ.
本教程旨在帮助您利用 Java 中的 OpenCL 与 ImageJ 一起使用。
背景
要在 ImageJ 中使用 Java 中的 OpenCL,我们依赖JOCL。 JOCL 是在低级 JNI API 上面编写的,使 OpenCL 的使用更容易。您编写的 OpenCL 代码还可以利用 JOCL 来加速 Java 中 ImageJ 插件的执行。我们创建了一个 OpenCL deconvolution 示例来使用演示 OpenCL 的计算加速(本地和远程作为二级 Web 服务)。
设置开发机
我们设置了一个基于 Ubuntu 的开发机器用于 OpenCL 开发和测试。Mac OS X 10.6、Windows 64/32 和 Linux 64/32 通过测试并受到此支持。以下是设置 Ubuntu 的步骤:
- 获取 Ubuntu 10.04 的 ISO
- 在目标机器上安装 Ubuntu。
- 安装g++:
sudo apt-get install g++ - 安装所需的开发库:
sudo apt-get install freeglut3-dev sudo apt-get install libxi-dev sudo apt-get install libxmu-devOpenCL
如果支持 OpenCL 的硬件未作为操作系统的一部分进行安装,则需要为其安装 OpenCL。
为 ATI OpenCL
如果您有 ATI GPU 硬件 (AMD),则可以下载 SDK on GitHub。
为 NVidia OpenCL
对于 NVidia 硬件,请按照these installation instructions安装开发驱动程序、CUDA 工具包和 GPU 计算 SDK 代码示例。
使用 wget 工具从 NVidia 的下载站点下载三个必需的安装文件。
wget http://developer.download.nvidia.com/compute/cuda/\
3_2_prod/drivers/devdriver_3.2_linux_64_260.19.26.run
wget http://developer.download.nvidia.com/compute/cuda/\
3_2_prod/toolkit/cudatoolkit_3.2.16_linux_64_ubuntu10.04.run
wget http://developer.download.nvidia.com/compute/cuda/\
3_2_prod/sdk/gpucomputingsdk_3.2.16_linux.run
通过输入以下内容停止图形桌面管理器:
须藤 gdm 停止
从命令行。
安装所需的文件:
sudo sh devdriver_3.2_linux_64_260.19.26.run
sudo sh cudatoolkit_3.2.16_linux_64_ubuntu10.04.run
sh gpucomputingsdk_3.2.16_linux.run
根据安装说明,我们设置环境变量(在.bashrc中):
export LD_LIBRARY_PATH="/usr/local/cuda/lib:/usr/local/cuda/lib64"
export PATH="/usr/local/cuda/bin"
通过编译和运行一些 NVidia 提供的 OpenCL 示例来测试安装,方法只需将目录更改为:
/NVIDIA_GPU_COMPUTING_SDK/C
and running:
make
We ran into an error and ended up editing the file
/NVIDIA_GPU_COMPUTING_SDK/C/common.mk
by replacing line 169 with:
NVCCFLAGS += --compiler-options -fpermissive
and re-running:
make
Change directories to
/NVIDIA_GPU_Computing_SDK/C/bin/linux/release
and run
./bandwidthtest
to check the binary CUDA install.
Build the OpenCL examples by changing directories to
/NVIDIA_GPU_COMPUTING_SDK/OpenCL
and running:
make
Change directories to
/NVIDIA_GPU_Computing_SDK/OpenCL/bin/linux/release
to run the OpenCL Bandwidth sample using:
./oclBandwidthTest
在 Ubuntu 上设置 Eclipse 和所需的插件
为了配置开发环境,我们首先安装JRE:
sudo apt-get 安装 openjdk-6-jdk
并从以下位置下载 Eclipse for J2EE Developers: http://www.eclipse.org/downloads/download.php 并遵循Eclipse安装步骤。
我们通过单击 Properties › Java Build Path › Libraries 并添加 SVN 适配器站点,将 SVN 插件添加到 Eclipse: http://subclipse.tigris.org/update_1.6.x
下载并运行 ImageJ OpenCL 示例
通过右键单击 Package Explorer 窗口并选择 Import,可以将 ImageJ OpenCL 示例导入为 Eclipse 项目。选择 Git 项目并添加站点: https://github.com/uw-loci/opencl-decon 导入分支并指定一个通用项目名称,例如 imagej-opencl。
源的文件夹结构由以下部分组成:
- src - Java 和 OpenCL 源文件(扩展名 .cl)请注意 src 目录中的文件 fht.cl 和 sobel.cl。执行时,示例中提供的 Java 代码将编译这些 OpenCL 以便执行。注意:OpenCL 源文件的运行时编译允许在任何潜在的支持 OpenCL 的设备上执行。
- 源数据 - (点扩散函数)PSF 和 3D 数据关联 FHT3D 样本的小样本数据集。
- lib - 使用 JOCL、ImageJ 和 Hessian 4.0.7 的类所需的库
我们这里目录中包含了 Windows 32/64、Apple 和 Linux 32/64 平台所需的 JOCL 本机库。为了在 ImageJ 中使用 Java 中的 OpenCL,我们使用 JOCL。 JOCL 使用 JNI 调用 OpenCL API。您编写的 OpenCL 代码还可以利用 JOCL 来加速 Java 中 ImageJ每个由于操作系统都有不同的本机JOCL本机库,因此必须配置运行时环境,以便Java代码可以加载所需的本机库。
了解特定于平台的 JOCL 本机库
对于这些示例,三个本机库:gluegen-rt、jocl 和 JOCL-‘platform’-‘arch’。如果您查看 lib 文件夹,您将找到包含相应库的 -natives-xyz.jar 文件。需要解压这三个 jar 文件,需要把动态文件(.so、.dylib 或 .dll)复制到父目录中(如果它们不存在)。请注意下面的示例,其中libgluegen-rt.dylib、libJOCL-apple-x86_64.dylib 和 libjocl.dylib 文件位于平台目录特定中。

然后确保在项目构建期间导出特定于平台的 jar。例如,请注意项目中引用了 JOCL-0-1.4-beta1.jar 文件。 (要查看此菜单,请右键单击项目并选择Help › Install New Software。)

最后,确保导出平台特定文件:

通过查看文件 src/publication/SobelFilterExample.java 中的开发人员注释开始探索示例。请注意,Main() 方法调用 run(),它使用 awt.Image 类型作为输入参数。修改并运行 Main() 方法作为 Java 应用程序,并根据需要调整 VM 参数(例如-Xmx1024m)。
SobelFilter 示例
在不进行修改的情况下,SobelFilterExample.java从Web服务器加载图像,使用OpenCL在本地处理该图像,并显示结果。这个例子和什么新地点奇。它只允许对多个系统配置步骤进行运行时测试,以确保JOCL和OpenCL本机库的工作配置。修改此示例满足您的需求,但请在没有继续确保之前正确的JOCL和OpenCL配置。
了解 ImageJ + OpenCL
在 ImageJ 工作中:如果使用 OpenCL 开发 ImageJ 插件,请发现编程控制将在 PlugIn(或 PluginFilter)run() 方法内提供给您的插件。可以在 src.demos.OpenCL_SobelFilter.java 中找到这样的示例。为了使该插件在 ImageJ 中运行,ImageJ 类加载器需要提供与目标平台相关的 JOCL jar 和本机库。支持的 JOCL本机库可以复制到 ImageJ 内的插件目录中,并允许使用 OpenCL 的插件实现引用 OpenCL 安装提供的本机库。
ImageJ OpenCL:应用OpenCL的增量方法
现在您已经修改了在 Java 中以及在 ImageJ 中使用 OpenCL 的演示,您可能希望看到一个计算密集型示例,演示对现有 Java 实现的,将其部分实现委托给 OpenCL。查看 FHT3D_3D_Deconvolution.java 示例中的开发人员评论,了解算法实现中的步骤在 Java 和 OpenCL 之间使用哪些步骤之间的代理数据。
用于从现有的 Java 实现委托给 OpenCL 的方法开始:
- 评估现有实现的性能,新增计算最密集的代码区域
- 开发该区域之前和之后的测试数据集 3.编写替换计算密集型区域的OpenCL代码
- 进行测试以确保新的 OpenCL 代码使用测试数据生成相同的结果 5.添加条件委托逻辑来处理运行时计算功能
OpenCL ImageJ 插件遵循企业 java 模式
最后,一些用户和学术实验室正在构建“GPU Supercomputers”,以将计算资源公开给本地运行的各种应用程序。在这种情况下,您希望利用查看FHTEJBService和Iterative_Deconvolve_3D_WS类来获取有关如何使用开源J2EE技术远程提供GPU加速资源的示例。
在此示例中,Hessian 二进制 Web 服务用于在 Java 用户和 Hessian Servlet 之间代理数据。仅建议那些在客户端应用程序和 OpenCL/GPU servlet 主机之间有足够吞吐量的实验室使用此方法。
使用 Oracle 的 GlassfishV3 托管 OpenCL 加速算法
要在Glassfish上设置OpenCL支持以部署基于ImageJ/Fiji Java的EJB,请导航至系统的lib目录(例如:/opt/glassfishv3/glassfish/lib)并安装所需的jar/本机库。
sudo wget http://jogamp.org/deployment/webstart/jocl-natives-linux-amd64.jar
sudo unzip jocl-natives-linux-amd64.jar
sudo rm -rdf META-INF
sudo rm jocl-natives-linux-amd64.jar
sudo wget http://jogamp.org/deployment/webstart/gluegen-rt-natives-linux-amd64.jar
sudo unzip gluegen-rt-natives-linux-amd64.jar
sudo rm -rdf META-INF/
sudo rm gluegen-rt-natives-linux-amd64.jar
sudo wget http://jocl.org/downloads/JOCL-0.1.4-beta1-bin-linux-x86_64.zip
sudo unzip JOCL-0.1.4-beta1-bin-linux-x86_64.zip
sudo mv JOCL-0.1.4-beta1-bin-linux-x86_64/*.so .
sudo mv JOCL-0.1.4-beta1-bin-linux-x86_64/*.jar .
sudo rm -rdf JOCL-0.1.4-beta1-bin-linux-x86_64
sudo rm JOCL-0.1.4-beta1-bin-linux-x86_64.zip
sudo wget http://jogamp.org/deployment/webstart/gluegen-rt.jar
sudo wget http://jogamp.org/deployment/webstart/gluegen.jar
sudo wget http://jogamp.org/deployment/webstart/jocl.jar
glassfish 以支持 JOCL 设置所需的唯一另一件事是登录到管理控制台,位于 Common Tasks › Configuration › JVM Settings › Path Settings 下。
本机库路径出口:/opt/glassfishv3/glassfish/lib
#基于GPU的处理技术和ImageJ架构
The following article describes our first effort at GPU computing with ImageJ using OpenCL, in early 2010. The tutorial above is more recent and more complete; the text below is preserved only for historical reasons.
简介
本文的主要重点是介绍和评估两种常见的 GPU 技术(CUDA 和 OpenCL),因为它们可以在 ImageJ 中使用。目的是简单介绍用于执行两个基本图像处理任务的软件库,并提供可能有助于确定该领域未来工作的性能指标。
ImageJ 和 ImageJ 插件中的许多算法都可以利用 GPU 和多核 CPU 处理器来实现。能够支持利用“多核硬件处理器”的插件给 ImageJ 带来了重要的架构问题。ImageJ 重构工作的目的是利用“幕后”硬件设备的方式实现对本机代码集成的支持。性能并不像与外部本机库的兼容性和非编程科学家的易用性那么重要。
注意:“设备”是指基于GPU的硬件设备,“主机”是指基于GPU的设备。
ImgLib 使用背景
ImageJ 的未来版本将采用ImgLib通用处理库。 ImgLib 代码库中引入了一个非常小的更改,允许将数据存储在 Java.NIO 数据库中。NIO 支持的数据库在 Java 虚拟机外部分配,并允许与本机代码共享多个数据副本。
开发基于GPU的代码时会遇到几个问题:
- 使用 NIO 缓冲区并考虑不同硬件设备之间交换数据时的不同字节顺序,需要字节顺序差异。
- 可用主机内存量、设备内存量、GPU 处理器数量以及设备的计算能力可能会有很大差异。
为了解决这些问题,可以使用辅助方法在运行时动态评估给定主机的功能。设备和主机的工作内存与设备的性能特征同样重要。分析性能对于评估设备也很重要,因为在多个应用程序之间共享的设备可能会比不共享设备时获得的性能。
在考虑如何从 Java 访问 GPU 资源时,考虑了几个开源 API。出于本次评估的目的,选择 Olivier Chafik 的 JavaCL 是因为其较宽松的通用公共许可证。
GPU 处理基站简介
在ImageJ中使用GPU作为计算设备时的处理管道涉及几个步骤:
- 从 imglib 对象获取所需字节顺序的本机备份中的数据
- 选择,编译内核,暂时设备与内核关联 3.启动内核
- 将结果返回到兼容的 Imglib 对象
指标/方法
Sobel 滤波器是一种常见图像的处理示例,用于边缘检测。由于实现简单以及 GPU 代码与现有开源实现的相似性,它非常适合此评估。
为了进行定时处理,8位测试图像将被加载到Imglib NIO支持的状态中。内核源代码是预编译的。计时器在调用执行内核启动之前,并在结果返回到Imglib NIO支持的状态后结束。计算100次迭代的命令行记录值。
注意:几乎肯定可以优化以下任何实现,但此评估的主要目标不是性能。
实施
以下代码演示了ImageJ中sobel过滤器的部分实现:
public byte[] filter(int width, int height, byte[] inputImageArray)
{
byte[] pixels = new byte[width*height];
int p1, p2, p3, p4, p5, p6, p7, p8, p9;
int offset, sum1, sum2=0, sum=0;
int rowOffset = width;
for (int y=1; y 255) sum = 255;
pixels[offset++] = (byte)sum;
}
}
return pixels;
}
有一些属性使得上述部分实现非常适合GPU计算。每个结果像素的值与周围的像素值无关。计算结果像素时消耗的值共享顺序可以利用性能优势。对每个像素执行多次计算。
以下是OpenCL中Sobel滤波器的部分实现:
__kernel void sobel( __global char* input, __global char* output, int width, int height)
{
int x = get_global_id(0); //find the X id
int y = get_global_id(1); //find the Y id
int p[9]; //allocate a local array used for intermediate values
int offset = y * width + x; //determine the offset
if( x < 1 || y < 1 || x > width - 2 || y > height - 2 ) //is this an edge pixel?
{
output[offset] = 0; //This partial implementation does not calculate edge values
}
else
{
p[0] = input[offset - width - 1] & 0xff;
p[1] = input[offset - width] & 0xff;
p[2] = input[offset - width + 1] & 0xff;
p[3] = input[offset - 1] & 0xff;
p[4] = input[offset] & 0xff;
p[5] = input[offset + 1] & 0xff;
p[6] = input[offset + width - 1] & 0xff;
p[7] = input[offset + width] & 0xff;
p[8] = input[offset + width + 1] & 0xff;
int sum1 = p[0] + 2*p[1] + p[2] - p[6] - 2*p[7] - p[8];
int sum2 = p[0] + 2*p[3] + p[6] - p[2] - 2*p[5] - p[8];
float sum3 = sum1*sum1 + sum2*sum2;
int sum = sqrt( sum3 );
if (sum > 255) sum = 255;
output[offset] = (char) sum; //write the result to the output array
}
};
OpenCL 内核与 Java 实现几乎相同,只是使用索引来标识每个值的偏移量(而不是循环遍历队列)。这使得计算可以分布在多个核心上,从而提供加速的潜力。
以下示例演示了如何使用 Imglib 加载和图像准备 GPU 计算:
//Create an array container factory
ArrayContainerFactory arrayContainerFactory = new ArrayContainerFactory();
//Set the backing type to NIO
arrayContainerFactory.setNIOUse(true);
//Create a image backed by an NIO typed array given an input file
Image inImg = LOCI.openLOCIFloatType( file.getPath(), arrayContainerFactory );
ArrayContainerFactory.setNIOUse(true)确保使用NIO支持的备份。使用NIO支持的备份而不是Java本机备份的原因是Java和本机之间的数据共享以及主机和设备之间的吞吐量的提高。CUDA和OpenCL的受益者都用于使用不分页的主机分区。这种类型的存储器称为页锁定存储器。“CUDA编程指南版本3.0”的第5.3.1节有关设备参数的更多具体信息。
注意:当设置 CL_MEM_ALLOC_HOST_PTR 标志时,OpenCL 可以使用页面锁定主机内存。