1 2 # More Complex Interface Mapping Example - The Cascade 3 4 ---- 5 6 * [Contents](hat-00.md) 7 * House Keeping 8 * [Project Layout](hat-01-01-project-layout.md) 9 * [Building Babylon](hat-01-02-building-babylon.md) 10 * [Building HAT](hat-01-03-building-hat.md) 11 * Programming Model 12 * [Programming Model](hat-03-programming-model.md) 13 * Interface Mapping 14 * [Interface Mapping Overview](hat-04-01-interface-mapping.md) 15 * [Cascade Interface Mapping](hat-04-02-cascade-interface-mapping.md) 16 * Implementation Detail 17 * [Walkthrough Of Accelerator.compute()](hat-accelerator-compute.md) 18 19 ---- 20 21 # More Complex Interface Mapping Example - The Cascade 22 23 Previously we showed probably the minimal useful mapping with S32Array 24 25 The HaarCascade example has multiple nested interfaces representing data 26 structures involving various nested structs and unions 27 28 ```java 29 public interface Cascade extends Buffer { 30 int width(); 31 void width(int width); 32 int height(); 33 void height(int height); 34 interface Feature extends Buffer.StructChild { 35 int id(); 36 float threshold(); 37 void id(int id); 38 void threshold(float threshold); 39 interface LinkOrValue extends Buffer.StructChild { 40 interface Anon extends Buffer.UnionChild { 41 int featureId(); 42 void featureId(int featureId); 43 float value(); 44 void value(float value); 45 } 46 boolean hasValue(); 47 void hasValue(boolean hasValue); 48 Anon anon(); 49 } 50 LinkOrValue left(); 51 LinkOrValue right(); 52 interface Rect extends Buffer.StructChild { 53 byte x(); 54 byte y(); 55 byte width(); 56 byte height(); 57 float weight(); 58 void x(byte x); 59 void y(byte y); 60 void width(byte width); 61 void height(byte height); 62 void weight(float height); 63 } 64 Rect rect(long idx); 65 } 66 int featureCount(); 67 void featureCount(int featureCount); 68 Feature feature(long idx); 69 interface Stage extends Buffer.StructChild { 70 float threshold(); 71 short firstTreeId(); 72 short treeCount(); 73 int id(); 74 void id(int id); 75 void threshold(float threshold); 76 void firstTreeId(short firstTreeId); 77 void treeCount(short treeCount); 78 } 79 80 int stageCount(); 81 void stageCount(int stageCount); 82 Stage stage(long idx); 83 interface Tree extends Buffer.StructChild { 84 void id(int id); 85 void firstFeatureId(short firstFeatureId); 86 void featureCount(short featureCount); 87 int id(); 88 short firstFeatureId(); 89 short featureCount(); 90 } 91 int treeCount(); 92 void treeCount(int treeCount); 93 Tree tree(long idx); 94 Schema<Cascade> schema = Schema.of(Cascade.class, cascade -> cascade 95 .fields("width", "height") 96 .arrayLen("featureCount") 97 .array("feature", feature -> feature 98 .field("id") 99 .field("threshold") 100 .fields("left", "right", linkOrValue -> linkOrValue 101 .field("hasValue") 102 .pad(3) 103 .field("anon", anon -> anon 104 .field("featureId") 105 .field("value") 106 ) 107 ) 108 .array("rect", 3, rect -> rect 109 .field("x") 110 .field("y") 111 .field("width") 112 .field("height"). 113 .field("weight")) 114 ) 115 .arrayLen("treeCount") 116 .array("tree", tree -> tree 117 .field("id") 118 .field("featureCount") 119 .field("firstFeatureId") 120 ) 121 .arrayLen("stageCount") 122 .array("stage", stage -> stage 123 .field("id") 124 .field("threshold") 125 .field("treeCount") 126 .field("firstTreeId")) 127 ); 128 } 129 ``` 130 131 Another great advantage of using interfaces is that we can choose 132 to re implement the interface in any was we see fit. 133 134 For example we load HaarCascades from XML files. 135 We therefore can create an implementation of the Cascade interface which just 136 loads the XML DOM... stores them in arrays and the interface methods just delegate to 137 the appropriately wrapped w3c.Node tree nodes ;) 138 139 If we know we are using Java backend we can actually 140 just pass the XMLCascade implementation directly to the backend... 141 142 Actually the Cascade `create` method takes an existing 143 implementation of a Cascade and clones it. 144 So we can just pass it an XMLHaarCascade ;) 145 146 So we build an XMLCascade then pass it to the `create` method of the iface 147 mapped Cascade 148 149 ```java 150 XMLHaarCascadeModel haarCascade = XMLHaarCascadeModel.load( 151 ViolaJonesRaw.class.getResourceAsStream("haarcascade_frontalface_default.xml")); 152 153 assert haarCascade instanceof Cascade; // Here it is just an interface 154 155 Cascade cascade = Cascade.create(accelerator, haarCascade); 156 157 // Now it can be used on the GPU 158 ``` 159 160 The implementation is currently hand crafted, but this could easily be automated. 161 162 ```java 163 import java.lang.invoke.MethodHandles; 164 165 static Cascade create(MethodHandles.Lookup lookup,BufferAllocator bufferAllocator, XMLHaarCascadeModel haarCascade) { 166 167 Cascade cascade = bufferAllocator.allocate(SegmentMapper.of(lookup, Cascade.class, 168 JAVA_INT.withName("width"), 169 JAVA_INT.withName("height"), 170 JAVA_INT.withName("featureCount"), 171 sequenceLayout(haarCascade.features.size(), Feature.layout.withName(Feature.class.getSimpleName())).withName("feature"), 172 JAVA_INT.withName("stageCount"), 173 sequenceLayout(haarCascade.stages.size(), Stage.layout.withName(Stage.class.getSimpleName())).withName("stage"), 174 JAVA_INT.withName("treeCount"), 175 sequenceLayout(haarCascade.trees.size(), Tree.layout.withName(Tree.class.getSimpleName())).withName("tree") 176 )); 177 cascade.width(haarCascade.width()); 178 cascade.height(haarCascade.height()); 179 cascade.featureCount(haarCascade.features.size()); 180 cascade.stageCount(haarCascade.stages.size()); 181 cascade.treeCount(haarCascade.trees.size()); 182 for (int idx = 0; idx < haarCascade.features.size(); idx++) { 183 Cascade.Feature cascadeFeature = cascade.feature(idx); 184 var haarfeature = haarCascade.features.get(idx); 185 cascadeFeature.id(haarfeature.id()); 186 cascadeFeature.threshold(haarfeature.threshold()); 187 Cascade.Feature.LinkOrValue cascadeLeft = cascadeFeature.left(); 188 cascadeLeft.hasValue(haarfeature.left.hasValue()); 189 if (haarfeature.left.hasValue()) { 190 cascadeLeft.anon().value(haarfeature.left.value()); 191 } else { 192 cascadeLeft.anon().value(haarfeature.left.featureId()); 193 } 194 Cascade.Feature.LinkOrValue cascadeRight = cascadeFeature.right(); 195 cascadeRight.hasValue(haarfeature.right.hasValue()); 196 if (haarfeature.right.hasValue()) { 197 cascadeRight.anon().value(haarfeature.right.value()); 198 } else { 199 cascadeRight.anon().featureId(haarfeature.right.featureId()); 200 } 201 for (int r = 0; r < 3; r++) { 202 var haarrect = haarfeature.rects[r]; 203 if (haarrect != null) { 204 Cascade.Feature.Rect cascadeRect = cascadeFeature.rect(r); 205 cascadeRect.x(haarrect.x()); 206 cascadeRect.y(haarrect.y()); 207 cascadeRect.width(haarrect.width()); 208 cascadeRect.height(haarrect.height()); 209 cascadeRect.weight(haarrect.weight()); 210 } 211 } 212 } 213 for (XMLHaarCascadeModel.Stage haarstage : haarCascade.stages) { 214 Cascade.Stage cascadeStage = cascade.stage(haarstage.id); 215 cascadeStage.id(haarstage.id()); 216 cascadeStage.threshold(haarstage.threshold()); 217 cascadeStage.firstTreeId(haarstage.firstTreeId()); 218 cascadeStage.treeCount(haarstage.treeCount()); 219 } 220 221 for (XMLHaarCascadeModel.Tree haarTree : haarCascade.trees) { 222 Cascade.Tree cascadeTree = cascade.tree(haarTree.id()); 223 cascadeTree.id(haarTree.id()); 224 cascadeTree.firstFeatureId(haarTree.firstFeatureId()); 225 cascadeTree.featureCount(haarTree.featureCount()); 226 } 227 return cascade; 228 } 229 ``` 230