<div class="container">
  <div class="img-container">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Material_Design.svg/640px-Material_Design.svg.png" crossorigin="anonymous">
    <div class="boxes-container"></div>
  </div>
  <div class="buttons">

    <div class="model tflite-custom">
      <div class="btn disabled">TFLite (custom)</div>
      <div class="result"></div>
    </div>
  </div>
</div>
body {
  font-family: 'Google Sans';
}

.container {
  display: flex;
}

.img-container {
  position: relative;
}

img {
  height: 250px;
  border-radius: 8px;
}

.boxes-container {
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;

  position: absolute;
}

.buttons {
  margin-left: 20px;
}

.model {
  display: flex;
  align-items: center;
}

.result {
  margin-left: 20px;
}

.btn {
  border: 1px solid #888;
  cursor: pointer;
  width: 150px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px 0;
}

.btn.disabled {
  color: #bbb;
  border-color: #bbb;
  pointer-events: none;
}

.btn:hover {
  background-color: #eee;
}

.box-container {
  position: absolute;
}

.box {
  border: 2px solid red;
}

.label {
  background-color: red;
  color: white;
  height: 18px;
  line-height: 18px;
  position: absolute;
  top: -16px;
  white-space: nowrap;
  padding: 0 5px;
  font-size: 12px;
  display: none;
}

.box-container:hover .label {
  display: block;
}

.msg {
  visibility: hidden;
  font-size: 14px;
}

.msg.show {
  visibility: visible;
}
const img = document.querySelector("img");
let lastModel;
let lastClassName;
let warmedUp = false;


setupButton(
  "tflite-custom",
  async () =>
    await tfTask.ObjectDetection.CustomModel.TFLite.load({
      model: "https://raw.githack.com/dusskapark/zeplin-ml/main/public/models/rico.tflite"
    })
);

async function setupButton(className, modelCreateFn, needWarmup) {
  document
    .querySelector(`.model.${className} .btn`)
    .classList.remove("disabled");
  const resultEle = document.querySelector(`.model.${className} .result`);
  document
    .querySelector(`.model.${className} .btn`)
    .addEventListener("click", async () => {
      let model;
      // Create the model when user clicks on a button.
      if (lastClassName !== className) {
        // Clean up the previous model if existed.
        if (lastModel) {
          lastModel.cleanUp();
        }
        // Create the new model and save it.
        resultEle.textContent = "Loading...";
        model = await modelCreateFn();
        lastModel = model;
        lastClassName = className;
      }
      // Reuse the model if user clicks on the same button.
      else {
        model = lastModel;
      }

      // Warm up if needed.
      if (needWarmup && !warmedUp) {
        await model.predict(img);
        warmedUp = true;
      }

      // Run inference and update result.
      const start = Date.now();
      const result = await model.predict(img);
      const latency = Date.now() - start;
      renderDetectionResult(result);
      resultEle.textContent = `Latency: ${latency}ms`;
    });
}

/** Render detection results. */
function renderDetectionResult(result) {
  const boxesContainer = document.querySelector(".boxes-container");
  boxesContainer.innerHTML = "";
  const objects = result.objects;
  for (let i = 0; i < Math.min(5, objects.length); i++) {
    const curObject = objects[i];
    const boundingBox = curObject.boundingBox;
    const name = curObject.className;
    const score = curObject.score;

    const boxContainer = createDetectionResultBox(
      boundingBox.originX,
      boundingBox.originY,
      boundingBox.width,
      boundingBox.height,
      name,
      score
    );
    boxesContainer.appendChild(boxContainer);
  }
}

/** Create a single detection result box. */
function createDetectionResultBox(left, top, width, height, name, score) {
  const container = document.createElement("div");
  container.classList.add("box-container");

  const box = document.createElement("div");
  box.classList.add("box");
  container.appendChild(box);

  const label = document.createElement("div");
  label.classList.add("label");
  label.textContent = `${name} (${score.toFixed(2)})`;
  container.appendChild(label);

  container.style.left = `${left - 1}px`;
  container.style.top = `${top - 1}px`;
  box.style.width = `${width + 1}px`;
  box.style.height = `${height + 1}px`;

  return container;
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdn.jsdelivr.net/npm/@tensorflow-models/tasks@0.0.1-alpha.8