// // 导入tensorflow.js
// importScripts("https://cdn.staticfile.org/tensorflow/3.14.0/tf.min.js")
// var model;
// const list = get_label();
// function preprocess(imageTensor) {
// const widthToHeight = imageTensor.shape[1] / imageTensor.shape[0];
// let squareCrop;
// if (widthToHeight > 1) {
// const heightToWidth = imageTensor.shape[0] / imageTensor.shape[1];
// const cropTop = (1-heightToWidth) / 2;
// const cropBottom = 1 - cropTop;
// squareCrop = [[cropTop, 0, cropBottom, 1]];
// } else {
// const cropLeft = (1-widthToHeight) / 2;
// const cropRight = 1 - cropLeft;
// squareCrop = [[0, cropLeft, 1, cropRight]];
// }
// // Expand image input dimensions to add a batch dimension of size 1.
// const crop = tf.image.cropAndResize(
// tf.expandDims(imageTensor), squareCrop, [0], [224, 224]);
// return crop.div(255);
// }
// async function setup(){
// print("开始");
// // 设置loop函数为1000ms执行一次
// loop_ms(1000);
// // 加载模型
// model = await tf.loadGraphModel(tf.io.browserFiles(get_model()));
// }
// // loop函数会周期执行
// function loop(){
// // ImageData转为Tensor
// img = tf.browser.fromPixels(get_img())
// // 预处理
// pix = preprocess(img);
// // 预测
// const res = model.predict(pix).dataSync();
// res.forEach((score, pred) => {
// if (score > 0.5) print(list[pred]);
// })
// }
let P = 2.5, D = 1;
let speed = 100, last_error = 0, last_center = -1;
// setup函数仅执行一次,完成初始化
function setup(){
print("开始");
// 设置loop函数为100ms执行一次
loop_ms(100);
}
// loop函数会周期执行
function loop(){
// 获取图片ImageData,并转换为opencv格式
let src = img2Mat(get_img());
// 创建一个图像
let dst = new cv.Mat();
// 转换灰度图
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
// 自适应阈值二值化
cv.adaptiveThreshold(dst, dst, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 2);
// 裁剪ROI图像
src = dst.roi(new cv.Rect(0, dst.rows/3, dst.cols, 10));
let left = 0, right = src.cols-1, center = src.cols/2;
if (last_center == -1) {
last_center = center;
}
// 左右边界搜索
for (let i = last_center; i < src.cols; i++) {
if (src.ucharAt(5, i) == 0){
right = i;
break;
}
}
for (let i = last_center; i >= 0; i--) {
if (src.ucharAt(5, i) == 0){
left = i;
break;
}
}
// 误差计算
let error = left + 80 - center;
// pid示波器显示
pid_show(error, 0);
// pid计算
let duty = P * error + D * (error - last_error);
// 舵机限幅
if (duty > 500) {
duty = 500;
} else if (duty < -500) {
duty = -500;
}
// 左右电机舵机PWM输出
if (right - left < 220) {
control(speed, speed, duty);
last_error = error;
last_center = center;
}
// 转换为RGBA图像
cv.cvtColor(dst, dst, cv.COLOR_GRAY2RGBA);
// 画线
cv.line(dst, new cv.Point(left, dst.rows/3-5), new cv.Point(left, dst.rows/3+15), new cv.Scalar(255, 0, 0, 255), 2);
cv.line(dst, new cv.Point(right, dst.rows/3-5), new cv.Point(right, dst.rows/3+15), new cv.Scalar(0, 255, 0, 255), 2);
cv.rectangle(dst,{x:0,y:dst.rows/3},{x:dst.cols,y:dst.rows/3+10},[0,0,255,255]);
// 显示图像
img_show(dst);
// 手动释放内存
src.delete();
dst.delete();
}