bacteria counting page (work in progress) like everything else.

This commit is contained in:
lukas fricke 2025-01-16 03:30:32 +01:00
parent 37612b7898
commit 007b23da89

344
observe_bact.html Normal file
View file

@ -0,0 +1,344 @@
<!DOCTYPE html>
<html>
<head>
<link href="bootstrap-5.0.2-dist/css/bootstrap.min.css" rel="stylesheet" ></link>
<script src="bootstrap-5.0.2-dist/js/bootstrap.bundle.min.js" ></script>
<script type="text/javascript" src="https://docs.opencv.org/4.10.0/opencv.js"></script>
<meta charset='utf-8'>
<style>
#output{
position: relative;
width: 100%;
}
#video_container{
position: relative;
}
#video {
position:absolute;
z-index: 9;
width: 100%;
}
#canvas-draw{
position:absolute;
z-index:10;
width: 100%;
}
#canvas-debug{
position:absolute;
z-index:10;
width: 20em;
opacity: 100%;
}
#photo {
position:absolute;
z-index:5;
width: 100%;
}
#canvas-temp{
display: none;
}
#tables {
width: 100%;
}
#control-elements {
height:30em;
}
</style>
</head>
<body>
<!-- this canvas is not displayed and only used to generate the photo -->
<canvas id="canvas-temp"></canvas>
<div class="container">
<!-- the output div is used to display the video, the photo and the canvas where you can draw in (and measure) your organisms. -->
<div id="output" class="row">
<div id = "video_container" class="col-9">
<img id="photo" alt="The screen capture will appear in this box." ></img>
<canvas id="canvas-draw"></canvas>
<video autoplay="true" id="video"></video>
</div>
<div id = "control-elements" class="col-3 ">
<div id="organisms-table">
<h2> bacteria-candidates </h2>
<table id= "org-table" style="width:100%">
<thead>
<tr>
<th>
bacteria
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<button class="btn btn-primary float-end" onclick="toggleFullscreen();" id="fullscreen-button">toggle Fullscreen video</button>
<div class="row">
<button class="btn btn-primary float-end" onclick="toggle_cam();">Toggle camera</button>
<button class="btn btn-primary float-end" onclick="do_opencv_magic();">opencv</button>
</div>
</div>
<canvas id="canvas-debug"></canvas>
</div>
<script>
function toggleFullscreen() {
let elem = document.querySelector("#output");
canvas_draw.style.width = video.offsetWidth
if (!document.fullscreenElement) {
elem.requestFullscreen().catch((err) => {
alert(
`Error attempting to enable fullscreen mode: ${err.message} (${err.name})`,
);
});
} else {
document.exitFullscreen();
}
}
var video = document.querySelector("#video");
var out = document.querySelector("#output");
// width of FoV -- will be supplied by FLASK microscope setup.
var real_width_FoV = 255;
// opencv stuff
var canvas_draw = document.getElementById("canvas-draw");
const context = canvas_draw.getContext('2d');
var contours;
var hierarchy;
var objects_tracked = [];
var objects_lost = [];
function do_opencv_magic() {
var cap = new cv.VideoCapture(video);
let src = new cv.Mat(video.offsetHeight, video.offsetWidth, cv.CV_8UC4);
let dst = new cv.Mat(video.offsetHeight, video.offsetWidth, cv.CV_8UC1);
var rects_old_frame = [];
var objects_last = [];
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
const FPS = 30;
var framecount = 0;
function processVideo() {
cap.read(src);
framecount+=1;
let objects_this = [];
let object_found = false;
let where = '';
for (let k = 0; k < objects_tracked.length; ++k){
if (objects_tracked[k].at(-1)[0] < framecount-1){
objects_lost.push(objects_tracked[k]);
objects_tracked.splice(k, 1);
}
}
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
return;
}
let begin = Date.now();
// start processing.
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(dst, dst, 120, 200, cv.THRESH_BINARY);
// You can try more different parameters
// Find contours
cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
// iterate over contours
for (let i = 0; i < contours.size(); ++i) {
let rect_found = false;
let cnt = contours.get(i);
// exclude contours with an area < 1000
if (cv.contourArea(cnt) < 1000){
continue;
}
// get the bounding rect of the contour
let rect = cv.boundingRect(cnt);
// first check if there are objects that currently get tracked that fit the detected contour rect
for (let k = 0; k < objects_tracked.length; ++k){
let dist = (objects_tracked[k].at(-1)[1].x-rect.x)**2 + (objects_tracked[k].at(-1)[1].y-rect.y)**2;
if (dist < 100000 && objects_tracked[k].at(-1)[0] < framecount) {
objects_tracked[k].push([framecount, rect]);
rect_found = true;
where = k;
break;
}
}
if (rect_found){
let rectangleColor = new cv.Scalar(255, 0, 255,255);
let point1 = new cv.Point(rect.x, rect.y);
let point2 = new cv.Point(rect.x + rect.width, rect.y + rect.height);
cv.rectangle(src, point1, point2, rectangleColor, 2, cv.LINE_AA, 0);
cv.putText(src, String(where), point1, cv.FONT_HERSHEY_COMPLEX, 1, rectangleColor, 1, cv.LINE_8)
continue;
}
for (let j = 0; j < objects_last.length; ++j){
let dist = (objects_last[j].x-rect.x)**2 + (objects_last[j].y-rect.y)**2;
if (dist < 1000 ){
objects_tracked.push([[framecount-1, objects_last[j]], [framecount, rect]]);
//let my_img = new cv.Mat();
//my_img = src.roi(rect);
//cv.imshow("canvas-debug", my_img);
rect_found = true;
break;
}
}
if (rect_found){
let rectangleColor = new cv.Scalar(255, 0, 255,255);
let point1 = new cv.Point(rect.x, rect.y);
let point2 = new cv.Point(rect.x + rect.width, rect.y + rect.height);
cv.rectangle(src, point1, point2, rectangleColor, 2, cv.LINE_AA, 0);
cv.putText(src, String(objects_tracked.length), point1, cv.FONT_HERSHEY_COMPLEX, 1, rectangleColor, 1, cv.LINE_8)
continue;
}
objects_this.push(rect);
let rectangleColor = new cv.Scalar(255, 0, 255,255);
let point1 = new cv.Point(rect.x, rect.y);
let point2 = new cv.Point(rect.x + rect.width, rect.y + rect.height);
cv.rectangle(src, point1, point2, rectangleColor, 2, cv.LINE_AA, 0);
//cv.drawContours(dst, contours, i, color, 1, cv.LINE_8, hierarchy, 100);
}
objects_last = objects_this;
let contoursColor = new cv.Scalar(0, 0, 255,255);
cv.drawContours(src, contours, -1, contoursColor, 1 );
cv.imshow("canvas-draw", src);
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.log(cv.exceptionFromPtr(err));
contours.delete();
hierarchy.delete();
cap.delete();
}
};
// schedule the first one.
setTimeout(processVideo, 0);
};
// init video switching get IDs of video inputs
var deviceIDs = [];
navigator.mediaDevices
.enumerateDevices()
.then((devices) => {
devices.forEach((device) => {
if (device.kind=="videoinput"){
deviceIDs.push(device.deviceId);
}
console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
});
})
.catch((err) => {
console.error(`${err.name}: ${err.message}`);
});
// toggle between cameras
var device_index = 0;
function toggle_cam(){
device_index += 1
if (device_index>=deviceIDs.length){
device_index=0
};
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: {
deviceId: deviceIDs[device_index],
}, })
.then(function (stream) {
video.srcObject = stream;
})
.catch(function (error) {
console.log("Something went wrong!");
});
}
};
let streaming = false;
function startup() {
output = document.getElementById("output");
video = document.getElementById("video");
canvas = document.getElementById("canvas-temp");
canvas_draw = document.getElementById("canvas-draw");
photo = document.getElementById("photo");
startButton = document.getElementById("start-button");
navigator.mediaDevices
.getUserMedia({ video: {width: { ideal: 99999} , height: { ideal: 99999 }}, audio: false })
.then((stream) => {
video.srcObject = stream;
video.play();
})
.catch((err) => {
console.error(`An error occurred: ${err}`);
});
video.addEventListener(
"canplay",
(ev) => {
if (!streaming) {
video_aspect = video.videoWidth / video.videoHeight;
video.style.aspectRatio = video_aspect;
video.height = video.offsetHeight;
video.width = video.offsetWidth;
photo.style.aspectRatio = video_aspect;
canvas.style.aspectRatio = video_aspect;
canvas_draw.style.aspectRatio = video_aspect;
//canvas_draw.width = canvas_draw.width*5;
//canvas_draw.height = canvas_draw.height*5;
streaming = true;
}
},
false,
);
}
window.addEventListener("load", startup, false);
</script>
</body>
</html>