Commit 430ae275 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '323-fix-bugs-found-by-testing-pre-release-2024-07-5' into 'master'

Resolve "Fix bugs found by testing pre-release 2024.07.5"

Closes #323

See merge request grp-fidentis/analyst2!349
parents 2dc95ab1 c67a1b7e
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -117,8 +117,8 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
                break;
            
            case FeaturePointsPanel.ACTION_FILL_NAME_AND_DESCRIPTION:
                getControlPanel().setNameText(selectedFeaturePoints.get(0).getName());
                getControlPanel().setDescriptionText(selectedFeaturePoints.get(0).getDescription());
                getControlPanel().setNameText(selectedFeaturePoints.getFirst().getName());
                getControlPanel().setDescriptionText(selectedFeaturePoints.getFirst().getDescription());
                break;
                
            case FeaturePointsPanel.ACTION_SAVE_CHANGES:
@@ -218,7 +218,7 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>

            } else if (closestIntersection != null && workingFpMode.equals(ENABLE_CHANGE_FP_POSITION)) {
                for (Landmark fp : getPrimaryFeaturePoints().getFeaturePoints()) {
                    if (fp.equals(selectedFeaturePoints.get(0))) {
                    if (fp.equals(selectedFeaturePoints.getFirst())) {
                        fp.setPosition(closestIntersection.getPosition());
                        fp.setMeshVicinity(new MeshVicinity(0, closestIntersection.getPosition()));
                    }
@@ -249,7 +249,7 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
            getPrimaryFeaturePoints().setColor(index, getPrimaryFeaturePoints().getAssignedColor(index));
            setColorsOfFeaturePoints();
            if (selectedFeaturePoints.size() == 1) {
                getControlPanel().updateFpDescription(selectedFeaturePoints.get(0), true);
                getControlPanel().updateFpDescription(selectedFeaturePoints.getFirst(), true);
            } else {
                getControlPanel().updateFpDescription(fp, false);
            }
@@ -361,12 +361,12 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
        String newDesc = getControlPanel().getDescriptionText();
        String newName = getControlPanel().getNameText();
        for (Landmark fp : getPrimaryFeaturePoints().getFeaturePoints()) {
            if (fp.equals(selectedFeaturePoints.get(0))) {
            if (fp.equals(selectedFeaturePoints.getFirst())) {
                fp.setName(newName);
                fp.setDescription(newDesc);
            }
        }
        getControlPanel().updateFpDescription(selectedFeaturePoints.get(0), true);
        getControlPanel().updateFpDescription(selectedFeaturePoints.getFirst(), true);
        getControlPanel().getFeaturePointListPanel().refreshPanel(this, getPrimaryFeaturePoints(), selectedFeaturePoints);
    }
    
@@ -383,7 +383,7 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
        } else if (ae.getSource() == getControlPanel().getAddSecondaryFpButton()) {
            String fptName = getControlPanel().getNewSecondaryFpName().getText();
            List<Landmark> customFps = getPrimaryFace().getCustomLandmarks();
            int index = (customFps.isEmpty()) ? 0 : customFps.get(customFps.size() - 1).getType() + 1;
            int index = (customFps.isEmpty()) ? 0 : customFps.getLast().getType() + 1;
            Landmark fp = LandmarksFactory.createLandmark(index, workingFP.getPosition(), fptName, "");
            fp.setMeshVicinity(new MeshVicinity(0, workingFP.getPosition()));
            getPrimaryFeaturePoints().addFeaturePoint(fp);
@@ -445,7 +445,7 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
        if (getPrimaryFace().hasLandmarks()) {
            JOptionPane.showMessageDialog(
                    getCanvas(),
                    "Currently, this function is available only if there are no landmarks defined yet.");
                    "Currently, this function is available only if there are no feature points defined yet.");
            return Collections.emptyList();
        }

@@ -479,7 +479,7 @@ public class FeaturePointsAction extends ControlPanelAction<FeaturePointsPanel>
        getCanvas().setState(state);

        if (result.isEmpty()) {
            JOptionPane.showMessageDialog(getCanvas(), "Detection was no successful");
            JOptionPane.showMessageDialog(getCanvas(), "Detection was not successful");
        }

        return result;
+66 −52
Original line number Diff line number Diff line
@@ -9,8 +9,10 @@ import cz.fidentis.analyst.data.face.HumanFaceListener;
import cz.fidentis.analyst.data.face.HumanFaceState;
import cz.fidentis.analyst.data.landmarks.Landmark;
import cz.fidentis.analyst.data.mesh.impl.MeshTriangleImpl;
import cz.fidentis.analyst.drawables.DrawableFeaturePoints;
import cz.fidentis.analyst.drawables.DrawablePointCloud;
import cz.fidentis.analyst.engines.face.FaceRegistrationServices;
import cz.fidentis.analyst.engines.face.FaceStateServices;
import cz.fidentis.analyst.engines.face.events.HumanFaceTransformedEvent;
import cz.fidentis.analyst.engines.face.events.LandmarksChangedEvent;
import cz.fidentis.analyst.engines.face.events.MeshDistanceComputed;
@@ -22,9 +24,9 @@ import cz.fidentis.analyst.engines.sampling.PointSamplingVisitor;
import cz.fidentis.analyst.engines.symmetry.SymmetryConfig;
import cz.fidentis.analyst.gui.elements.SpinSlider;
import cz.fidentis.analyst.gui.task.ControlPanelAction;
import cz.fidentis.analyst.landmarks.LandmarksDetector;
import cz.fidentis.analyst.opencl.OpenCLServices;
import cz.fidentis.analyst.project.FacesProxy;
import cz.fidentis.analyst.landmarks.LandmarksDetector;

import javax.swing.*;
import javax.vecmath.Vector3d;
@@ -346,31 +348,29 @@ public class RegistrationAction extends ControlPanelAction<RegistrationPanel> im
    }

    private void alignDetection() {
        Logger out = Logger.measureTime();

        // Detect faces and add landmarks
        List<Landmark> priLandmarks = new ArrayList<>();
        List<Landmark> secLandmarks = new ArrayList<>();
        detectAndAddLandmarks(priLandmarks, secLandmarks);

        if (priLandmarks.isEmpty() || secLandmarks.isEmpty()) {
            JOptionPane.showMessageDialog(new JFrame("Face detection has failed"),
                    "Not enough feature points detected on both faces");
        List<Landmark> priModelLandmarks = new ArrayList<>();
        boolean priModelPredefinedFPs = getOrDetectLandmarks(
                priModelLandmarks,
                getCanvas().getScene().getPrimaryFaceSlot());

        List<Landmark> secModelLandmarks = new ArrayList<>();
        boolean secModelPredefinedFPs = getOrDetectLandmarks(
                secModelLandmarks,
                getCanvas().getScene().getSecondaryFaceSlot());

        if (priModelLandmarks.isEmpty() || secModelLandmarks.isEmpty()) {
            JOptionPane.showMessageDialog(new JFrame("Landmarks detection failed"),
                    "Not enough feature points detected or predefined on both models");
            return;
        }

        out.printDuration(
                "Detection of landmarks for models with "
                        + getPrimaryFace().getMeshModel().getNumVertices()
                        + "/"
                        + getSecondaryFace().getMeshModel().getNumVertices()
                        + " vertices"
        );
        out = Logger.measureTime();

        // TO DO: what if there are landmarks already defined?
        priLandmarks.forEach(landmark -> getPrimaryFace().addCustomLandmark(landmark));
        secLandmarks.forEach(landmark -> getSecondaryFace().addCustomLandmark(landmark));
        // Add auto-detected feature points into faces temporarily
        if (!priModelPredefinedFPs) {
            priModelLandmarks.forEach(landmark -> getPrimaryFace().addCustomLandmark(landmark));
        }
        if (!secModelPredefinedFPs) {
            secModelLandmarks.forEach(landmark -> getSecondaryFace().addCustomLandmark(landmark));
        }

        // Align using acquired feature points
        FaceRegistrationServices.alignFeaturePoints(
@@ -379,25 +379,20 @@ public class RegistrationAction extends ControlPanelAction<RegistrationPanel> im
                getControlPanel().getScaleParam()
        );

        // TO DO: what if there are landmarks already defined?
        priLandmarks.forEach(landmark -> getPrimaryFace().removeCustomLandmark(landmark));
        secLandmarks.forEach(landmark -> getSecondaryFace().removeCustomLandmark(landmark));

        out.printDuration("Procrustes (Detection) for models with "
                + getPrimaryFace().getMeshModel().getNumVertices()
                + "/"
                + getSecondaryFace().getMeshModel().getNumVertices()
                + " vertices and "
                + getPrimaryFace().getAllLandmarks().size()
                + " feature points"
        );
        out = Logger.measureTime();
        // Remove auto-detected feature points from faces
        if (!priModelPredefinedFPs) {
            priModelLandmarks.forEach(landmark -> getPrimaryFace().removeCustomLandmark(landmark));
        }
        if (!secModelPredefinedFPs) {
            secModelLandmarks.forEach(landmark -> getSecondaryFace().removeCustomLandmark(landmark));
        }

        // Align using ICP
        HumanFace body = getPrimaryFace();
        HumanFace face = getSecondaryFace();

        if (getPrimaryFace().getBoundingBox().diagonalLength() < getSecondaryFace().getBoundingBox().diagonalLength()) {
        FaceStateServices.updateBoundingBox(body, FaceStateServices.Mode.COMPUTE_IF_ABSENT);
        FaceStateServices.updateBoundingBox(face, FaceStateServices.Mode.COMPUTE_IF_ABSENT);
        if (body.getBoundingBox().diagonalLength() < face.getBoundingBox().diagonalLength()) {
            body = getSecondaryFace();
            face = getPrimaryFace();
        }
@@ -413,14 +408,6 @@ public class RegistrationAction extends ControlPanelAction<RegistrationPanel> im
                        samplingStrategy,
                        getControlPanel().getIcpAutoCropParam() ? 0 : -1));

        out.printDuration("ICP (Detection) for models with "
                + body.getMeshModel().getNumVertices()
                + "/"
                + face.getMeshModel().getNumVertices()
                + " vertices. Sub-sampling of the secondary face: "
                + samplingStrategy
        );

    }

    private PointSamplingConfig getSamplingStrategy() {
@@ -478,25 +465,52 @@ public class RegistrationAction extends ControlPanelAction<RegistrationPanel> im
        return cloudSlot;
    }

    protected void detectAndAddLandmarks(List<Landmark> priLandmarks, List<Landmark> secLandmarks) {
    /**
     * Returns either existing or auto-detected feature points.
     *
     * @param fpList output list
     * @param faceSlot face slot
     * @return {@code true} if pre-defined landmarks are used (put into the output list)
     */
    protected boolean getOrDetectLandmarks(List<Landmark> fpList, int faceSlot) {
        String modelName = getScene().getDrawableFace(faceSlot).getHumanFace().getShortName();

        DrawableFeaturePoints fps = getScene().getDrawableFeaturePoints(faceSlot);
        if (fps != null) {
            fpList.addAll(fps.getFeaturePoints().stream()
                    .filter(Landmark::isStandardFeaturePoint)
                    .toList());
        }
        if (!fpList.isEmpty()) { // return existing feature points
            Logger.print(modelName + ": Using existing feature points for pre-alignment.");
            return true;
        }

        // AUTODETECT:
        SymmetryConfig symmetryConfig = new SymmetryConfig(
                SymmetryConfig.Method.ROBUST_POINT_CLOUD,
                new PointSamplingConfig(UNIFORM_SPACE, 200),
                200);
        LandmarksDetector service = LandmarksDetector.getDetector(getCanvas());
        Logger out = Logger.measureTime();

        // save scene state
        CanvasState state = getCanvas().getState();

        // compute (the scene is changed)
        priLandmarks.addAll(service.recognizeFromMultipleAngles(
                getCanvas().getScene().getPrimaryFaceSlot(),
                symmetryConfig, MINIMAL_SIGNIFICANT_POINTS, X_ANGLE_ROTATION_INCREMENT));
        secLandmarks.addAll(service.recognizeFromMultipleAngles(
                getCanvas().getScene().getSecondaryFaceSlot(),
        fpList.addAll(service.recognizeFromMultipleAngles(
                faceSlot,
                symmetryConfig, MINIMAL_SIGNIFICANT_POINTS, X_ANGLE_ROTATION_INCREMENT));

        // restore scene state
        getCanvas().setState(state);

        if (fpList.isEmpty()) {
            out.printDuration(modelName + ": Auto-detection failed");
        } else {
            out.printDuration(modelName + ": Using auto-detected feature points");
        }

        return false;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ public class FaceToolbox extends Toolbox {
            addToPanel(initColorButton(16, 35, toolboxType));
        }
        //addToPanel(initSymmetryButton(faceSlot));
        //addToPanel(initLandmarksButton(faceSlot));
        addToPanel(initLandmarksButton(faceSlot));
        addToPanel(initFaceButton(faceSlot, toolboxType.getIcon()));
        addToPanel(initSlider(faceSlot, toolboxType));
    }