| <!DOCTYPE html> |
| <html lang="en"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>DW-Pose WASM Inference</title> |
| <style> |
| body { |
| font-family: 'Helvetica Neue', Arial, sans-serif; |
| background-color: #121212; |
| color: #e0e0e0; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| padding: 40px 20px; |
| margin: 0; |
| } |
| |
| .container { |
| max-width: 900px; |
| width: 100%; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| gap: 24px; |
| background: rgba(255, 255, 255, 0.03); |
| border-radius: 16px; |
| padding: 30px; |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); |
| backdrop-filter: blur(4px); |
| border: 1px solid rgba(255, 255, 255, 0.05); |
| } |
| |
| h1 { |
| margin: 0 0 10px 0; |
| font-size: 2.5rem; |
| background: linear-gradient(45deg, #00dbde, #fc00ff); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| font-weight: 700; |
| } |
| |
| #display-img { |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| border-radius: 8px; |
| max-width: 100%; |
| height: auto; |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); |
| background-color: #1a1a1a; |
| display: block; |
| } |
| |
| .controls { |
| display: flex; |
| gap: 15px; |
| align-items: center; |
| flex-wrap: wrap; |
| justify-content: center; |
| width: 100%; |
| } |
| |
| .btn { |
| border: 1px solid #333; |
| color: #fff; |
| background-color: #222; |
| padding: 12px 24px; |
| border-radius: 8px; |
| font-size: 15px; |
| font-weight: 600; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| } |
| |
| .btn:hover { |
| background-color: #333; |
| border-color: #555; |
| } |
| |
| #submit-btn { |
| background: linear-gradient(135deg, #007acc 0%, #005999 100%); |
| border: none; |
| box-shadow: 0 4px 15px rgba(0, 122, 204, 0.3); |
| min-width: 160px; |
| } |
| |
| #submit-btn:hover { |
| background: linear-gradient(135deg, #0099ff 0%, #007acc 100%); |
| box-shadow: 0 6px 20px rgba(0, 122, 204, 0.5); |
| } |
| |
| #submit-btn:disabled { |
| background: #333; |
| color: #777; |
| box-shadow: none; |
| cursor: not-allowed; |
| } |
| |
| #download-btn { |
| background: linear-gradient(135deg, #28a745 0%, #218838 100%); |
| border: none; |
| box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3); |
| } |
| |
| #download-btn:hover:not(:disabled) { |
| background: linear-gradient(135deg, #2ecc71 0%, #28a745 100%); |
| box-shadow: 0 6px 20px rgba(40, 167, 69, 0.5); |
| } |
| |
| #download-btn:disabled { |
| background: #333; |
| color: #777; |
| box-shadow: none; |
| cursor: not-allowed; |
| } |
| |
| #status { |
| font-size: 14px; |
| color: #00ffcc; |
| font-family: monospace; |
| padding: 8px 16px; |
| background: rgba(0, 255, 204, 0.05); |
| border: 1px solid rgba(0, 255, 204, 0.2); |
| border-radius: 6px; |
| text-align: center; |
| min-width: 200px; |
| } |
| |
| .examples-section { |
| width: 100%; |
| margin-top: 20px; |
| border-top: 1px solid rgba(255, 255, 255, 0.05); |
| padding-top: 20px; |
| } |
| |
| .examples-section h2 { |
| font-size: 1.2rem; |
| margin-top: 0; |
| margin-bottom: 15px; |
| color: #aaa; |
| text-align: center; |
| } |
| |
| .examples-grid { |
| display: flex; |
| gap: 15px; |
| justify-content: center; |
| flex-wrap: wrap; |
| } |
| |
| .example-thumb { |
| width: 100px; |
| height: 100px; |
| object-fit: cover; |
| border-radius: 8px; |
| border: 2px solid transparent; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); |
| } |
| |
| .example-thumb:hover { |
| transform: scale(1.08); |
| border-color: #007acc; |
| box-shadow: 0 6px 15px rgba(0, 122, 204, 0.5); |
| } |
| </style> |
| |
| |
| <link rel="rust" href="Cargo.toml" /> |
| <link rel="modulepreload" href="/web.js" crossorigin="anonymous"><link rel="modulepreload" href="/snippets/ort-web-c7b42e3e9fb58316/_telemetry.js" crossorigin="anonymous"><link rel="modulepreload" href="/snippets/ort-web-c7b42e3e9fb58316/_loader.js" crossorigin="anonymous"><link rel="preload" href="/web_bg.wasm" crossorigin="anonymous" as="fetch" type="application/wasm"></head> |
|
|
| <body> |
| <div class="container"> |
| <h1>DW-Pose WASM Inference</h1> |
| <div class="controls"> |
| <input type="file" id="file-input" accept="image/*" class="btn"> |
| <label style="display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;"> |
| <input type="checkbox" id="auto-chk" checked style="width: 18px; height: 18px; cursor: pointer;"> |
| <span>Auto</span> |
| </label> |
| <button id="submit-btn" class="btn" disabled>Loading Model...</button> |
| <button id="download-btn" class="btn" disabled>Save</button> |
| <label style="display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;"> |
| <input type="checkbox" id="pose-only-chk" style="width: 18px; height: 18px; cursor: pointer;"> |
| <span>Pose Only</span> |
| </label> |
| </div> |
| <div id="status">Initializing WebGPU ONNX Runtime API...</div> |
| <img id="display-img" src="" alt="Pose estimation result image" style="display: none;"> |
|
|
| <div class="examples-section"> |
| <h2>Sample Images (Click to Infer)</h2> |
| <div class="examples-grid"> |
| <img class="example-thumb" id="example-1" src="/examples/example1.jpg" alt="Example 1"> |
| <img class="example-thumb" id="example-2" src="/examples/example2.jpg" alt="Example 2"> |
| <img class="example-thumb" id="example-3" src="/examples/example3.jpg" alt="Example 3"> |
| </div> |
| </div> |
| <div> |
| <p>To reduce download time, this app does not use yolox_l.onnx for image cropping, so its accuracy may be |
| slightly lower.</p> |
| </div> |
| </div> |
| <hr> |
| <div><a href="https://huggingface.co/yzd-v/DWPose" target="_blank">DWPose</a></div> |
|
|
| <script type="module"> |
| import init, * as bindings from '/web.js'; |
| const wasm = await init({ module_or_path: '/web_bg.wasm' }); |
| |
| |
| window.wasmBindings = bindings; |
| |
| |
| dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}})); |
| |
| </script><script>"use strict"; |
| |
| (function () { |
| |
| const address = '{{__TRUNK_ADDRESS__}}'; |
| const base = '{{__TRUNK_WS_BASE__}}'; |
| let protocol = ''; |
| protocol = |
| protocol |
| ? protocol |
| : window.location.protocol === 'https:' |
| ? 'wss' |
| : 'ws'; |
| const url = protocol + '://' + address + base + '.well-known/trunk/ws'; |
| |
| class Overlay { |
| constructor() { |
| |
| this._overlay = document.createElement("div"); |
| const style = this._overlay.style; |
| style.height = "100vh"; |
| style.width = "100vw"; |
| style.position = "fixed"; |
| style.top = "0"; |
| style.left = "0"; |
| style.backgroundColor = "rgba(222, 222, 222, 0.5)"; |
| style.fontFamily = "sans-serif"; |
| |
| style.zIndex = "1000000"; |
| style.backdropFilter = "blur(1rem)"; |
| |
| const container = document.createElement("div"); |
| |
| container.style.position = "absolute"; |
| container.style.top = "30%"; |
| container.style.left = "15%"; |
| container.style.maxWidth = "85%"; |
| |
| this._title = document.createElement("div"); |
| this._title.innerText = "Build failure"; |
| this._title.style.paddingBottom = "2rem"; |
| this._title.style.fontSize = "2.5rem"; |
| |
| this._message = document.createElement("div"); |
| this._message.style.whiteSpace = "pre-wrap"; |
| |
| const icon= document.createElement("div"); |
| icon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="#dc3545" viewBox="0 0 16 16"><path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/></svg>'; |
| this._title.prepend(icon); |
| |
| container.append(this._title, this._message); |
| this._overlay.append(container); |
| |
| this._inject(); |
| window.setInterval(() => { |
| this._inject(); |
| }, 250); |
| } |
| |
| set reason(reason) { |
| this._message.textContent = reason; |
| } |
| |
| _inject() { |
| if (!this._overlay.isConnected) { |
| |
| document.body?.prepend(this._overlay); |
| } |
| } |
| |
| } |
| |
| class Client { |
| constructor(url) { |
| this.url = url; |
| this.poll_interval = 5000; |
| this._overlay = null; |
| } |
| |
| start() { |
| const ws = new WebSocket(this.url); |
| ws.onmessage = (ev) => { |
| const msg = JSON.parse(ev.data); |
| switch (msg.type) { |
| case "reload": |
| this.reload(); |
| break; |
| case "buildFailure": |
| this.buildFailure(msg.data) |
| break; |
| } |
| }; |
| ws.onclose = () => this.onclose(); |
| } |
| |
| onclose() { |
| window.setTimeout( |
| () => { |
| |
| |
| |
| |
| const ws = new WebSocket(this.url); |
| ws.onopen = () => window.location.reload(); |
| ws.onclose = () => this.onclose(); |
| }, |
| this.poll_interval); |
| } |
| |
| reload() { |
| window.location.reload(); |
| } |
| |
| buildFailure({reason}) { |
| |
| console.error("Build failed:", reason); |
| |
| console.debug("Overlay", this._overlay); |
| |
| if (!this._overlay) { |
| this._overlay = new Overlay(); |
| } |
| this._overlay.reason = reason; |
| } |
| } |
| |
| new Client(url).start(); |
| |
| })() |
| </script></body> |
|
|
| </html> |