TrackerPanel.java Source code

Java tutorial

Introduction

Here is the source code for TrackerPanel.java

Source

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.text.DecimalFormat;

import javax.swing.JPanel;

import org.OpenNI.AlternativeViewpointCapability;
import org.OpenNI.Context;
import org.OpenNI.DepthGenerator;
import org.OpenNI.DepthMetaData;
import org.OpenNI.GeneralException;
import org.OpenNI.ImageGenerator;
import org.OpenNI.License;
import org.OpenNI.MapOutputMode;
import org.OpenNI.PixelFormat;
import org.OpenNI.SceneMetaData;
import org.OpenNI.StatusException;
import org.OpenNI.UserGenerator;
import org.json.simple.parser.ParseException;

public class TrackerPanel extends JPanel implements Runnable, GesturesWatcher {
    private static final long serialVersionUID = 1L;

    private BufferedImage cameraImage;
    private int[] cameraPixels;
    private int hideBGPixel;

    private static final int MAX_DEPTH_SIZE = 10000;

    private Color USER_COLORS[] = { Color.RED, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.PINK,
            Color.YELLOW, Color.WHITE };
    /*
     * colors used to draw each user's depth image, except the last (white)
     * which is for the background
     */

    private byte[] imgbytes;
    private int imWidth, imHeight;
    private float histogram[]; // for the depth values
    private int maxDepth = 0; // largest depth value

    private volatile boolean isRunning;

    // used for the average ms processing information
    private int imageCount = 0;
    private long totalTime = 0;
    private DecimalFormat df;
    private Font msgFont;

    // OpenNI
    private Context context;
    private DepthMetaData depthMD;
    private DepthGenerator depthGen;
    private ImageGenerator imageGen;

    private SceneMetaData sceneMD;

    private Skeletons skels; // the users' skeletons

    public TrackerPanel() {
        setBackground(Color.GRAY);

        df = new DecimalFormat("0.#"); // 1 dp
        msgFont = new Font("SansSerif", Font.BOLD, 13);

        configOpenNI();

        histogram = new float[MAX_DEPTH_SIZE];

        imWidth = depthMD.getFullXRes();
        imHeight = depthMD.getFullYRes();
        setSize(imWidth * 2, imHeight);
        System.out.println("Image dimensions (" + imWidth + ", " + imHeight + ")");
        // create empty image bytes array of correct size and type
        imgbytes = new byte[imWidth * imHeight * 3];
        hideBGPixel = new Color(0, 0, 255, 0).getRGB();

        // create d.s for holding camera pixels and image
        cameraPixels = new int[imWidth * imHeight];
        cameraImage = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_INT_ARGB);
        // the image must have an alpha channel for the transparent blue pixels

        new Thread(this).start(); // start updating the panel
    } // end of TrackerPanel()

    private void configOpenNI() {
        try {
            context = new Context();
            License license = new License("PrimeSense", "0KOIk2JeIBYClPWVnMoRKn5cdY4=");
            context.addLicense(license);

            depthGen = DepthGenerator.create(context);
            imageGen = ImageGenerator.create(context);

            // set the viewpoint of the DepthGenerator to match the
            // ImageGenerator

            AlternativeViewpointCapability altViewCap = depthGen.getAlternativeViewpointCapability();
            altViewCap.setViewpoint(imageGen);

            MapOutputMode mapMode = new MapOutputMode(640, 480, 30);
            depthGen.setMapOutputMode(mapMode);
            imageGen.setMapOutputMode(mapMode);
            imageGen.setPixelFormat(PixelFormat.RGB24);

            context.setGlobalMirror(true); // set mirror mode

            depthMD = depthGen.getMetaData();

            UserGenerator userGen = UserGenerator.create(context);
            sceneMD = userGen.getUserPixels(0);

            skels = new Skeletons(userGen, depthGen, this);

            context.startGeneratingAll();
            System.out.println("Started context generating...");
        } catch (Exception e) {
            System.out.println(e);
            System.exit(1);
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(imWidth, imHeight);
    }

    public void closeDown() {
        isRunning = false;
    }

    public void run() {
        isRunning = true;
        while (isRunning) {
            try {
                context.waitAnyUpdateAll();
            } catch (StatusException e) {
                System.out.println(e);
                System.exit(1);
            }
            long startTime = System.currentTimeMillis();
            screenUsers();
            updateUserDepths();
            skels.update();
            screenUsers();
            imageCount++;
            totalTime += (System.currentTimeMillis() - startTime);
            repaint();
        }
        // close down
        try {
            context.stopGeneratingAll();
        } catch (StatusException e) {
        }
        context.release();
        System.exit(0);
    } // end of run()

    private void screenUsers() {
        // store the Kinect RGB image as a pixel array in cameraPixels
        try {
            ByteBuffer imageBB = imageGen.getImageMap().createByteBuffer();
            convertToPixels(imageBB, cameraPixels);
        } catch (GeneralException e) {
            System.out.println(e);
        }

        hideBackground(cameraPixels);

        // change the modified pixels into an image
        cameraImage.setRGB(0, 0, imWidth, imHeight, cameraPixels, 0, imWidth);
        imageCount++;
    } // end of screenUsers()

    private void convertToPixels(ByteBuffer pixelsRGB, int[] cameraPixels) {
        int rowStart = 0;

        int bbIdx; // index into ByteBuffer
        int i = 0; // index into pixels int[]
        int rowLen = imWidth * 3; // number of bytes in each row
        for (int row = 0; row < imHeight; row++) {
            bbIdx = rowStart;
            // System.out.println("bbIdx: " + bbIdx);
            for (int col = 0; col < imWidth; col++) {
                int pixR = pixelsRGB.get(bbIdx++);
                int pixG = pixelsRGB.get(bbIdx++);
                int pixB = pixelsRGB.get(bbIdx++);

                cameraPixels[i++] = 0xFF000000 | ((pixR & 0xFF) << 16) | ((pixG & 0xFF) << 8) | (pixB & 0xFF);
            }
            rowStart += rowLen; // move to next row
        }
    } // end of convertToPixels()

    private void hideBackground(int[] cameraPixels) {
        depthMD = depthGen.getMetaData();

        ShortBuffer usersBuf = sceneMD.getData().createShortBuffer();
        int userCount = 0;
        int maxUserCount = 0;
        int userCountMaxRow = 0;
        int maxY = 0;
        int row = 0;
        int rowCount = 0;

        while (usersBuf.remaining() > 0) {
            int pos = usersBuf.position();
            short userID = usersBuf.get();
            if (userID == 0) {
                // if not a user (i.e. is part of the background)
                cameraPixels[pos] = hideBGPixel; // make pixel transparent
            } else {
                userCount++;
                int y = imHeight - row;
                if (y > maxY) {
                    maxY = y;
                }
            }
            rowCount++;
            if (rowCount == imWidth) {
                if (userCount > maxUserCount) {
                    maxUserCount = userCount;
                    userCountMaxRow = row;
                }
                row++;
                rowCount = 0;
                userCount = 0;
            }
        }
        int startPoint = imWidth * (imHeight - maxY);
        int finalPoint = startPoint + imWidth;
        if (maxY != 0) {
            printLine(startPoint, finalPoint, Color.YELLOW.getRGB());
        }
        startPoint = imWidth * (userCountMaxRow);
        finalPoint = startPoint + imWidth;
        if (userCountMaxRow != 0) {
            SimpleHTTPPOSTRequester httpPost = new SimpleHTTPPOSTRequester();
            try {
                httpPost.makeHTTPPOSTRequest(userCountMaxRow);
            } catch (ParseException e1) {
                e1.printStackTrace();
            }
            Util.insertLastPoint(userCountMaxRow);
            int response = Util.analyzeLastFivePoints();

            if (response == Util.NOT_READY) {
                printLine(startPoint, finalPoint, Color.RED.getRGB());
            } else if (response == Util.READY) {
                printLine(startPoint, finalPoint, Color.WHITE.getRGB());
            } else if (response == Util.GOING_UP) {
                printLine(startPoint, finalPoint, Color.GREEN.getRGB());
            } else if (response == Util.GOING_DOWN) {
                printLine(startPoint, finalPoint, Color.PINK.getRGB());
            }

        }
    }

    private void printLine(int startPoint, int finalPoint, int rgbColor) {
        for (int i = startPoint; i < finalPoint; i++) {
            cameraPixels[i] = rgbColor;
        }
    }

    private void updateUserDepths() {
        depthMD = depthGen.getMetaData();
        ShortBuffer depthBuf = depthMD.getData().createShortBuffer();
        calcHistogram(depthBuf);
        depthBuf.rewind();

        ShortBuffer usersBuf = sceneMD.getData().createShortBuffer();

        while (depthBuf.remaining() > 0) {
            int pos = depthBuf.position();
            short depthVal = depthBuf.get();
            short userID = usersBuf.get();

            imgbytes[3 * pos] = 0; // default colour is black when there's no
            // depth data
            imgbytes[3 * pos + 1] = 0;
            imgbytes[3 * pos + 2] = 0;

            if (depthVal != 0) { // there is depth data
                // convert userID to index into USER_COLORS[]
                int colorIdx = userID % (USER_COLORS.length - 1); // skip last
                // color

                if (userID == 0) // not a user; actually the background
                    colorIdx = USER_COLORS.length - 1;
                // use last index: the position of white in USER_COLORS[]

                // convert histogram value (0.0-1.0f) to a RGB color
                float histValue = histogram[depthVal];
                imgbytes[3 * pos] = (byte) (histValue * USER_COLORS[colorIdx].getRed());
                imgbytes[3 * pos + 1] = (byte) (histValue * USER_COLORS[colorIdx].getGreen());
                imgbytes[3 * pos + 2] = (byte) (histValue * USER_COLORS[colorIdx].getBlue());
            }
        }
    }

    private void calcHistogram(ShortBuffer depthBuf) {
        // reset histogram
        for (int i = 0; i <= maxDepth; i++)
            histogram[i] = 0;

        // record number of different depths in histogram[]
        int numPoints = 0;
        maxDepth = 0;
        while (depthBuf.remaining() > 0) {
            short depthVal = depthBuf.get();
            if (depthVal > maxDepth)
                maxDepth = depthVal;
            if ((depthVal != 0) && (depthVal < MAX_DEPTH_SIZE)) { // skip
                // histogram[0]
                histogram[depthVal]++;
                numPoints++;
            }
        }
        // System.out.println("No. of numPoints: " + numPoints);
        // System.out.println("Maximum depth: " + maxDepth);

        // convert into a cummulative depth count (skipping histogram[0])
        for (int i = 1; i <= maxDepth; i++)
            histogram[i] += histogram[i - 1];

        /*
         * convert cummulative depth into the range 0.0 - 1.0f which will later
         * be used to modify a color from USER_COLORS[]
         */
        if (numPoints > 0) {
            for (int i = 1; i <= maxDepth; i++)
                // skipping histogram[0]
                histogram[i] = 1.0f - (histogram[i] / (float) numPoints);
        }
    } // end of calcHistogram()

    // -------------------- drawing -------------------------

    public void paintComponent(Graphics g)
    // Draw the depth image with coloured users, skeletons, and statistics info
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        drawUserDepths(g2d);
        g2d.drawImage(cameraImage, 641, 0, this);

        g2d.setFont(msgFont); // for user status and stats
        skels.draw(g2d);
        writeStats(g2d);
    } // end of paintComponent()

    private void drawUserDepths(Graphics2D g2d) {
        // define an 8-bit RGB channel color model
        ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                new int[] { 8, 8, 8 }, false, false, ComponentColorModel.OPAQUE, DataBuffer.TYPE_BYTE);

        // fill the raster with the depth image bytes
        DataBufferByte dataBuffer = new DataBufferByte(imgbytes, imWidth * imHeight * 3);

        WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, imWidth, imHeight, imWidth * 3, 3,
                new int[] { 0, 1, 2 }, null);

        // combine color model and raster to create a BufferedImage
        BufferedImage image = new BufferedImage(colorModel, raster, false, null);

        g2d.drawImage(image, 0, 0, null);
    } // end of drawUserDepths()

    private void writeStats(Graphics2D g2d) {
        g2d.setColor(Color.WHITE);
        int panelHeight = getHeight();
        if (imageCount > 0) {
            double avgGrabTime = (double) totalTime / imageCount;
            g2d.drawString("Pic " + imageCount + "  " + df.format(avgGrabTime) + " ms", 5, panelHeight); // bottom left
        } else
            // no image yet
            g2d.drawString("Loading...", 5, panelHeight);
    }

    // ------------GesturesWatcher.pose() -----------------------------

    public void pose(int userID, GestureName gest, boolean isActivated)
    // called by the gesture detectors
    {
        //      if (isActivated)
        //System.out.println(gest + " " + userID + " on");

    } // end of pose()

} // end of TrackerPanel class