Package com.googlecode.javacv

Source Code of com.googlecode.javacv.ReflectanceInitializer

/*
* Copyright (C) 2009,2010,2011 Samuel Audet
*
* This file is part of JavaCV.
*
* JavaCV 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 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* JavaCV 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 JavaCV.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.googlecode.javacv;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.logging.Logger;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;

/**
*
* @author Samuel Audet
*/
public class ReflectanceInitializer {

    public ReflectanceInitializer(CameraDevice cameraDevice, ProjectorDevice projectorDevice,
            int channels, GNImageAligner.Settings alignerSettings) {
        this(cameraDevice, projectorDevice, channels, alignerSettings, 51, 0.01);
    }
    public ReflectanceInitializer(CameraDevice cameraDevice, ProjectorDevice projectorDevice,
            int channels, GNImageAligner.Settings alignerSettings, int smoothingSize, double reflectanceMin) {
        this.alignerSettings = alignerSettings;
        this.smoothingSize   = smoothingSize;
        this.reflectanceMin  = reflectanceMin;
        this.cameraDevice    = cameraDevice;
        this.projectorDevice = projectorDevice;
        this.projectorImages = new IplImage[3];

        for (int i = 0; i < projectorImages.length; i++) {
            projectorImages[i] = IplImage.create(projectorDevice.imageWidth,
                    projectorDevice.imageHeight, IPL_DEPTH_32F, channels);
        }

        // capture "black" image (illuminated by ambient light only)
        cvSetZero(projectorImages[0]);
        // capture "white" image (projector illumination + ambient light)
        cvSet(projectorImages[1], CvScalar.ONE);
        // capture image with some texture easy to register... ugh...
        CvMat H = mat3x3.get();
        projectorDevice.getRectifyingHomography(cameraDevice, H);
        JavaCV.fractalTriangleWave(projectorImages[2], H);
    }

    private static ThreadLocal<CvMat>
            mat3x1 = CvMat.createThreadLocal(3, 1),
            mat3x3 = CvMat.createThreadLocal(3, 3);

    private GNImageAligner.Settings alignerSettings;
    private int smoothingSize;
    private double reflectanceMin;
    private CameraDevice cameraDevice;
    private ProjectorDevice projectorDevice;
    private IplImage[] projectorImages;

    public IplImage[] getProjectorImages() {
        return projectorImages;
    }

    public IplImage initializeReflectance(IplImage[] cameraImages, double[] roiPts, double[] ambientLight) {
        int w        = cameraImages[0].width();
        int h        = cameraImages[0].height();
        int channels = cameraImages[0].nChannels();

        IplImage roiMask = IplImage.create(w, h, IPL_DEPTH_8U, 1);
        cvSetZero(roiMask);
        cvFillConvexPoly(roiMask, new CvPoint((byte)16, roiPts), 4, CvScalar.WHITE, 8, 16);

        // make the images very very smooth to compensate for small movements
        IplImage float1 = cameraImages[0];
        IplImage float2 = cameraImages[1];
        IplImage reflectance = float2.clone();
        cvSmooth(float1, float1, CV_GAUSSIAN, smoothingSize, 0, 0, 0);
        cvSmooth(float2, float2, CV_GAUSSIAN, smoothingSize, 0, 0, 0);

        // remove ambient light of image1 from image2 -> image2
        cvSub(float2, float1, float2, null);

        // remove distortion caused by the mixing matrix of the projector light
        // and recover (very very smooth) reflectance map
        CvMat p    = mat3x1.get();
        CvMat invp = mat3x3.get();
        p.put(1.0, 1.0, 1.0); // white
        cvMatMul(projectorDevice.colorMixingMatrix, p, p);
        invp.put(1/p.get(0), 0, 0,
                 0, 1/p.get(1), 0,
                 0, 0, 1/p.get(2));
        cvTransform(float2, float2, invp, null);

        // recover (very very smooth) ambient light by removing distortions
        // caused by the reflectance map
        // cvDiv(image1, image3, image1, 1);
        // cvDiv() doesn't support division by zero...
        FloatBuffer fb1 = float1.getFloatBuffer();
        FloatBuffer fb2 = float2.getFloatBuffer();
        ByteBuffer  rmb = roiMask.getByteBuffer();
        assert(fb1.capacity() == fb2.capacity()/3);
        assert(fb1.capacity() == rmb.capacity()/3);
        int[] nPixels = new int[channels];
        for (int i = 0, j = 0; j < fb1.capacity(); i++, j+=channels) {
            for (int z = 0; z < channels; z++) {
                float ra = fb1.get(j+z);
                float r  = fb2.get(j+z);
                float a  = ra/r;
                fb1.put(j+z, a);
                if (rmb.get(i) != 0) {
                    if (r > reflectanceMin) {
                        nPixels[z]++;
                        ambientLight[z] += a;
                    }
                }
            }
        }
        for (int z = 0; z < channels; z++) {
            ambientLight[z] = nPixels[z] == 0 ? 0 : ambientLight[z]/nPixels[z];
        }
//        System.out.println(ambientLight[0] + " " + ambientLight[1] + " " + ambientLight[2]);

        // recover sharp reflectance map by using the original image2 and smooth ambient light
        cvAddS(float1, cvScalar(p.get(0), p.get(1), p.get(2), 0.0), float1, null);
        cvDiv(reflectance, float1, reflectance, 1.0);

        cvNot(roiMask, roiMask);
        // increase region a bit so that the resulting image can be
        // interpolated or averaged properly within the region of interest...
        cvErode(roiMask, roiMask, null, 15);
        cvSet(reflectance, CvScalar.ZERO, roiMask);

        return reflectance;
    }

    public CvMat initializePlaneParameters(IplImage[] cameraImages, IplImage reflectance,
            double[] roiPts, double[] ambientLight) {
        ProCamTransformer transformer = new ProCamTransformer(roiPts, cameraDevice, projectorDevice, null);
        transformer.setProjectorImage(projectorImages[2], alignerSettings.pyramidLevels);

        ProCamTransformer.Parameters parameters = transformer.createParameters();
//        parameters.set(8,  0);
//        parameters.set(9,  0);
//        parameters.set(10, -1/cameraDevice.getSettings().nominalDistance);
        parameters.set(11, 1.0);
        for (int i = 0; i < ambientLight.length; i++) {
            parameters.set(12+i, ambientLight[i]);
        }
        ImageAligner aligner = new GNImageAligner(transformer, parameters,
                reflectance, roiPts, cameraImages[2], alignerSettings);

        double[] delta = new double[parameters.size()+1];
        boolean converged = false;
        long iterationsStartTime = System.currentTimeMillis();
        int iterations = 0;
        while (!converged && iterations < 100) {
            converged = aligner.iterate(delta);
            iterations++;
        }
        parameters = (ProCamTransformer.Parameters)aligner.getParameters();
        Logger.getLogger(ReflectanceInitializer.class.getName()).info(
            "iteratingTime = " + (System.currentTimeMillis()-iterationsStartTime) +
                "  iterations = " + iterations + "  objectiveRMSE = " + (float)aligner.getRMSE());
        return parameters.getSrcN();
    }

}
TOP

Related Classes of com.googlecode.javacv.ReflectanceInitializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.