I am trying to recreate this app in next.js https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#0
To start the data collection, I added a onMouseDown MouseEvent on the button which, triggers this code:
const handleGatherDataForClass: MouseEventHandler = (e) => {
let classNumber = parseInt(e.target.getAttribute('data-1hot'));
console.log('inside EventHandler:', { classNumber });
let state = gatherDataState === STOP_DATA_GATHER ? classNumber : STOP_DATA_GATHER;
console.log({ state });
setGatherDataState(state);
};
Where
classNumber= positive integerSTOP_DATA_GATHER=-1gatherDataState=-1(default)
Here is the original code snippet from the working app: https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#11
After the state of the gatherDataState variable changes, the useEffect hook should run the dataGatherLoop function, which takes frames from the video stream and converts it into tensors:
useEffect(() => {
dataGatherLoop();
}, [gatherDataState]);
function dataGatherLoop() {
console.log('inside Loop: ', {
gatherDataState
});
if (videoPlaying && gatherDataState !== STOP_DATA_GATHER) {
let imageFeatures = tf.tidy(function() {
let videoFrameAsTensor = tf.browser.fromPixels(VIDEO);
let resizedTensorFrame = tf.image.resizeBilinear(
videoFrameAsTensor, [MOBILE_NET_INPUT_HEIGHT, MOBILE_NET_INPUT_WIDTH],
true
);
let normalizedTensorFrame = resizedTensorFrame.div(255);
return mobilenet.predict(normalizedTensorFrame.expandDims()).squeeze();
});
imageFeatures.print();
setTrainData((prev) => ({
trainX: [...prev.trainX, imageFeatures],
trainY: [...prev.trainY, gatherDataState],
}));
// Intialize array index element if currently undefined.
let newCount = [...examplesCount];
if (examplesCount[gatherDataState] === undefined) {
newCount[gatherDataState] = 1;
setExamplesCount(newCount);
} else {
newCount[gatherDataState]++;
setExamplesCount(newCount);
}
window.requestAnimationFrame(dataGatherLoop);
}
}
This loop runs, as long as the gatherDataState variable is a positive integer (not equal to -1)
After the mouse button is released, an onMouseUp event is triggered which runs the same handleGatherDataForClass function as the onMouseDown event. This should change the state back to -1 and therefore stop the Loop.
Problem:
Even though the state is changing to -1 after the onMouseUp event is triggered, the gatherDataState ends up being a positive integer every time.. Therefore the loop is not stopping. (there is NO setGatherDataState function anywhere else in the code)
I tried:
- writing the
gatherDataLoopfunction inside thehandleGatherDataForClassevent handler and passing thegatherDataStatevariable as an argument - using a global variable for
gatherDataStateinstead of a react state to save the currentgatherDataState - canceling the
requestAnimationFrameloop with thecancelAnimationFramefunction (saving the id globally and as state)