001package org.openimaj.image.processing; 002 003import java.io.IOException; 004import java.io.InputStream; 005import java.net.URL; 006 007import org.apache.commons.io.IOUtils; 008import org.openimaj.image.CLImageConversion; 009import org.openimaj.image.Image; 010import org.openimaj.image.processor.ImageProcessor; 011 012import com.nativelibs4java.opencl.CLBuildException; 013import com.nativelibs4java.opencl.CLContext; 014import com.nativelibs4java.opencl.CLEvent; 015import com.nativelibs4java.opencl.CLImage2D; 016import com.nativelibs4java.opencl.CLKernel; 017import com.nativelibs4java.opencl.CLMem; 018import com.nativelibs4java.opencl.CLPlatform.DeviceFeature; 019import com.nativelibs4java.opencl.CLProgram; 020import com.nativelibs4java.opencl.CLQueue; 021import com.nativelibs4java.opencl.JavaCL; 022 023/** 024 * Base {@link ImageProcessor} for GPGPU accelerated processing. 025 * 026 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 027 * 028 * @param <I> Type of {@link Image} being processed 029 */ 030public class CLImageProcessor<I extends Image<?, I>> implements ImageProcessor<I> { 031 protected CLContext context; 032 protected CLKernel kernel; 033 034 /** 035 * Construct with the given OpenCL program 036 * @param program the OpenCL program 037 */ 038 public CLImageProcessor(CLProgram program) { 039 try { 040 this.context = JavaCL.createBestContext(DeviceFeature.GPU); 041 this.kernel = program.createKernels()[0]; 042 } catch (CLBuildException e) { 043 //fallback to OpenCL on the CPU 044 this.context = JavaCL.createBestContext(DeviceFeature.CPU); 045 this.kernel = program.createKernels()[0]; 046 } 047 } 048 049 /** 050 * Construct with the given OpenCL program source, given in 051 * the form of {@link String}s. 052 * 053 * @param programSrcs the source of the program 054 */ 055 public CLImageProcessor(String... programSrcs) { 056 CLProgram program; 057 try { 058 this.context = JavaCL.createBestContext(DeviceFeature.GPU); 059 program = context.createProgram(programSrcs); 060 this.kernel = program.createKernels()[0]; 061 } catch (CLBuildException e) { 062 //fallback to OpenCL on the CPU 063 this.context = JavaCL.createBestContext(DeviceFeature.CPU); 064 program = context.createProgram(programSrcs); 065 this.kernel = program.createKernels()[0]; 066 } 067 } 068 069 /** 070 * Construct with the program sourcecode at the given URL. 071 * @param srcUrl the url 072 * @throws IOException 073 */ 074 public CLImageProcessor(URL srcUrl) throws IOException { 075 this(IOUtils.toString(srcUrl)); 076 } 077 078 /** 079 * Construct by reading the program source from a stream 080 * @param src the source stream 081 * @throws IOException 082 */ 083 public CLImageProcessor(InputStream src) throws IOException { 084 this(IOUtils.toString(src)); 085 } 086 087 /** 088 * Construct with the given OpenCL program 089 * @param context the OpenCL context to use 090 * @param program the OpenCL program 091 */ 092 public CLImageProcessor(CLContext context, CLProgram program) { 093 this.context = context; 094 this.kernel = program.createKernels()[0]; 095 } 096 097 /** 098 * Construct with the given OpenCL program source, given in 099 * the form of {@link String}s. 100 * @param context the OpenCL context to use 101 * 102 * @param programSrcs the source of the program 103 */ 104 public CLImageProcessor(CLContext context, String... programSrcs) { 105 this.context = context; 106 CLProgram program = context.createProgram(programSrcs); 107 this.kernel = program.createKernels()[0]; 108 } 109 110 /** 111 * Construct with the given OpenCL kernel 112 * @param kernel the OpenCL kernel to use 113 */ 114 public CLImageProcessor(CLKernel kernel) { 115 this.context = kernel.getProgram().getContext(); 116 this.kernel = kernel; 117 } 118 119 /** 120 * Construct with the program sourcecode at the given URL. 121 * @param context the OpenCL context to use 122 * @param srcUrl the url 123 * @throws IOException 124 */ 125 public CLImageProcessor(CLContext context, URL srcUrl) throws IOException { 126 this(context, IOUtils.toString(srcUrl)); 127 } 128 129 /** 130 * Construct by reading the program source from a stream 131 * @param context the OpenCL context to use 132 * @param src the source stream 133 * @throws IOException 134 */ 135 public CLImageProcessor(CLContext context, InputStream src) throws IOException { 136 this(context, IOUtils.toString(src)); 137 } 138 139 @Override 140 public void processImage(I image) { 141 CLQueue queue = context.createDefaultQueue(); 142 143 CLImage2D in = CLImageConversion.convert(context, image); 144 CLImage2D out = context.createImage2D(CLMem.Usage.Output, in.getFormat(), in.getWidth(), in.getHeight()); 145 146 kernel.setArgs(in, out); 147 CLEvent evt = kernel.enqueueNDRange(queue, new int[] {(int) in.getWidth(), (int) in.getHeight()}); 148 149 CLImageConversion.convert(queue, evt, out, image); 150 151 in.release(); 152 out.release(); 153 queue.release(); 154 } 155}