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 }