cv.undistort "Assertion failed" error in Javascript - javascript

I am trying to undistort an image with opencv.js before scanning aruco markers with my camera.
Scanning the codes is not a problem but when i try to undistort the image first with cv.undistort i run into an Assertion failed error which looks something like this.
Minimal working example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script id="cv" async src="opencv.js"></script>
</head>
<body>
<canvas id="canvasOutput" width="640" height="480"></canvas>
</body>
<script>
document.getElementById('cv').addEventListener('load', async () => {
if (cv.getBuildInformation) {
console.log(cv.getBuildInformation());
onloadCallback();
}
else {
// WASM
if (cv instanceof Promise) {
cv = await cv;
console.log(cv.getBuildInformation());
onloadCallback();
} else {
cv['onRuntimeInitialized'] = () => {
console.log(cv.getBuildInformation());
onloadCallback();
}
}
}
});
function onloadCallback() {
var canvas = document.getElementById('canvasOutput')
var ctx = canvas.getContext("2d", { willReadFrequently: true });
var video_element = document.createElement("video")
video_element.id = "video-stream"
navigator.mediaDevices.getUserMedia({
video: {}}).then(function (stream) {
video_element.srcObject = stream;
video_element.play();
video_element.addEventListener('canplay', function () {
requestAnimationFrame(() => {processImage()});
}, false);
});
function processImage() {
if (video_element.readyState === video_element.HAVE_ENOUGH_DATA) {
ctx.drawImage(video_element, 0, 0, canvas.width,canvas.height);
var inputImage = cv.imread("canvasOutput");
var cameraMatrix = cv.matFromArray(3, 3, cv.CV_64F, [740.50225182, 0, 369.29446792, 0, 740.73074392, 252.55216544, 0, 0, 1]);
var newCameraMatrix = cv.matFromArray(3, 3, cv.CV_64F, [719.72668457, 0, 374.17970017, 0, 711.57000732, 251.96928564, 0, 0, 1]);
var distCoeffs = cv.matFromArray(1, 5, cv.CV_64F, [0.0798354, -0.55563903, -0.00168822, 0.00225224, 0.28264803]);
cv.cvtColor(inputImage, inputImage, cv.COLOR_RGBA2RGB, 0);
var markerIds = new cv.Mat();
var markerCorners = new cv.MatVector();
var rvecs = new cv.Mat();
var tvecs = new cv.Mat();
var dictionary = new cv.Dictionary(cv.DICT_6X6_1000);
cv.undistort(inputImage,cameraMatrix,distCoeffs,newCameraMatrix);
cv.detectMarkers(inputImage,dictionary, markerCorners, markerIds);
if (markerIds.rows > 0) {
cv.drawDetectedMarkers(inputImage,markerCorners,markerIds);
cv.estimatePoseSingleMarkers(markerCorners, 0.1, cameraMatrix,distCoeffs,rvecs,tvecs);
for (let i = 0; i < markerIds.rows; ++i) {
rvec = cv.matFromArray(3, 1, cv.CV_64F, [rvecs.doublePtr(0, i)[0],rvecs.doublePtr(0, i)[1],rvecs.doublePtr(0, i)[2]]);
tvec = cv.matFromArray(3, 1, cv.CV_64F, [tvecs.doublePtr(0, i)[0],tvecs.doublePtr(0, i)[1],tvecs.doublePtr(0, i)[2]]);
cv.drawAxis(inputImage,cameraMatrix,distCoeffs,rvec, tvec, 0.1);
rvec.delete();
tvec.delete();
}
}
cv.imshow("canvasOutput",inputImage);
inputImage.delete();
dictionary.delete();
markerIds.delete();
markerCorners.delete();
rvecs.delete();
tvecs.delete();
cameraMatrix.delete();
newCameraMatrix.delete();
distCoeffs.delete();
}
requestAnimationFrame(() => {processImage()});
}
}
</script>
</html>
where the opencv.js file in the head can be any OpenCV js version (example https://docs.opencv.org/3.4.0/opencv.js)
I have no idea what this means and i'm not sure how to make it work.
I think I defined the size of the camera matrix correctly as well as the sizes of all other parameters but I just keep getting the same error.
When I try to do this in python everything works fine. I can't seem to figure out what I'm doing wrong when I try to replicate this in javascript.

The problem was that the cv.undistort method didn't have proper parameters passed to it, more specificaly it was called with 4 parameters instead of 5 and it didn't have the output parameter defined:
cv.undistort(inputImage,cameraMatrix,distCoeffs,newCameraMatrix);
should be
var output = new cv.Mat();
cv.undistort(inputImage, output,cameraMatrix, distCoeffs, newCameraMatrix );

Related

How to make canvas lines visible when dragging (no libraries, only vanilla JS, React.JS if necessary.)

I'd like to add lines by two clicks, when moving the mouse the line should be visible. When click left mouse button again the line should be added. Only left button should draw.
How should I change my code to do this? (for now it allows to create lines,
but they aren't visible before mouseup).
Any help is appreciated! Thanks!
const canvasEl = document.getElementById('drawContainer')
canvasEl.style.position = 'absolute'
canvasEl.style.top = '12%'
canvasEl.style.left = '32%'
var lines = [], line;
const context = canvasEl.getContext('2d')
const collapseLinesBtn = document.getElementById('collapse_lines')
let startPosition = {x: 0, y: 0}
let lineCoordinates = {x: 0, y: 0}
let isDrawStart = false
const getClientOffset = (event) => {
const {pageX, pageY} = event.clicks ? event.clicks[0] : event
const x = pageX - canvasEl.offsetLeft
const y = pageY - canvasEl.offsetTop
return { x, y }
}
const initialDraw = () => {
context.beginPath() //allows to prevent previously created lines from delete
context.moveTo(startPosition.x, startPosition.y)
context.lineTo(lineCoordinates.x, lineCoordinates.y)
context.stroke()
line = [];
line.push([lineCoordinates.x, lineCoordinates.y]);
console.log(line)
}
const mouseDownListener = (e) => {
startPosition = getClientOffset(e)
//isDrawStart = true // isDrawStart = true + clearCanvas() + initialDraw() from const mouseMoveListener = one visible line when dragging + coordinates
context.beginPath();
context.moveTo(e.offsetX, e.offsetY);
context.lineTo(e.offsetX, e.offsetY);
}
const mouseMoveListener = (event) => {
if(!isDrawStart)
return
lineCoordinates = getClientOffset(event)
//clearCanvas()
//initialDraw()
//initialDraw(!isDrawStart())
}
const mouseUpListener = (e) => {
isDrawStart = false
context.lineTo(e.offsetX, e.offsetY);
context.stroke();
}
const clearCanvas = () => {
context.clearRect(0, 0, canvasEl.width, canvasEl.height)
}
canvasEl.addEventListener('mousedown', mouseDownListener)
canvasEl.addEventListener('mousemove', mouseMoveListener)
canvasEl.addEventListener('mouseup', mouseUpListener)
collapseLinesBtn.addEventListener('click', function clear() {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#collapse_lines {
position: absolute;
bottom: 75px;
left: 47%;
padding: 10px 25px;
font-size: 1rem;
}
</style>
<title>Test Task</title>
</head>
<body>
<div id="main_container">
<canvas id="drawContainer" width="700" height="700" style="border: 1px solid rgb(10, 10, 10)" ></canvas>
<button id="collapse_lines">collapse lines</button>
</div>
<script src="./app.js"></script>
</body>
</html>
In your mouseMoveListener just do something similar as you do in your mouseUpListener, without setting isDrawStart = false:
const mouseMoveListener = (event) => {
if(!isDrawStart)
return
lineCoordinates = getClientOffset(event)
// Clear the canvas each frame
clearCanvas()
// Similar to mouseUpListener
context.lineTo(lineCoordinates.x, lineCoordinates.y);
context.stroke();
}

I want to convert paper.js Examples from paperscript to javascript

I am Japanese and I apologize for my unnatural English, but I would appreciate it if you could read it.
I learned how to convert paperscript to javascript from the official documentation.
Its means are as follows
Change the type attribute of the script tag to text/paperscript. <script type="text/paperscript" src="./main.js"></script>
Enable Paperscope for global use.  paper.install(window)
Specify the target of the canvas. paper.setup(document.getElementById("myCanvas"))
Write the main code in the onload window.onload = function(){ /* add main code */ }
Finally, add paper.view.draw()
The onFrame and onResize transforms as follows. view.onFrame = function(event) {}
onMouseDown, onMouseUp, onMouseDrag, onMouseMove, etc. are converted as follows. var customTool = new Tool(); customTool.onMouseDown = function(event) {};
I have tried these methods, but applying these to the Examples on the paper.js official site does not work correctly.
The following code is the result of trying these.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://unpkg.com/paper"></script>
<script type="text/javascript" src="./main.js"></script>
<title>Document</title>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>
paper.install(window);
console.log("run test")
var myCanvas = document.getElementById("myCanvas")
var customTool = new Tool();
window.onload = function(){
paper.setup(myCanvas)
var points = 25;
// The distance between the points:
var length = 35;
var path = new Path({
strokeColor: '#E4141B',
strokeWidth: 20,
strokeCap: 'round'
});
var start = view.center / [10, 1];
for (var i = 0; i < points; i++)
path.add(start + new Point(i * length, 0));
customTool.onMouseMove=function(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
var vector = segment.point - nextSegment.point;
vector.length = length;
nextSegment.point = segment.point - vector;
}
path.smooth({ type: 'continuous' });
}
customTool.onMouseDown=function(event) {
path.fullySelected = true;
path.strokeColor = '#e08285';
}
customTool.onMouseUp=function(event) {
path.fullySelected = false;
path.strokeColor = '#e4141b';
}
view.draw();
}
The original paperscript can be found here.
What is the problem with this code?
Thank you for reading to the end!
The var vector in the for loop is not getting the correct values in your code. Change the math operators and it will work like the paperjs demo.
Math operators (+ - * /) for vector only works in paperscript. In Javascript, use .add() .subtract() .multiply() .divide(). see http://paperjs.org/reference/point/#subtract-point
// paperscript
segment.point - nextSegment.point
// javascript
segment.point.subtract(nextSegment.point)
Here's a working demo of your example
paper.install(window);
console.log("run test")
var myCanvas = document.getElementById("myCanvas")
var customTool = new Tool();
window.onload = function() {
paper.setup(myCanvas)
var points = 15; //25
// The distance between the points:
var length = 20; //35
var path = new Path({
strokeColor: '#E4141B',
strokeWidth: 20,
strokeCap: 'round'
});
var start = view.center / [10, 1];
for (var i = 0; i < points; i++) {
path.add(start + new Point(i * length, 0));
}
customTool.onMouseMove = function(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
//var vector = segment.point - nextSegment.point;
var vector = segment.point.subtract(nextSegment.point);
vector.length = length;
//nextSegment.point = segment.point - vector;
nextSegment.point = segment.point.subtract(vector);
}
path.smooth({
type: 'continuous'
});
}
customTool.onMouseDown = function(event) {
path.fullySelected = true;
path.strokeColor = '#e08285';
}
customTool.onMouseUp = function(event) {
path.fullySelected = false;
path.strokeColor = '#e4141b';
}
view.draw();
}
html,
body {
margin: 0
}
canvas {
border: 1px solid red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://unpkg.com/paper"></script>
<!-- you can add this back in -->
<!-- <script type="text/javascript" src="./main.js"></script> -->
<title>Document</title>
</head>
<body>
<!-- set any size you want, or use CSS/JS to make this resizable -->
<canvas id="myCanvas" width="600" height="150"></canvas>
</body>
</html>

Baffled by NaN - HTML CANVAS JS

I'm trying to create a timer within an object - however when trying to increment the counter by the time that's passed I'm getting a NaN error. The error stops if I replace the deltaTime argument with a constant, but then the jump time would vary depending upon the end users machine and work load.
class Actor {
constructor() {
this.jumpCounter = 0
this.jumpTimer = function (deltaTime) {
console.log(this.jumpCounter);
this.jumpCounter += deltaTime;
console.log(deltaTime)
}
}
}
let canvas = document.getElementById('gameScreen');
let ctx = canvas.getContext("2d");
var lastTime = 0;
const GAME_WIDTH = 600;
const GAME_HEIGHT = 600;
actor = new Actor;
function gameLoop(timestamp) {
let deltaTime = timestamp - lastTime;
lastTime = timestamp;
ctx.fillStyle = 'rgba(155, 200, 155, 0.3)'
ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
actor.jumpTimer(deltaTime)
requestAnimationFrame(gameLoop);
}
gameLoop();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game Sandbox</title>
<style>
#gameScreen {
border: 1px solid;
}
</style>
</head>
<body>
<canvas id="gameScreen" width="600" height="600"></canvas>
<script></script>
</body>
</html>
As the error resulted from there being on timestamp on the first run through of the code this fixed the issue:
this.jumpTimer = function (deltaTime) {
if (!deltaTime) return;
console.log(this.jumpCounter);
this.jumpCounter += deltaTime;
console.log(deltaTime)
}

javascript: uncaught reference error

I am making a javascript game, using Canvas. However, I got that error(below image) and background image is not shown. I suspect below 4 files, because other files didn't make any trouble. I guess the problem is related with game_state...how can I solve the problem??
I am agonizing for 2days:( plz, help me..
error image1
error image2
index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>Lion Travel</title>
<!--GameFramework-->
<script src="/.c9/gfw/GameFramework.js"></script>
<script src="/.c9/gfw/FrameCounter.js"></script>
<script src="/.c9/gfw/InputSystem.js"></script>
<script src="/.c9/gfw/SoundManager.js"></script>
<script src="/.c9/gfw/GraphicObject.js"></script>
<script src="/.c9/gfw/SpriteAnimation.js"></script>
<script src="/.c9/gfw/ResourcePreLoader.js"></script>
<script src="/.c9/gfw/DebugSystem.js"></script>
<script src="/.c9/gfw/Timer.js"></script>
<script src="/.c9/gfw/FrameSkipper.js"></script>
<script src="/.c9/gfw/TransitionState.js"></script>
<!--GameInit-->
<script src="/.c9/gfw/gfw.js"></script>
<!--Game Logic-->
<script src="/.c9/RS_Title.js"></script>
</head>
<body>
<canvas id="GameCanvas" width="800" height="600">html5 canvas is not supported.</canvas>
</body>
</html>
gfw.js
function onGameInit() {
document.title = "Lion Travel";
GAME_FPS = 30;
debugSystem.debugMode = true;
resourcePreLoader.AddImage("/.c9/title_background.png");
soundSystem.AddSound("/.c9/background.mp3", 1);
after_loading_state = new TitleState();
setInterval(gameLoop, 1000 / GAME_FPS);
}
window.addEventListener("load", onGameInit, false);
RS_Title.js
function TitleState()
{
this.imgBackground = resourcePreLoader.GetImage("/.c9/title_background.png");
soundSystem.PlayBackgroundMusic("/.c9/background.mp3");
return this;
}
TitleState.prototype.Init = function()
{
soundSystem.PlayBackgroundMusic("/.c9/background.mp3");
};
TitleState.prototype.Render = function()
{
var theCanvas = document.getElementById("GameCanvas");
var Context = theCanvas.getContext("2d");
//drawing backgroundimage
Context.drawImage(this.imgBackground, 0, 0);
};
TitleState.prototype.Update = function()
{
};
GameFramework.js
var GAME_FPS;
var game_state = after_loading_state;
function ChangeGameState(nextGameState)
{
//checking essential function
if(nextGameState.Init == undefined)
return;
if(nextGameState.Update == undefined)
return;
if(nextGameState.Render == undefined)
return;
game_state = nextGameState;
game_state.Init();
}
function Update()
{
timerSystem.Update();
game_state.Update();
debugSystem.UseDebugMode();
}
function Render()
{
//drawing
var theCanvas = document.getElementById("GameCanvas");
var Context = theCanvas.getContext("2d");
Context.fillStyle = "#000000";
Context.fillRect(0, 0, 800, 600);
//game state
game_state.Render();
if(debugSystem.debugMode)
{
//showing fps
Context.fillStyle = "#ffffff";
Context.font = '15px Arial';
Context.textBaseline = "top";
Context.fillText("fps: "+ frameCounter.Lastfps, 10, 10);
}
}
function gameLoop()
{
Update();
Render();
frameCounter.countFrame();
}
The issue here is that you are initializing game_state with the object after_loading_state even before after_loading_state is initialized(which is initialized only after the document is loaded). Due to this game_state remains undefined.
To fix this, change var game_state = after_loading_state; in GameFramework.js to var game_state;. And add game_state = after_loading_state; as the first line in gameLoop function. This way, the initialization of variables occur in the correct order.

Trying to get decibel levels from an audio file through javascript

I've been looking at the information here:
Is there a way get something like decibel levels from an audio file and transform that information into a json array?
But when I try to run the JSBin here:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Get Audio Data</title>
<link rel="stylesheet" type="text/css" href="index.css">
<script type="text/javascript" src="music.js"></script>
</head>
<body>
<div id=meter></div>
</body>
</html>
#meter {
width: 500px;
height: 15px;
margin: 2px 0;
background: green;
-webkit-transition;
width .05s;
}
function() {
var ctx = new webkitAudioContext(),
url = 'test.mp3',
audio = new Audio(url),
processor = ctx.createJavaScriptNode(2048, 1, 1),
meter = document.getElementById('meter'),
source;
audio.addEventListener('canplaythrough', function() {
source = ctx.createMediaElementSource(audio);
source.connect(processor);
source.connect(ctx.destination);
processor.connect(ctx.destination);
audio.play();
}, false);
processor.onaudioprocess = function(evt) {
var input = evt.inputBuffer.getChannelData(0),
len = input.length,
total = i = 0,
rms;
while(i<len)
total += Math.abs(input[i++]);
rms = Math.sqrt(total/len);
meter.style.width = (rms*100) + '%';
};
};
I'm not really sure what it's doing. Can anyone give me more info?
Your code does generate RMS output once you replace defunct API calls
old webkitAudioContext
new
try {
window.AudioContext = window.AudioContext ||
window.webkitAudioContext ||
window.mozAudioContext ||
window.oAudioContext ||
window.msAudioContext;
ctx = new AudioContext();
console.log("cool audio context established ... ctx ");
} catch (e) {
alert("Web Audio API is not supported by this browser\n ... http://caniuse.com/#feat=audio-api");
}
and
old createJavaScriptNode
new createScriptProcessor

Categories