de.openVJJ.processor.Warping.java Source code

Java tutorial

Introduction

Here is the source code for de.openVJJ.processor.Warping.java

Source

package de.openVJJ.processor;

import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;

import org.jdom2.Element;

import com.jogamp.opencl.CLBuffer;
import com.jogamp.opencl.CLCommandQueue;
import com.jogamp.opencl.CLKernel;
import com.jogamp.opencl.CLProgram;
import com.jogamp.opencl.CLMemory.Mem;

import de.openVJJ.InputComponents;
import de.openVJJ.openGJTest;
import de.openVJJ.controler.WarpingControl;
import de.openVJJ.graphic.VideoFrame;

/*
 * Copyright (C) 2012  Jan-Erik Matthies
 *
 * This program is free software;
 * you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation;
 * either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses/>.  
 */

public class Warping extends ImageProcessor {
    private Point[][][] imageMatrix;
    private int[][][] fastImageMatrix;
    int imageWidth = -1;
    int imageHeight = -1;
    Point pointTL;
    Point pointTR;
    Point pointBR;
    Point pointBL;

    public int speed = 2;
    private final static int FAST = 2;
    private final static int NORMAL = 1;

    @Override
    public VideoFrame processImage(VideoFrame videoFrame) {
        int newImageX = videoFrame.getHeight();
        int newImageY = videoFrame.getWidth();
        if (imageHeight != newImageX || imageWidth != newImageY) {
            imageHeight = newImageX;
            imageWidth = newImageY;
            if (pointTL == null) {
                pointTL = new Point(0, 0);
            }
            if (pointTR == null) {
                pointTR = new Point(imageWidth, 0);
            }
            if (pointBR == null) {
                pointBR = new Point(imageWidth, imageHeight);
            }
            if (pointBL == null) {
                pointBL = new Point(0, imageHeight);
            }
            if (pointTL.y > imageHeight) {
                pointTL.y = imageHeight;
            }
            if (pointTR.y > imageHeight) {
                pointTR.y = imageHeight;
            }
            if (pointBL.y > imageHeight) {
                pointBL.y = imageHeight;
            }
            if (pointBR.y > imageHeight) {
                pointBR.y = imageHeight;
            }
            if (pointTL.x > imageWidth) {
                pointTL.x = imageWidth;
            }
            if (pointTR.x > imageWidth) {
                pointTR.x = imageWidth;
            }
            if (pointBL.x > imageWidth) {
                pointBL.x = imageWidth;
            }
            if (pointBR.x > imageWidth) {
                pointBR.x = imageWidth;
            }
            refrefshMatrix();
        }
        return warpe(videoFrame);
    }

    public Point[] getWarpPoints() {
        return new Point[] { pointTL, pointTR, pointBR, pointBL };
    }

    public void setWarp(Point[] points) {
        setWarp(points[0], points[1], points[2], points[3]);
    }

    public void setWarp(Point pointTL, Point pointTR, Point pointBR, Point pointBL) {
        this.pointTL = pointTL;
        this.pointBL = pointBL;
        this.pointTR = pointTR;
        this.pointBR = pointBR;
        refrefshMatrix();
    }

    private void refrefshMatrix() {
        if (imageWidth < 1 || imageHeight < 1) {
            return;
        }
        double[] resultx = new double[] { (pointTR.x - pointTL.x) / (double) imageWidth, pointTL.x,
                (pointBL.x - pointTL.x) / (double) imageHeight,
                (((pointTR.x - pointTL.x) / (double) imageWidth - (pointBR.x - pointBL.x) / (double) imageWidth)
                        / imageHeight) };
        double[] resulty = new double[] { (pointTR.y - pointTL.y) / (double) imageWidth, pointTL.y,
                (pointBL.y - pointTL.y) / (double) imageHeight,
                (((pointTL.y - pointBL.y) / (double) imageHeight - (pointTR.y - pointBR.y) / (double) imageHeight)
                        / imageWidth) };
        generateMatrix(resultx, resulty);
    }

    private CLBuffer<FloatBuffer> matrixBuffer = null;

    private void generateMatrix(double[] fX, double[] fY) {
        FloatBuffer intBuffer = null;
        CLBuffer<FloatBuffer> matrixBufferTemp = null;
        if (InputComponents.useGPU) {
            if (!gpuReady) {
                initGPU();
            }
            matrixBufferTemp = getCLContext().createFloatBuffer(getGlobalWorkSize(imageWidth * imageHeight * 3),
                    Mem.READ_ONLY);
            intBuffer = matrixBufferTemp.getBuffer();
        } else if (speed < FAST) {
            imageMatrix = new Point[imageWidth][imageHeight][];
        } else {
            fastImageMatrix = new int[imageWidth][imageHeight][3];
        }

        for (double x = 0; x < imageWidth; x++) {
            for (double y = 0; y < imageHeight; y++) {
                int xPos = (int) (x * (fX[0] - (fX[3] * y)) + fX[1] + y * fX[2]);
                int yPos = (int) (y * (fY[2] + (fY[3] * x)) + fY[1] + x * fY[0]);
                if (xPos >= imageWidth || yPos >= imageHeight) {
                    continue;
                }
                try {
                    if (InputComponents.useGPU) {
                        int pos = (xPos * imageHeight * 3) + (yPos * 3);
                        if (intBuffer.get(pos) != 1) {
                            intBuffer.put(pos, 1);
                            intBuffer.put(pos + 1, (int) x);
                            intBuffer.put(pos + 2, (int) y);
                        }
                        continue;
                    }
                    if (speed > NORMAL) {
                        if (fastImageMatrix[xPos][yPos][2] != 1) {
                            fastImageMatrix[xPos][yPos][2] = 1;//for isSet
                            fastImageMatrix[xPos][yPos][0] = (int) x;
                            fastImageMatrix[xPos][yPos][1] = (int) y;
                        }
                        continue;
                    }
                    if (imageMatrix[xPos][yPos] == null) {
                        imageMatrix[xPos][yPos] = new Point[1];
                        imageMatrix[xPos][yPos][0] = new Point((int) x, (int) y);
                    } else {
                        int length = imageMatrix[xPos][yPos].length;
                        imageMatrix[xPos][yPos] = Arrays.copyOf(imageMatrix[xPos][yPos], length + 1);
                        imageMatrix[xPos][yPos][length] = new Point((int) x, (int) y);
                    }
                } catch (Exception e) {
                    System.out.println("at x=" + x + " : xPos=" + xPos + " xmax=" + imageWidth + " y=" + y
                            + " : yPos=" + yPos + " ymax=" + imageHeight);
                    e.printStackTrace();
                    return;
                }
            }
        }
        if (InputComponents.useGPU) {
            if (matrixBuffer != null) {
                matrixBuffer.release();
            }
            matrixBuffer = matrixBufferTemp;
        }
    }

    private CLProgram program;
    //private CLKernel kernel;
    boolean gpuReady = false;
    boolean gpuIniting = false;

    private void initGPU() {
        if (gpuIniting) {
            return;
        }
        gpuIniting = true;
        try {
            program = getCLContext().createProgram(openGJTest.class.getResourceAsStream("kernelProgramms/warp"))
                    .build();
        } catch (IOException e) {
            e.printStackTrace();
        }
        gpuReady = true;
        gpuIniting = false;
    }

    private CLKernel getKernel() {
        return program.createCLKernel("warp");
    }

    private void shutdownGPU() {
        if (program != null) {
            program.release();
        }
    }

    private void warpeChannel(CLBuffer<FloatBuffer> in, CLBuffer<FloatBuffer> out, int width, int height) {
        CLKernel kernel = getKernel();

        kernel.putArg(in);
        kernel.putArg(matrixBuffer);
        kernel.putArg(out);
        kernel.putArg(width);
        kernel.putArg(height);
        CLCommandQueue clCommandQueue = getCLCommandQueue();
        synchronized (clCommandQueue) {
            //clCommandQueue.putWriteBuffer(in, false);
            clCommandQueue.putWriteBuffer(matrixBuffer, false);
            clCommandQueue.put2DRangeKernel(kernel, 0, 0, width, height, 0, 0);
            clCommandQueue.putReadBuffer(out, true);
            clCommandQueue.finish();
        }
        kernel.release();
    }

    private VideoFrame warpe(VideoFrame videoFrame) {

        if (InputComponents.useGPU) {
            if (!gpuReady) {
                initGPU();
            }
            if (!gpuReady || matrixBuffer == null) {
                return videoFrame;
            }

            int width = videoFrame.getWidth();
            int height = videoFrame.getHeight();

            VideoFrame resultVideoFrame = new VideoFrame(width, height);

            CLBuffer<FloatBuffer> rIn = videoFrame.getRedCLBuffer(this);
            CLBuffer<FloatBuffer> rOut = resultVideoFrame.getRedCLBuffer(this);
            warpeChannel(rIn, rOut, width, height);

            CLBuffer<FloatBuffer> gIn = videoFrame.getGreenCLBuffer(this);
            CLBuffer<FloatBuffer> gOut = resultVideoFrame.getGreenCLBuffer(this);
            warpeChannel(gIn, gOut, width, height);

            CLBuffer<FloatBuffer> bIn = videoFrame.getBlueCLBuffer(this);
            CLBuffer<FloatBuffer> bOut = resultVideoFrame.getBlueCLBuffer(this);
            warpeChannel(bIn, bOut, width, height);

            return resultVideoFrame;
        }

        if (speed > NORMAL) {
            if (fastImageMatrix == null) {
                return videoFrame;
            }
            int xMax = fastImageMatrix.length;
            int yMax = fastImageMatrix[0].length;

            VideoFrame newVideoFrame = new VideoFrame(videoFrame.getWidth(), videoFrame.getHeight());

            for (int x = 0; x < xMax; x++) {
                for (int y = 0; y < yMax; y++) {
                    if (fastImageMatrix[x][y][2] != 1) {
                        continue;
                    }
                    newVideoFrame.setRGB(x, y,
                            videoFrame.getRGB(fastImageMatrix[x][y][0], fastImageMatrix[x][y][1]));
                }
            }
            return newVideoFrame;
        }

        if (imageMatrix == null) {
            return videoFrame;
        }
        VideoFrame newVideoFrame = new VideoFrame(videoFrame.getWidth(), videoFrame.getHeight());

        for (int x = 0; x < imageMatrix.length; x++) {
            for (int y = 0; y < imageMatrix[x].length; y++) {
                if (imageMatrix[x][y] == null) {
                    continue;
                }
                try {
                    if (speed == NORMAL || imageMatrix[x][y].length == 1) {
                        newVideoFrame.setRGB(x, y,
                                videoFrame.getRGB(imageMatrix[x][y][0].x, imageMatrix[x][y][0].y));
                        continue;
                    }
                    for (int i = 0; i < imageMatrix[x][y].length; i++) {
                        newVideoFrame.addColor(x, y,
                                videoFrame.getRGB(imageMatrix[x][y][i].x, imageMatrix[x][y][i].y));
                    }
                    newVideoFrame.divide(x, y, imageMatrix[x][y].length);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("x=" + x + " y=" + y);
                    return null;
                }
            }
        }
        return newVideoFrame;
    }

    public static class Point {
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int x;
        public int y;
    }

    @Override
    public void openConfigPanel() {
        new WarpingControl(this);
    }

    @Override
    public void getConfig(Element element) {
        element.setAttribute("pointTLx", String.valueOf(pointTL.x));
        element.setAttribute("pointTLy", String.valueOf(pointTL.y));
        element.setAttribute("pointBLx", String.valueOf(pointBL.x));
        element.setAttribute("pointBLy", String.valueOf(pointBL.y));
        element.setAttribute("pointTRx", String.valueOf(pointTR.x));
        element.setAttribute("pointTRy", String.valueOf(pointTR.y));
        element.setAttribute("pointBRx", String.valueOf(pointBR.x));
        element.setAttribute("pointBRy", String.valueOf(pointBR.y));
    }

    @Override
    public void setConfig(Element element) {
        String pointTLx = element.getAttribute("pointTLx").getValue();
        String pointTLy = element.getAttribute("pointTLy").getValue();
        String pointBLx = element.getAttribute("pointBLx").getValue();
        String pointBLy = element.getAttribute("pointBLy").getValue();
        String pointTRx = element.getAttribute("pointTRx").getValue();
        String pointTRy = element.getAttribute("pointTRy").getValue();
        String pointBRx = element.getAttribute("pointBRx").getValue();
        String pointBRy = element.getAttribute("pointBRy").getValue();

        if (pointTLx != null && pointTLy != null && pointBLx != null && pointBLy != null && pointTRx != null
                && pointTRy != null && pointBRx != null && pointBRy != null) {
            int pointTLxInt = Integer.parseInt(pointTLx);
            int pointTLyInt = Integer.parseInt(pointTLy);
            Point pointTL = new Point(pointTLxInt, pointTLyInt);

            int pointBLxInt = Integer.parseInt(pointBLx);
            int pointBLyInt = Integer.parseInt(pointBLy);
            Point pointBL = new Point(pointBLxInt, pointBLyInt);

            int pointTRxInt = Integer.parseInt(pointTRx);
            int pointTRyInt = Integer.parseInt(pointTRy);
            Point pointTR = new Point(pointTRxInt, pointTRyInt);

            int pointBRxInt = Integer.parseInt(pointBRx);
            int pointBRyInt = Integer.parseInt(pointBRy);
            Point pointBR = new Point(pointBRxInt, pointBRyInt);
            setWarp(pointTL, pointTR, pointBR, pointBL);
        }
    }

}