commit 72d791566bda52ee454a03b4ac522475138d46bc
Author: ffff:207.243.92.34 <ffff:207.243.92.34@mitosite.powerhouse.wiki>
Date: 2025-01-17 17:15:05 +0000
Subject: updated index.scroll
diff --git a/index.scroll b/index.scroll
index 49dbfec..59b471d 100644
--- a/index.scroll
+++ b/index.scroll
@@ -3,6 +3,7 @@ buildHtml
https://hub.powerhouse.wiki/powerhouse.parsers
powerhouseButton
+editButton /edit.html
code.parsers
commit 4a21245b282e82d0305d2240a2aa47c22f4d6ba0
Author: ffff:207.243.92.34 <ffff:207.243.92.34@mitosite.powerhouse.wiki>
Date: 2025-01-17 15:01:27 +0000
Subject: updated index.scroll
diff --git a/index.scroll b/index.scroll
index 33e1538..49dbfec 100644
--- a/index.scroll
+++ b/index.scroll
@@ -1,4 +1,9 @@
buildHtml
+
+https://hub.powerhouse.wiki/powerhouse.parsers
+
+powerhouseButton
+
code.parsers
style.css
commit 6b7fad5acefa2244163cb75fbfbcdb5c249c382d
Author: root <root@hub.scroll.pub>
Date: 2025-01-17 15:01:02 +0000
Subject: Deleted powerhouse.parsers
diff --git a/powerhouse.parsers b/powerhouse.parsers
deleted file mode 100644
index e69de29..0000000
commit ff589e00ed0f539ce294eeb534cdf8e5bf5667f3
Author: ffff:207.243.92.34 <ffff:207.243.92.34@mitosite.powerhouse.wiki>
Date: 2025-01-17 15:00:54 +0000
Subject: created powerhouse.parsers
diff --git a/powerhouse.parsers b/powerhouse.parsers
new file mode 100644
index 0000000..e69de29
commit dc957463bbc9fea888a94cc0f978b2fc8dc6d6b4
Author: 1 <1@localhost>
Date: 2025-01-16 20:08:25 -0800
Subject: updated brev.js
diff --git a/brev.js b/brev.js
index e69de29..434eda3 100644
--- a/brev.js
+++ b/brev.js
@@ -0,0 +1,88 @@
+const fs = require("fs");
+const decompress = require("decompress");
+
+const nvai_url =
+ "https://ai.api.nvidia.com/v1/cv/nvidia/retail-object-detection";
+const header_auth = `Bearer $API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC`;
+
+async function _upload_asset(input, description) {
+ const assets_url = "https://api.nvcf.nvidia.com/v2/nvcf/assets";
+
+ const headers = {
+ Authorization: header_auth,
+ "Content-Type": "application/json",
+ accept: "application/json",
+ };
+
+ const s3_headers = {
+ "x-amz-meta-nvcf-asset-description": description,
+ "content-type": "video/mp4",
+ };
+
+ const payload = {
+ contentType: "video/mp4",
+ description: description,
+ };
+
+ const response = await fetch(assets_url, {
+ method: "POST",
+ body: JSON.stringify(payload),
+ headers: headers,
+ });
+
+ const data = await response.json();
+
+ const asset_url = data["uploadUrl"];
+ const asset_id = data["assetId"];
+
+ const fileData = fs.readFileSync(input);
+
+ await fetch(asset_url, {
+ method: "PUT",
+ body: fileData,
+ headers: s3_headers,
+ });
+
+ return asset_id.toString();
+}
+
+(async () => {
+ if (process.argv.length != 4) {
+ console.log("Usage: node test.js <input_video> <output_dir>");
+ process.exit(1);
+ }
+
+ // Upload specified user asset
+ const asset_id = await _upload_asset(`${process.argv[2]}`, "Input Video");
+
+ // Metadata for the request
+ const inputs = { input_video: asset_id, threshold: 0.9 };
+ const asset_list = asset_id;
+ const headers = {
+ "Content-Type": "application/json",
+ "NVCF-INPUT-ASSET-REFERENCES": asset_list,
+ "NVCF-FUNCTION-ASSET-IDS": asset_list,
+ Authorization: header_auth,
+ };
+
+ // Make the request to nvcf
+ const response = await fetch(nvai_url, {
+ method: "POST",
+ body: JSON.stringify(inputs),
+ headers: headers,
+ });
+
+ // Gather the binary response data
+ const arrayBuffer = await response.arrayBuffer();
+ const buffer = Buffer.from(arrayBuffer);
+
+ const zipname = `${process.argv[3]}.zip`;
+ fs.writeFileSync(zipname, buffer);
+
+ // Unzip the response synchronously
+ await decompress(zipname, process.argv[3]);
+
+ // Log the output directory and its contents
+ console.log(`Response saved to ${process.argv[3]}`);
+ console.log(fs.readdirSync(process.argv[3]));
+})();
commit 75a9fa9e310b7201f149908f7fcbe3bead301cef
Author: 1 <1@localhost>
Date: 2025-01-16 20:08:24 -0800
Subject: created brev.js
diff --git a/brev.js b/brev.js
new file mode 100644
index 0000000..e69de29
commit 25f4f6b833d7b22510b75c8542cdd4c6c5688221
Author: Breck Yunits <breck7@gmail.com>
Date: 2025-01-16 20:05:41 -0800
Subject:
diff --git a/index.scroll b/index.scroll
index e2acb00..33e1538 100644
--- a/index.scroll
+++ b/index.scroll
@@ -23,7 +23,7 @@ webcam 800 600
hud Current Time
type time
position top-right
- hud Swift SW200DL 400x
+ hud Swift SW200DL 100x
position top-left
diff --git a/mitosite.js b/mitosite.js
index 5bb92ca..76011ca 100644
--- a/mitosite.js
+++ b/mitosite.js
@@ -341,11 +341,13 @@ class MitoSiteApp {
console.log("Stopped auto drawing")
} else {
console.log("Started auto drawing")
- let max = 53
+ let max = 253
data.autoDrawInterval = setInterval(() => {
if (max) {
this.drawRandomBox(container)
max--
+ } else {
+ if (Math.random() > 0.92) this.drawRandomBox(container)
}
}, 25) // Draw every 500ms
}
@@ -358,8 +360,8 @@ class MitoSiteApp {
const { canvas } = data
// Generate random box dimensions within canvas bounds
- const minSize = 20
- const maxSize = 50
+ const minSize = 10
+ const maxSize = 30
const width = Math.random() * (maxSize - minSize) + minSize
const height = Math.random() * (maxSize - minSize) + minSize
const x = Math.random() * (canvas.width - width)
commit d4160ba5aba631d4c749212613a5148adff966cd
Author: Breck Yunits <breck7@gmail.com>
Date: 2025-01-16 19:56:55 -0800
Subject:
diff --git a/index.scroll b/index.scroll
index 6285316..e2acb00 100644
--- a/index.scroll
+++ b/index.scroll
@@ -3,8 +3,11 @@ code.parsers
style.css
-https://cdn.jsdelivr.net/npm/@tensorflow/tfjs
-https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd
+
+<!-- Load TensorFlow.js. This is required to use coco-ssd model. -->
+<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"> </script>
+<!-- Load the coco-ssd model. -->
+<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"> </script>
// lib/tensorflow/coco-ssd.min.js
mitosite.js
diff --git a/mitosite.js b/mitosite.js
index 25809b2..5bb92ca 100644
--- a/mitosite.js
+++ b/mitosite.js
@@ -1,13 +1,21 @@
class MitoSiteApp {
constructor(containerSelector = ".scrollWebcam") {
this.containers = document.querySelectorAll(containerSelector)
- this.instances = new Map() // Store instance data for each container
-
- this.init()
- console.log()
+ this.instances = new Map()
+ this.model = null
+ this.isDetecting = false
}
- init() {
+ async init() {
+ // Load COCO-SSD model using the official library
+ try {
+ // Load the model directly from the CDN
+ this.model = await cocoSsd.load()
+ console.log("TensorFlow model loaded successfully")
+ } catch (err) {
+ console.error("Error loading TensorFlow model:", err)
+ }
+
this.containers.forEach((container) => this.setupContainer(container))
}
@@ -27,6 +35,117 @@ class MitoSiteApp {
await this.setupWebcam(container)
this.setupCanvas(container)
this.setupHUD(container)
+
+ // Start detection loop once everything is set up
+ this.startDetection(container)
+ }
+
+ async startDetection(container) {
+ const data = this.instances.get(container)
+ const { video } = data
+
+ if (!this.model) {
+ console.error("TensorFlow model not loaded")
+ return
+ }
+
+ // Wait for video to be ready
+ if (video.readyState === 0) {
+ video.addEventListener("loadeddata", () => this.startDetection(container))
+ return
+ }
+
+ const detectFrame = async () => {
+ if (!this.isDetecting) return
+
+ // Check if video is ready and has valid dimensions
+ if (
+ video.readyState !== 4 ||
+ video.videoWidth === 0 ||
+ video.videoHeight === 0
+ ) {
+ requestAnimationFrame(() => detectFrame())
+ return
+ }
+
+ try {
+ // Make sure video dimensions are set
+ if (video.width !== video.videoWidth) {
+ video.width = video.videoWidth
+ }
+ if (video.height !== video.videoHeight) {
+ video.height = video.videoHeight
+ }
+
+ // Perform detection only if video is playing and visible
+ if (!video.paused && !video.ended && video.style.display !== "none") {
+ const predictions = await this.model.detect(video)
+
+ // Clear previous boxes
+ this.clearCanvas(container)
+
+ // Draw AI predictions in a different color without adding to boxes
+ predictions.forEach((prediction) => {
+ if (prediction.score > 0.5) {
+ // Confidence threshold
+ const [x, y, width, height] = prediction.bbox
+
+ // Draw AI predictions in blue
+ const { ctx } = data
+ ctx.strokeStyle = "#0000ff"
+ ctx.lineWidth = 2
+ ctx.strokeRect(x, y, width, height)
+
+ if (prediction.score !== null) {
+ ctx.fillStyle = "#0000ff"
+ ctx.font = "12px Arial"
+ ctx.fillText(`${Math.round(prediction.score * 100)}%`, x, y - 5)
+ }
+ }
+ })
+
+ // Redraw manual boxes in green
+ data.boxes.forEach((box) => {
+ this.drawBox(container, box.x, box.y, box.width, box.height)
+ })
+ }
+ } catch (err) {
+ console.error("Detection error:", err)
+ }
+
+ // Request next frame
+ requestAnimationFrame(() => detectFrame())
+ }
+
+ // Start detection loop
+ this.isDetecting = true
+ detectFrame()
+ }
+
+ drawBox(container, x, y, width, height, score = null) {
+ const data = this.instances.get(container)
+ const { ctx } = data
+
+ ctx.strokeStyle = "#00ff00"
+ ctx.lineWidth = 2
+ ctx.strokeRect(x, y, width, height)
+
+ if (score !== null) {
+ ctx.fillStyle = "#00ff00"
+ ctx.font = "12px Arial"
+ ctx.fillText(`${Math.round(score * 100)}%`, x, y - 5)
+ }
+ }
+
+ updateCellCount(container) {
+ const data = this.instances.get(container)
+ const hud = container.querySelector(".scrollWebcamHud")
+ const cellCounter = hud.querySelector(
+ '.scrollWebcamHudElement[data-type="cellCount"]',
+ )
+ if (cellCounter) {
+ cellCounter.textContent = `Cells Detected: ${data.boxes.length}`
+ }
}
async setupWebcam(container) {
@@ -39,20 +158,28 @@ class MitoSiteApp {
(device) => device.kind === "videoinput",
)
- if (videoDevices.length > 1) {
- videoDevices.forEach((device) => {
- const option = document.createElement("option")
- option.value = device.deviceId
- option.text = device.label || `Camera ${select.length + 1}`
- select.appendChild(option)
- })
- select.style.display = "block"
- select.addEventListener("change", (e) =>
- this.startCamera(container, e.target.value),
- )
- } else {
- select.style.display = "none"
- }
+ // Add demo video option first
+ const demoOption = document.createElement("option")
+ demoOption.value = "demo"
+ demoOption.text = "Demo Video"
+ select.appendChild(demoOption)
+
+ // Add webcam options
+ videoDevices.forEach((device) => {
+ const option = document.createElement("option")
+ option.value = device.deviceId
+ option.text = device.label || `Camera ${select.length}`
+ select.appendChild(option)
+ })
+
+ select.style.display = "block"
+ select.addEventListener("change", (e) => {
+ if (e.target.value === "demo") {
+ this.startDemoVideo(container)
+ } else {
+ this.startCamera(container, e.target.value)
+ }
+ })
await this.startCamera(container)
} catch (err) {
@@ -61,6 +188,25 @@ class MitoSiteApp {
}
}
+ async startDemoVideo(container) {
+ const data = this.instances.get(container)
+ const { video, currentStream } = data
+
+ // Stop any existing stream
+ if (currentStream) {
+ currentStream.getTracks().forEach((track) => track.stop())
+ data.currentStream = null
+ }
+
+ // Set up video source
+ video.src = "rbc.mp4" // Make sure this file exists in your project
+ video.loop = true // Loop the video
+ video.play().catch((err) => {
+ console.error("Error playing demo video:", err)
+ container.innerHTML = "Error: Could not play demo video"
+ })
+ }
+
async startCamera(container, deviceId = null) {
const data = this.instances.get(container)
const { video, currentStream } = data
@@ -84,7 +230,17 @@ class MitoSiteApp {
const stream = await navigator.mediaDevices.getUserMedia(constraints)
data.currentStream = stream
video.srcObject = stream
- video.play()
+
+ // Wait for video to be ready before playing
+ await new Promise((resolve) => {
+ video.onloadedmetadata = () => {
+ video.width = video.videoWidth
+ video.height = video.videoHeight
+ resolve()
+ }
+ })
+
+ await video.play()
} catch (err) {
console.error("Error accessing webcam:", err)
container.innerHTML = "Error: Could not access webcam"
@@ -97,13 +253,15 @@ class MitoSiteApp {
const canvas = document.createElement("canvas")
canvas.className = "scrollWebcamCanvas"
- canvas.width = video.width
- canvas.height = video.height
+ canvas.width = video.videoWidth || video.width
+ canvas.height = video.videoHeight || video.height
canvas.style.position = "absolute"
canvas.style.top = "0"
canvas.style.left = "0"
canvas.style.zIndex = "1"
canvas.style.cursor = "crosshair"
+ canvas.style.width = "100%" // Make canvas scale with container
+ canvas.style.height = "100%"
container.insertBefore(canvas, container.firstChild.nextSibling)
@@ -129,7 +287,6 @@ class MitoSiteApp {
cellCounter.style.bottom = "10px"
cellCounter.style.left = "10px"
cellCounter.style.fontSize = "30px"
- //cellCounter.style.color = "#00ff00"
cellCounter.style.textShadow = "1px 1px 2px black"
hud.appendChild(cellCounter)
}
@@ -176,10 +333,54 @@ class MitoSiteApp {
this.redrawBoxes(container)
} else if (e.key === "Delete") {
this.clearAllBoxes(container)
+ } else if (e.key.toLowerCase() === "r") {
+ // Toggle automatic box drawing
+ if (data.autoDrawInterval) {
+ clearInterval(data.autoDrawInterval)
+ data.autoDrawInterval = null
+ console.log("Stopped auto drawing")
+ } else {
+ console.log("Started auto drawing")
+ let max = 53
+ data.autoDrawInterval = setInterval(() => {
+ if (max) {
+ this.drawRandomBox(container)
+ max--
+ }
+ }, 25) // Draw every 500ms
+ }
}
})
}
+ drawRandomBox(container) {
+ const data = this.instances.get(container)
+ const { canvas } = data
+
+ // Generate random box dimensions within canvas bounds
+ const minSize = 20
+ const maxSize = 50
+ const width = Math.random() * (maxSize - minSize) + minSize
+ const height = Math.random() * (maxSize - minSize) + minSize
+ const x = Math.random() * (canvas.width - width)
+ const y = Math.random() * (canvas.height - height)
+
+ // Add the box to the collection
+ data.boxes.push({ x, y, width, height })
+
+ // Redraw all boxes
+ this.redrawBoxes(container)
+
+ // Update cell counter
+ const hud = container.querySelector(".scrollWebcamHud")
+ const cellCounter = hud.querySelector(
+ '.scrollWebcamHudElement[data-type="cellCount"]',
+ )
+ if (cellCounter) {
+ cellCounter.textContent = `Cells Counted: ${data.boxes.length}`
+ }
+ }
+
handleMouseDown(container, e) {
const data = this.instances.get(container)
const rect = data.canvas.getBoundingClientRect()
@@ -237,15 +438,6 @@ class MitoSiteApp {
this.redrawBoxes(container)
}
- drawBox(container, x, y, width, height) {
- const data = this.instances.get(container)
- const { ctx } = data
-
- ctx.strokeStyle = "#00ff00"
- ctx.lineWidth = 2
- ctx.strokeRect(x, y, width, height)
- }
-
clearCanvas(container) {
const data = this.instances.get(container)
const { ctx, canvas } = data
@@ -277,6 +469,21 @@ class MitoSiteApp {
}
}
-document.addEventListener("DOMContentLoaded", () => {
+// Initialize the app when the DOM is loaded
+document.addEventListener("DOMContentLoaded", async () => {
+ // Verify TensorFlow.js and COCO-SSD are loaded
+ if (typeof tf === "undefined") {
+ console.error("TensorFlow.js is not loaded")
+ return
+ }
+ if (typeof cocoSsd === "undefined") {
+ console.error("COCO-SSD model is not loaded")
+ return
+ }
+
+ console.log("TensorFlow.js loaded:", typeof tf !== "undefined")
+ console.log("COCO-SSD loaded:", typeof cocoSsd !== "undefined")
+
const app = new MitoSiteApp()
+ await app.init()
})
commit c43d642a77172ea7771ae955a7ca0445881f7230
Author: 1 <1@localhost>
Date: 2025-01-16 19:45:40 -0800
Subject: updated index.scroll
diff --git a/index.scroll b/index.scroll
index e44e95d..6285316 100644
--- a/index.scroll
+++ b/index.scroll
@@ -2,6 +2,11 @@ buildHtml
code.parsers
style.css
+
+https://cdn.jsdelivr.net/npm/@tensorflow/tfjs
+https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd
+// lib/tensorflow/coco-ssd.min.js
+
mitosite.js
center
commit c6fda4c8c7ee923e7344f855a5d1c5a55ffecd2f
Author: 1 <1@localhost>
Date: 2025-01-16 19:17:03 -0800
Subject: updated video.scroll
diff --git a/video.scroll b/video.scroll
index 380cbad..94d9ce1 100644
--- a/video.scroll
+++ b/video.scroll
@@ -1,3 +1,4 @@
buildHtml
rbc.mp4
- autoplay
\ No newline at end of file
+ autoplay
+ loop
\ No newline at end of file