All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bytedeco.javacv.Marker Maven / Gradle / Ivy

There is a newer version: 1.5.10
Show newest version
/*
 * Copyright (C) 2009,2010,2011,2012 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 .
 */

package org.bytedeco.javacv;

import java.nio.ByteBuffer;
import java.util.Arrays;

import static org.bytedeco.javacpp.ARToolKitPlus.*;
import static org.bytedeco.javacpp.opencv_core.*;

/**
 *
 * @author Samuel Audet
 */
public class Marker implements Cloneable {
    public Marker(int id, double[] corners, double confidence) {
        this.id = id;
        this.corners = corners;
        this.confidence = confidence;
    }
    public Marker(int id, double ... corners) {
        this(id, corners, 1.0);
    }
    @Override public Marker clone() {
        return new Marker(id, corners.clone(), confidence);
    }
    public int id;
    public double[] corners;
    public double confidence;

    @Override public int hashCode() {
        int hash = 7;
        hash = 37 * hash + this.id;
        hash = 37 * hash + (this.corners != null ? this.corners.hashCode() : 0);
        return hash;
    }
    @Override public boolean equals(Object o) {
        if (o instanceof Marker) {
            Marker m = (Marker)o;
            return m.id == id && Arrays.equals(m.corners, corners);
        }
        return false;
    }

    public double[] getCenter() {
        double x = 0, y = 0;
if (true) {
// the centroid is not what we want as it does not remain at
// the same physical point under projective transformations..
// But it has the advantage of averaging noise better, and does
// give better results
        for (int i = 0; i < 4; i++) {
            x += corners[2*i  ];
            y += corners[2*i+1];
        }
        x /= 4;
        y /= 4;
} else {
        double x1 = corners[0]; double y1 = corners[1];
        double x2 = corners[4]; double y2 = corners[5];
        double x3 = corners[2]; double y3 = corners[3];
        double x4 = corners[6]; double y4 = corners[7];

        double u = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3))/
                   ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
        x = x1 + u*(x2-x1);
        y = y1 + u*(y2-y1);
}
        return new double[] { x, y };
    }

    public IplImage getImage() {
        return getImage(id);
    }

    private static IplImage imageCache[] = new IplImage[4096];
    public static IplImage getImage(int id) {
        if (imageCache[id] == null) {
            imageCache[id] = IplImage.create(8, 8, IPL_DEPTH_8U, 1);
            createImagePatternBCH(id, imageCache[id].getByteBuffer());
        }
        return imageCache[id];
    }

    private static final double[] src = { 0, 0, 8, 0, 8, 8, 0, 8 };
    public void draw(IplImage image) {
        draw(image, CvScalar.BLACK, 1, null);
    }
    public void draw(IplImage image, CvScalar color, double scale, CvMat prewarp) {
        draw(image, color, scale, scale, prewarp);
    }
    private static ThreadLocal
            H3x3      = CvMat.createThreadLocal(3, 3),
            srcPts4x1 = CvMat.createThreadLocal(4, 1, CV_64F, 2),
            dstPts4x1 = CvMat.createThreadLocal(4, 1, CV_64F, 2);
    public void draw(IplImage image, CvScalar color, double scaleX, double scaleY, CvMat prewarp) {
        CvMat H = H3x3.get();
        JavaCV.getPerspectiveTransform(src, corners, H);
        if (prewarp != null) {
            cvGEMM(prewarp, H, 1, null, 0, H, 0);
        }
        IplImage  marker = getImage();
        ByteBuffer  mbuf = marker.getByteBuffer();
        CvMat     srcPts = srcPts4x1.get();
        CvMat     dstPts = dstPts4x1.get();
        CvPoint  tempPts = new CvPoint(4);

        int h = marker.height();
        int w = marker.width();
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                if (mbuf.get(y*w + x) == 0) {
                    srcPts.put((double)x, y,  x+1, y,  x+1, y+1,  x, y+1);
                    //System.out.println("srcPts" + srcPts);
                    cvPerspectiveTransform(srcPts, dstPts, H);
                    //System.out.println("dstPts" + dstPts);

                    double centerx = 0, centery = 0;
                    for (int i = 0; i < 4; i++) {
                      centerx += dstPts.get(i*2  );
                      centery += dstPts.get(i*2+1);
                    }
                    centerx /= 4;
                    centery /= 4;
                    for (int i = 0; i < 4; i++) {
                        double a = dstPts.get(i*2  );
                        double b = dstPts.get(i*2+1);
                        double dx = centerx - a;
                        double dy = centery - b;
                        dx = dx < 0 ? -1 : 0;
                        dy = dy < 0 ? -1 : 0;
                        tempPts.position(i).x((int)Math.round((a*scaleX + dx) * (1<<16)));
                        tempPts.position(i).y((int)Math.round((b*scaleY + dy) * (1<<16)));
                    }
                    cvFillConvexPoly(image, tempPts.position(0), 4, color, 8/*CV_AA*/, 16);
                }
            }
        }
    }

    public static class ArraySettings extends BaseChildSettings {
        int rows = 8, columns = 12;
        double sizeX = 200, sizeY = 200, spacingX = 300, spacingY = 300;
        boolean checkered = true;

        public int getRows() {
            return rows;
        }
        public void setRows(int rows) {
            firePropertyChange("rows", this.rows, this.rows = rows);
        }

        public int getColumns() {
            return columns;
        }
        public void setColumns(int columns) {
            firePropertyChange("columns", this.columns, this.columns = columns);
        }

        public double getSizeX() {
            return sizeX;
        }
        public void setSizeX(double sizeX) {
            firePropertyChange("sizeX", this.sizeX, this.sizeX = sizeX);
        }
        public double getSizeY() {
            return sizeY;
        }
        public void setSizeY(double sizeY) {
            firePropertyChange("sizeY", this.sizeY, this.sizeY = sizeY);
        }

        public double getSpacingX() {
            return spacingX;
        }
        public void setSpacingX(double spacingX) {
            firePropertyChange("spacingX", this.spacingX, this.spacingX = spacingX);
        }
        public double getSpacingY() {
            return spacingY;
        }
        public void setSpacingY(double spacingY) {
            firePropertyChange("spacingY", this.spacingY, this.spacingY = spacingY);
        }

        public boolean isCheckered() {
            return checkered;
        }
        public void setCheckered(boolean checkered) {
            firePropertyChange("checkered", this.checkered, this.checkered = checkered);
        }
    }
    public static Marker[][] createArray(ArraySettings settings) {
        return createArray(settings, 0, 0);
    }
    public static Marker[][] createArray(ArraySettings settings, double marginx, double marginy) {
        Marker[] markers = new Marker[settings.rows*settings.columns];
        int id = 0;
        for (int y = 0; y < settings.rows; y++) {
            for (int x = 0; x < settings.columns; x++) {
                double sx =   settings.sizeX/2;
                double sy =   settings.sizeY/2;
                double cx = x*settings.spacingX + sx + marginx;
                double cy = y*settings.spacingY + sy + marginy;
                markers[id] = new Marker(id, new double[] {
                    cx-sx, cy-sy,  cx+sx, cy-sy,  cx+sx, cy+sy,  cx-sx, cy+sy }, 1);
                id++;
            }
        }
        if (!settings.checkered) {
            return new Marker[][] { markers };
        } else {
            Marker[] markers1 = new Marker[markers.length/2];
            Marker[] markers2 = new Marker[markers.length/2];
            for (int i = 0; i < markers.length; i++) {
                int x = i%settings.columns;
                int y = i/settings.columns;
                if (x%2==0 ^ y%2==0) {
                    markers2[i/2] = markers[i];
                } else {
                    markers1[i/2] = markers[i];
                }
            }
            return new Marker[][] { markers2, markers1 };
        }
    }
    public static Marker[][] createArray(int rows, int columns, double sizeX, double sizeY,
            double spacingX, double spacingY, boolean checkered, double marginx, double marginy) {
        ArraySettings s = new ArraySettings();
        s.rows      = rows;      s.columns  = columns;
        s.sizeX     = sizeX;     s.sizeY    = sizeY;
        s.spacingX  = spacingX;  s.spacingY = spacingY;
        s.checkered = checkered;
        return createArray(s, marginx, marginy);
    }

    public static void applyWarp(Marker[] markers, CvMat warp) {
        CvMat pts = srcPts4x1.get();

        for (Marker m : markers) {
            cvPerspectiveTransform(pts.put(m.corners), pts, warp);
            pts.get(m.corners);
        }
    }

    @Override public String toString() {
        String s = "[" + id + ": " +
                "(" + corners[0] + ", " + corners[1] + ") " +
                "(" + corners[2] + ", " + corners[3] + ") " +
                "(" + corners[4] + ", " + corners[5] + ") " +
                "(" + corners[6] + ", " + corners[7] + ")]";
        return s;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy