001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.hardware.kinect;
031
032import java.nio.ByteBuffer;
033
034import org.bridj.Pointer;
035import org.openimaj.hardware.kinect.freenect.libfreenectLibrary;
036import org.openimaj.hardware.kinect.freenect.libfreenectLibrary.freenect_depth_cb;
037import org.openimaj.hardware.kinect.freenect.libfreenectLibrary.freenect_depth_format;
038import org.openimaj.hardware.kinect.freenect.libfreenectLibrary.freenect_device;
039import org.openimaj.hardware.kinect.freenect.libfreenectLibrary.freenect_resolution;
040import org.openimaj.image.FImage;
041
042/**
043 * Callback handling the depth information
044 * 
045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
046 * 
047 */
048class DepthCallback extends freenect_depth_cb implements KinectStreamCallback {
049        private static final float[] LUT = new float[2048];
050        static {
051                for (int i = 0; i < LUT.length; i++)
052                        LUT[i] = i / (LUT.length - 1f);
053        }
054
055        KinectDepthStream stream;
056        ByteBuffer buffer;
057        int nextTimeStamp;
058        FImage nextFrame;
059        boolean updated = false;
060
061        public DepthCallback(KinectDepthStream stream, boolean registeredDepthMode) {
062                this.stream = stream;
063                final Pointer<freenect_device> device = stream.controller.device;
064
065                if (registeredDepthMode)
066                        libfreenectLibrary.freenect_set_depth_mode_proxy(device, freenect_resolution.FREENECT_RESOLUTION_MEDIUM,
067                                        freenect_depth_format.FREENECT_DEPTH_REGISTERED);
068                else
069                        libfreenectLibrary.freenect_set_depth_mode_proxy(device, freenect_resolution.FREENECT_RESOLUTION_MEDIUM,
070                                        freenect_depth_format.FREENECT_DEPTH_11BIT);
071
072                buffer = ByteBuffer.allocateDirect(libfreenectLibrary.freenect_get_video_buffer_size(device));
073                libfreenectLibrary.freenect_set_depth_buffer(device, Pointer.pointerToBuffer(buffer));
074
075                nextFrame = new FImage(stream.width, stream.height);
076
077                libfreenectLibrary.freenect_set_depth_callback(device, toPointer());
078                libfreenectLibrary.freenect_start_depth(device);
079        }
080
081        @Override
082        public synchronized void apply(Pointer<freenect_device> dev, Pointer<?> depth, int timestamp) {
083                updated = true;
084                nextTimeStamp = timestamp;
085
086                setImage();
087        }
088
089        @Override
090        public synchronized void swapFrames() {
091                if (!updated)
092                        return;
093
094                final FImage tmp = stream.frame;
095                stream.frame = nextFrame;
096                nextFrame = tmp;
097                stream.timeStamp = nextTimeStamp;
098                updated = false;
099        }
100
101        public void setImage() {
102                final ByteBuffer buf = buffer.duplicate();
103
104                final int width = stream.width;
105                final int height = stream.height;
106
107                final float[][] pix = nextFrame.pixels;
108
109                for (int y = 0; y < height; y++) {
110                        for (int x = 0; x < width; x++) {
111                                final int first = (buf.get() & 0xFF);
112                                final int second = (buf.get() & 0xFF);
113                                pix[y][x] = first + (second << 8);
114                        }
115                }
116        }
117
118        @Override
119        public void stop() {
120                libfreenectLibrary.freenect_stop_depth(stream.controller.device);
121        }
122}
123
124/**
125 * The stream of depth information
126 * 
127 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
128 * 
129 */
130public class KinectDepthStream extends KinectStream<FImage> {
131        boolean registered;
132
133        /**
134         * Construct with a reference to the controller
135         * 
136         * @param controller
137         *            The controller
138         * @param registeredDepthMode
139         *            whether to register the depth image. If true, depth
140         *            measurements are in millimeters.
141         */
142        public KinectDepthStream(KinectController controller, boolean registeredDepthMode) {
143                super(controller);
144
145                fps = 30;
146                width = 640;
147                height = 480;
148                frame = new FImage(width, height);
149                registered = registeredDepthMode;
150
151                callback = new DepthCallback(this, registeredDepthMode);
152        }
153}