001package org.openimaj.image.processing.convolution; 002 003import java.io.IOException; 004 005import org.apache.commons.io.IOUtils; 006import org.openimaj.image.CLImageConversion; 007import org.openimaj.image.FImage; 008import org.openimaj.image.MBFImage; 009import org.openimaj.image.processing.CLImageAnalyser; 010 011import com.nativelibs4java.opencl.CLContext; 012import com.nativelibs4java.opencl.CLEvent; 013import com.nativelibs4java.opencl.CLImage2D; 014import com.nativelibs4java.opencl.CLImageFormat; 015import com.nativelibs4java.opencl.CLImageFormat.ChannelDataType; 016import com.nativelibs4java.opencl.CLImageFormat.ChannelOrder; 017import com.nativelibs4java.opencl.CLMem; 018import com.nativelibs4java.opencl.CLQueue; 019 020/** 021 * OpenCL implementation of a 3x3 Sobel operator. Computes the magnitude, orientation 022 * and gradients (in x & y) in parallel. 023 * 024 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 025 * 026 */ 027public class CLSobel extends CLImageAnalyser<FImage> { 028 /** 029 * The computed Sobel magnitude 030 */ 031 public FImage magnitude; 032 033 /** 034 * The computed Sobel orientations 035 */ 036 public FImage orientation; 037 038 /** 039 * The computed Sobel gradient in the X direction 040 */ 041 public FImage gradientX; 042 043 /** 044 * The computed Sobel gradient in the Y direction 045 */ 046 public FImage gradientY; 047 048 /** 049 * Default Constructor 050 */ 051 public CLSobel() { 052 super(getKernel()); 053 } 054 055 /** 056 * Construct with context. 057 * @param ctx the context 058 */ 059 public CLSobel(CLContext ctx) { 060 super(ctx, getKernel()); 061 } 062 063 private static String getKernel() { 064 try { 065 return IOUtils.toString(CLSobel.class.getResource("Sobel3.cl")); 066 } catch (IOException e) { 067 throw new RuntimeException(e); 068 } 069 } 070 071 @Override 072 public void analyseImage(FImage image) { 073 CLQueue queue = context.createDefaultQueue(); 074 075 CLImage2D in = CLImageConversion.convert(context, image); 076 077 CLImageFormat outFmt = new CLImageFormat(ChannelOrder.RGBA, ChannelDataType.Float); 078 CLImage2D out = context.createImage2D(CLMem.Usage.Output, outFmt, in.getWidth(), in.getHeight()); 079 080 kernel.setArgs(in, out); 081 CLEvent evt = kernel.enqueueNDRange(queue, new int[] {(int) in.getWidth(), (int) in.getHeight()}); 082 083 MBFImage res = CLImageConversion.convert(queue, evt, out, new MBFImage(image.width, image.height, 4)); 084 085 this.magnitude = res.bands.get(0); 086 this.orientation = res.bands.get(1); 087 this.gradientX = res.bands.get(2); 088 this.gradientY = res.bands.get(3); 089 090 in.release(); 091 out.release(); 092 queue.release(); 093 } 094 095 /** 096 * @return the magnitude 097 */ 098 public FImage getMagnitude() { 099 return magnitude; 100 } 101 102 /** 103 * @return the orientation 104 */ 105 public FImage getOrientation() { 106 return orientation; 107 } 108 109 /** 110 * @return the gradientX 111 */ 112 public FImage getGradientX() { 113 return gradientX; 114 } 115 116 /** 117 * @return the gradientY 118 */ 119 public FImage getGradientY() { 120 return gradientY; 121 } 122}