1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package violajones.attic; 26 27 28 import hat.buffer.F32Array2D; 29 import violajones.XMLHaarCascadeModel; 30 import violajones.ifaces.Cascade; 31 import violajones.ifaces.ResultTable; 32 import violajones.ifaces.ScaleTable; 33 34 35 public class ReferenceJavaViolaJones extends CoreJavaViolaJones { 36 static boolean isAFaceStage( 37 float scale, float invArea, 38 int x, 39 int y, 40 float vnorm, 41 F32Array2D integral, 42 Cascade.Stage stage, 43 Cascade cascade) { 44 float sumOfThisStage = 0; 45 int startTreeIdx = stage.firstTreeId(); 46 int endTreeIdx = startTreeIdx + stage.treeCount(); 47 for (int treeIdx = startTreeIdx; treeIdx < endTreeIdx; treeIdx++) { 48 Cascade.Tree tree = cascade.tree(treeIdx); 49 Cascade.Feature feature = cascade.feature(tree.firstFeatureId()); 50 while (feature != null) { 51 float featureGradientSum = .0f; 52 53 for (int r = 0; r < 3; r++) { 54 Cascade.Feature.Rect rect = feature.rect(r); 55 56 float g = gradient(integral, 57 x + (int) (rect.x() * scale), y + (int) (rect.y() * scale), 58 (int) (rect.width() * scale), (int) (rect.height() * scale)) * 59 rect.weight(); // we assume weight is 0 for unused ;) 60 featureGradientSum += g; 61 } 62 if ((featureGradientSum * invArea) < (feature.threshold() * vnorm)) {//left 63 var left = feature.left(); 64 if (left.hasValue()) { 65 sumOfThisStage += left.anon().value(); 66 feature = null; 67 } else { 68 feature = cascade.feature(tree.firstFeatureId() + left.anon().featureId()); 69 70 } 71 } else {//right 72 var right = feature.right(); 73 if (right.hasValue()) { 74 sumOfThisStage += right.anon().value(); 75 feature = null; 76 } else { 77 feature = cascade.feature(tree.firstFeatureId() + right.anon().featureId()); 78 } 79 } 80 } 81 } 82 return sumOfThisStage > stage.threshold(); 83 } 84 85 static boolean isAFaceStageHaar( 86 87 float scale, float invArea, 88 int x, 89 int y, 90 float vnorm, 91 F32Array2D integral, 92 XMLHaarCascadeModel.Stage stage, 93 XMLHaarCascadeModel haarCascade 94 ) { 95 float sumOfThisStage = 0; 96 97 int startTreeIdx = stage.firstTreeId(); 98 int endTreeIdx = startTreeIdx + stage.treeCount(); 99 for (int treeIdx = startTreeIdx; treeIdx < endTreeIdx; treeIdx++) { 100 XMLHaarCascadeModel.Tree tree = haarCascade.trees.get(treeIdx); 101 // Cascade.Tree tree = cascade.tree(treeIdx); 102 103 104 XMLHaarCascadeModel.Feature feature = haarCascade.features.get(tree.firstFeatureId); 105 while (feature != null) { 106 float featureGradientSum = .0f; 107 for (XMLHaarCascadeModel.Feature.Rect r : feature.rects) { 108 if (r != null) { 109 float g = gradient(integral, 110 x + (int) (r.x() * scale), y + (int) (r.y() * scale), 111 (int) (r.width() * scale), (int) (r.height() * scale)) * 112 r.weight(); 113 featureGradientSum += g; 114 } 115 } 116 if ((featureGradientSum * invArea) < (feature.threshold() * vnorm)) {//left 117 if (feature.left.hasValue()) { 118 sumOfThisStage += feature.left.value(); 119 feature = null; 120 } else { 121 feature = haarCascade.features.get(tree.firstFeatureId() + feature.left.featureId()); 122 } 123 } else {//right 124 if (feature.right.hasValue()) { 125 sumOfThisStage += feature.right.value(); 126 feature = null; 127 } else { 128 feature = haarCascade.features.get(tree.firstFeatureId() + feature.right.featureId()); 129 // feature = tree.features.get(feature.right.featureId()); 130 } 131 } 132 } 133 134 } 135 return sumOfThisStage > stage.threshold; 136 } 137 138 static void findFeatures(int gid, 139 Cascade cascade, 140 F32Array2D integral, 141 F32Array2D integralSq, 142 ScaleTable scaleTable, 143 ResultTable resultTable 144 145 ) { 146 if (gid < scaleTable.multiScaleAccumulativeRange()) { 147 148 int scalc = 0; 149 ScaleTable.Scale scale = scaleTable.scale(scalc++); 150 for (; 151 gid >= scale.accumGridSizeMax(); 152 scale = scaleTable.scale(scalc++)) 153 ; 154 int scaleGid = gid - scale.accumGridSizeMin(); 155 int x = (int) ((scaleGid % scale.gridWidth()) * scale.scaledXInc()); 156 int y = (int) ((scaleGid / scale.gridWidth()) * scale.scaledYInc()); 157 float integralGradient = gradient(integral, x, y, scale.scaledFeatureWidth(), scale.scaledFeatureHeight()) * scale.invArea(); 158 float integralSqGradient = gradient(integralSq, x, y, scale.scaledFeatureWidth(), scale.scaledFeatureHeight()) * scale.invArea(); 159 160 float vnorm = integralSqGradient - integralGradient * integralGradient; 161 vnorm = (vnorm > 1) ? (float) Math.sqrt(vnorm) : 1; 162 boolean stillLooksLikeAFace = true; 163 if (cascade instanceof XMLHaarCascadeModel haarCascade) { 164 for (XMLHaarCascadeModel.Stage stage : haarCascade.stages) { 165 if (!(stillLooksLikeAFace = isAFaceStageHaar( 166 scale.scaleValue(), scale.invArea(), x, y, vnorm, integral, stage, haarCascade))) { 167 break; 168 } 169 } 170 } else { 171 int stageCount = cascade.stageCount(); 172 for (int stagec = 0; stagec < stageCount; stagec++) { 173 Cascade.Stage stage = cascade.stage(stagec); 174 if (!(stillLooksLikeAFace = isAFaceStage( 175 scale.scaleValue(), scale.invArea(), x, y, vnorm, integral, stage, cascade))) { 176 177 break; 178 } 179 } 180 } 181 if (stillLooksLikeAFace) { 182 int index = resultTable.atomicResultTableCount(); 183 index++; 184 resultTable.atomicResultTableCount(index); 185 System.out.println("face at " + x + "," + y); 186 if (index < resultTable.length()) { 187 ResultTable.Result result = resultTable.result(index); 188 result.x(x); 189 result.y(y); 190 result.width(scale.scaledFeatureWidth()); 191 result.height(scale.scaledFeatureWidth()); 192 } 193 } 194 } 195 } 196 197 }