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}