diff a/hat/docs/Implementation/cascade-interface-mapping.md b/hat/docs/Implementation/cascade-interface-mapping.md --- /dev/null +++ b/hat/docs/Implementation/cascade-interface-mapping.md @@ -0,0 +1,213 @@ +# More Complex Interface Mapping MavenStyleProject - The Cascade +[Back to Index ../](../index.md) + +# More Complex Interface Mapping MavenStyleProject - The Cascade + +Previously we showed probably the minimal useful mapping with S32Array + +The HaarCascade example has multiple nested interfaces representing data +structures involving various nested structs and unions + +```java +public interface Cascade extends Buffer { + int width(); + void width(int width); + int height(); + void height(int height); + interface Feature extends Buffer.StructChild { + int id(); + float threshold(); + void id(int id); + void threshold(float threshold); + interface LinkOrValue extends Buffer.StructChild { + interface Anon extends Buffer.UnionChild { + int featureId(); + void featureId(int featureId); + float value(); + void value(float value); + } + boolean hasValue(); + void hasValue(boolean hasValue); + Anon anon(); + } + LinkOrValue left(); + LinkOrValue right(); + interface Rect extends Buffer.StructChild { + byte x(); + byte y(); + byte width(); + byte height(); + float weight(); + void x(byte x); + void y(byte y); + void width(byte width); + void height(byte height); + void weight(float height); + } + Rect rect(long idx); + } + int featureCount(); + void featureCount(int featureCount); + Feature feature(long idx); + interface Stage extends Buffer.StructChild { + float threshold(); + short firstTreeId(); + short treeCount(); + int id(); + void id(int id); + void threshold(float threshold); + void firstTreeId(short firstTreeId); + void treeCount(short treeCount); + } + + int stageCount(); + void stageCount(int stageCount); + Stage stage(long idx); + interface Tree extends Buffer.StructChild { + void id(int id); + void firstFeatureId(short firstFeatureId); + void featureCount(short featureCount); + int id(); + short firstFeatureId(); + short featureCount(); + } + int treeCount(); + void treeCount(int treeCount); + Tree tree(long idx); + Schema schema = Schema.of(Cascade.class, cascade -> cascade + .fields("width", "height") + .arrayLen("featureCount") + .array("feature", feature -> feature + .field("id") + .field("threshold") + .fields("left", "right", linkOrValue -> linkOrValue + .field("hasValue") + .pad(3) + .field("anon", anon -> anon + .field("featureId") + .field("value") + ) + ) + .array("rect", 3, rect -> rect + .field("x") + .field("y") + .field("width") + .field("height"). + .field("weight")) + ) + .arrayLen("treeCount") + .array("tree", tree -> tree + .field("id") + .field("featureCount") + .field("firstFeatureId") + ) + .arrayLen("stageCount") + .array("stage", stage -> stage + .field("id") + .field("threshold") + .field("treeCount") + .field("firstTreeId")) + ); +} +``` + +Another great advantage of using interfaces is that we can choose +to re implement the interface in any was we see fit. + +For example we load HaarCascades from XML files. +We therefore can create an implementation of the Cascade interface which just +loads the XML DOM... stores them in arrays and the interface methods just delegate to +the appropriately wrapped w3c.Node tree nodes ;) + +If we know we are using Java backend we can actually +just pass the XMLCascade implementation directly to the backend... + +Actually the Cascade `create` method takes an existing +implementation of a Cascade and clones it. +So we can just pass it an XMLHaarCascade ;) + +So we build an XMLCascade then pass it to the `create` method of the iface +mapped Cascade + +```java + XMLHaarCascadeModel haarCascade = XMLHaarCascadeModel.load( + ViolaJonesRaw.class.getResourceAsStream("haarcascade_frontalface_default.xml")); + + assert haarCascade instanceof Cascade; // Here it is just an interface + + Cascade cascade = Cascade.create(accelerator, haarCascade); + + // Now it can be used on the GPU +``` + +The implementation is currently hand crafted, but this could easily be automated. + +```java + import java.lang.invoke.MethodHandles; + +static Cascade create(MethodHandles.Lookup lookup,BufferAllocator bufferAllocator, XMLHaarCascadeModel haarCascade) { + + Cascade cascade = bufferAllocator.allocate(SegmentMapper.of(lookup, Cascade.class, + JAVA_INT.withName("width"), + JAVA_INT.withName("height"), + JAVA_INT.withName("featureCount"), + sequenceLayout(haarCascade.features.size(), Feature.layout.withName(Feature.class.getSimpleName())).withName("feature"), + JAVA_INT.withName("stageCount"), + sequenceLayout(haarCascade.stages.size(), Stage.layout.withName(Stage.class.getSimpleName())).withName("stage"), + JAVA_INT.withName("treeCount"), + sequenceLayout(haarCascade.trees.size(), Tree.layout.withName(Tree.class.getSimpleName())).withName("tree") + )); + cascade.width(haarCascade.width()); + cascade.height(haarCascade.height()); + cascade.featureCount(haarCascade.features.size()); + cascade.stageCount(haarCascade.stages.size()); + cascade.treeCount(haarCascade.trees.size()); + for (int idx = 0; idx < haarCascade.features.size(); idx++) { + Cascade.Feature cascadeFeature = cascade.feature(idx); + var haarfeature = haarCascade.features.get(idx); + cascadeFeature.id(haarfeature.id()); + cascadeFeature.threshold(haarfeature.threshold()); + Cascade.Feature.LinkOrValue cascadeLeft = cascadeFeature.left(); + cascadeLeft.hasValue(haarfeature.left.hasValue()); + if (haarfeature.left.hasValue()) { + cascadeLeft.anon().value(haarfeature.left.value()); + } else { + cascadeLeft.anon().value(haarfeature.left.featureId()); + } + Cascade.Feature.LinkOrValue cascadeRight = cascadeFeature.right(); + cascadeRight.hasValue(haarfeature.right.hasValue()); + if (haarfeature.right.hasValue()) { + cascadeRight.anon().value(haarfeature.right.value()); + } else { + cascadeRight.anon().featureId(haarfeature.right.featureId()); + } + for (int r = 0; r < 3; r++) { + var haarrect = haarfeature.rects[r]; + if (haarrect != null) { + Cascade.Feature.Rect cascadeRect = cascadeFeature.rect(r); + cascadeRect.x(haarrect.x()); + cascadeRect.y(haarrect.y()); + cascadeRect.width(haarrect.width()); + cascadeRect.height(haarrect.height()); + cascadeRect.weight(haarrect.weight()); + } + } + } + for (XMLHaarCascadeModel.Stage haarstage : haarCascade.stages) { + Cascade.Stage cascadeStage = cascade.stage(haarstage.id); + cascadeStage.id(haarstage.id()); + cascadeStage.threshold(haarstage.threshold()); + cascadeStage.firstTreeId(haarstage.firstTreeId()); + cascadeStage.treeCount(haarstage.treeCount()); + } + + for (XMLHaarCascadeModel.Tree haarTree : haarCascade.trees) { + Cascade.Tree cascadeTree = cascade.tree(haarTree.id()); + cascadeTree.id(haarTree.id()); + cascadeTree.firstFeatureId(haarTree.firstFeatureId()); + cascadeTree.featureCount(haarTree.featureCount()); + } + return cascade; +} +``` +