mask after finding shape's contour - node.js

I'm trying to write ANPR project in nodejs.
I managed to draw the contours around the license plate, but now I want to mask it.
this is what I got now (just without the text):
i want to mask it like so (and even crop it afterwards):
this is my code by now:
import cv from 'opencv4nodejs';
// read image, grayscale
const img = cv.imread('./images/img2.jpg');
const grayImg = img.bgrToGray();
const bfilter = grayImg.bilateralFilter(11, 17, 17);
const edged = bfilter.canny(30, 200);
const getContour = (handMask) => {
const mode = cv.RETR_TREE;
const method = cv.CHAIN_APPROX_SIMPLE;
const contours = handMask.findContours(mode, method);
return contours
.sort((c0, c1) => c1.area - c0.area)
.slice(0, 10)
.find((contour) => {
const x = contour.approxPolyDP(10, true);
return x.length === 4;
});
};
let edgeContour = getContour(edged);
let mask = new cv.Mat(grayImg.rows, grayImg.cols, 0, 0);
let x = img.drawContours([edgeContour.getPoints()], 0, new cv.Vec3(0, 255, 0), {
thickness: 5,
});
x = img.bitwiseAnd(img);
cv.imshow('drawContours', x);
cv.waitKey();

Related

Getting 0 from x, y, bbox values of svg elements and setting the values manually is not working

I am using svgjs library as following:
const fs = require('fs');
const { createSVGWindow } = require('svgdom')
const window = createSVGWindow()
const document = window.document
const { SVG, registerWindow } = require('#svgdotjs/svg.js')
const setSizeInfoToID = require('./utils');
const svgFromFile = (path) => {
try {
const svgString = fs.readFileSync(path, 'utf8');
return svgString;
} catch (err) {
console.error(err);
}
};
// register window and document
registerWindow(window, document);
const svgFromString = (string) => {
const draw = SVG(document.documentElement);
var svg = draw.svg(string);
return svg;
};
// reading svg string from file
var svgstring = svgFromFile('svgs/test svgs/bib1.svg')
// create SVG document from the strings
var svg = svgFromString(svgstring);
let selector = `[id*="P8_5_" i]`;
const element = svg.findOne(selector);
console.log(element.x());
console.log(element.y());
element.x(1000);
element.y(1000);
console.log(element.x());
console.log(element.y());
//The output I am getting is:
0
0
0
0
here is the svg file I'm working with
I am getting the x, y and bbox values all 0 and setting the values also not working.
This problem is true for every <g> element of the svg. Although I can use the same methods to get and set x,y and bbox values from similar svg files

How to convert an array of bytes into an image that can be drawn onto a canvas?

I'm using node-canvas to do some image manipulation (in this example to convert the image to a grayscale version, just to keep the example simple). I have no issues getting the raw data, but I'm having trouble working out how to convert the derived array of data back into something that the canvas context can draw.
import { writeFile } from "fs/promises";
import { loadImage } from "canvas"
import { OUTPUT, WIDTH, HEIGHT } from "../config";
const fadeToGray = ctx => {
const src = ctx.getImageData(0, 0, WIDTH, HEIGHT).data;
const dst = new Uint32Array(src.length >> 2);
for (let i = 0; i < src.length; i += 2) {
dst[i >> 2] = (src[i] * 4899 + src[++i] * 9617 + src[++i] * 1868 + 8192) >> 14;
}
// I'm stuck here!
const image = CONVERT_BYTES_TO_IMAGE(dst);
ctx.drawImage(image, 0, 0, WIDTH, HEIGHT);
}
const start = async () => {
const image = await loadImage('input/test.png');
const canvas = createCanvas(WIDTH, HEIGHT);
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, WIDTH, HEIGHT);
fadeToGray(ctx);
writeFile(`${OUTPUT}/test.png`, canvas.toBuffer("image/png"));
}
start().then(() => {
console.log('done')
}).catch(err => {
console.error('dammit', err)
});
I feel like I'm missing something very obvious. How do I convert my array of bytes back into a drawable image?

Error on provided shape, expected (1200000) and actual (400000) tensor values are different

Is there any way to have the input image values match the expected values? The input image I know for a fact is 800px in width, 500px in height, and is colored (meaning 3 channels), so the shape should be [800,500,3].
However, I receive the error below:
The error: Error: Based on the provided shape, [800,500,3], the tensor should have 1200000 values but has 400000
Is there any way to give the image a value of 1200000, or a way to adjust the shape to 400000 but still retain the 800x500 size with 3 channels?
The code:
var tf = require('#tensorflow/tfjs-node');
const fs = require(`fs`)
const Jimp = require(`jimp`)
const image = `./1-1.png`
const imageWidth = 800;
const imageHeight = 500;
const imageChannels = 3;
const getData = async function (path) {
const data = [];
const image = await Jimp.read(path);
await image
.scan(0, 0, imageWidth, imageHeight, (x, y, idx) => {
let v = image.bitmap.data[idx + 0];
data.push(v / 255);
});
return data;
};
const createImage = async (data) => {
const imTen = tf.tensor(data, [imageWidth, imageHeight, 3]);
const inTen = imTen.expandDims();
return inTen;
}
const main = async () => {
const model = await tf.loadLayersModel('file:///retake/savedmodels/model.json');
model.summary();
const a = await getData(image)
const b = await createImage(a)
const tfImage = b
console.log(im)
const prediction = model.predict(tfImage);
prediction.print();
}
main()
The input image I know for a fact is 800px in width, 500px in height, and is colored (meaning 3 channels)
Check return value of your getData method since it seems its returning grayscale image - that would match 400,000 instead of expected 1,200,000 values

Cadlib draw model with images to bitmap

I am using Cadlib to read DWG, DXF and PDF architecture files, some files have images inside it, I create a DXFModel which I want to add those DXFImages to it then export to jpg, I always get a white image.
DxfModel dxfModel = new DxfModel();
foreach(DxfImage image in cadMimages)
{
dxfModel.Images.Add(image.ImageDef);
image.SetDefaultBoundaryVertices();
dxfModel.Entities.Add(image);
}
GraphicsConfig graphicsConfig = new GraphicsConfig(false, ArgbColors.White)
{
FixedForegroundColor = ArgbColors.Black,
CorrectColorForBackgroundColor = false,
ApplyLineType = true,
DisplayLineWeight = true,
DrawImages =true,
DrawImageFrame=true
};
var boundsCalculator = new BoundsCalculator();
boundsCalculator.GetBounds(dxfModel);
var bounds_ = boundsCalculator.Bounds;
Size maxSize = new Size(4096, 4096);
var width = maxSize.Width;
var height = maxSize.Height;
var point1 = new WW.Math.Point3D(0, height - 1, 0);
var point2 = new WW.Math.Point3D(width - 1, 0, 0);
var to2DTransform = DxfUtil.GetScaleTransform(bounds_.Corner1, bounds_.Corner2, point1, point2);
var bitmap = ImageExporter.CreateAutoSizedBitmap(dxfModel, new GDIGraphics3D(graphicsConfig), SmoothingMode.AntiAlias, to2DTransform, maxSize);
using (Stream stream = File.Create("d:/test.png"))
{
ImageExporter.EncodeImageToPng(bitmap, stream);
}

Infinitely looping background as character moves in Phaser?

I have a background image and a separate ground image that I want to loop infinitely as long as the character is moving forward. When the character stops, the background and ground should not be moving. For similar games it is often suggested to add this.game.background.tilePosition.x -= 1
to the update function. This is not what I am looking for as it makes the background constantly move regardless of whether the character is moving. At the moment my background and ground images are repeating, but they are restricted to this.game.world.setBounds(0, 0, 1280, 800);. Any suggestions would be greatly appreciated. My code is below:
function Hero(game, x, y) {
Phaser.Sprite.call(this, game, x, y, 'player');
//rest of code for Hero constructor....
}
Hero.prototype = Object.create(Phaser.Sprite.prototype);
Hero.prototype.constructor = Hero;
//code for Hero.prototype....
PlayState = {};
PlayState.init = function () {
//code for keyboard...
};
PlayState.preload = function () {
this.game.load.json('level:1', 'data/level01.json');
this.game.load.image('ground', 'images/ground.png'); // I need this to
//repeat infinitely
this.game.load.image('background', 'images/background.png'); // I need
//this to repeat infinitely
this.game.load.spritesheet('player', 'images/player.png', 64, 64);
};
PlayState.create = function () {
this.game.world.setBounds(0, 0, 1280, 800);
this.game.background = this.game.add.tileSprite(0, 0,
this.game.world.width, 800, 'background');
this.game.ground = this.game.add.tileSprite(0, 680,
this.game.world.width, 166, 'ground');
this.game.physics.arcade.enable(this.game.ground);
this.game.ground.body.immovable = true;
this.game.ground.body.allowGravity = false;
this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
this._loadLevel(this.game.cache.getJSON('level:1'));
};
PlayState.update = function () {
this.physics.arcade.collide(this.player, this.game.ground);
};
PlayState._loadLevel = function (data) {
this._spawnPlayer({player: data.player});
const GRAVITY = 1200;
this.game.physics.arcade.gravity.y = GRAVITY;
};
PlayState._spawnPlayer = function (data) {
this.player = new Hero(this.game, data.player.x, data.player.y);
this.game.add.existing(this.player);
this.game.camera.follow(this.player,
Phaser.Camera.FOLLOW_PLATFORMER);
};
window.onload = function () {
let game = new Phaser.Game(866, 520, Phaser.CANVAS, 'game');
game.state.add('play', PlayState);
game.state.start('play');
};
I have tried the following solution (see below) where I create a constructor function for the background. This idea is from an existing tutorial done in TypeScript that does exactly what I am looking for. However, I am not familiar with TypeScript so I have just tried to interpret the code from the tutorial as best I can and put it into Javascript but at the moment I am getting the error TypeError: "a is undefined"in the console. I am still learning Javascript and I can't see where I am going wrong. (I have included the keyboard logic and the character movement this time for clarity.)
function MyBackground(game, x, y) {
Phaser.Sprite.call(this, game, x, y, 'background');
}
MyBackground.prototype = Object.create(Phaser.Sprite.prototype);
MyBackground.prototype.constructor = MyScene;
MyBackground.prototype.repeatScene = function () {
this.nextFrame = new Phaser.Sprite(this.game, this.width, 0, "background", 0);
this.game.add.existing(this.nextFrame);
};
function Hero(game, x, y) {
Phaser.Sprite.call(this, game, x, y, 'player');
this.anchor.set(0.5, 0.5);
this.game.physics.enable(this);
this.body.collideWorldBounds = false;
this.animations.add('stop', [0]);
this.animations.add('run', [1, 2, 3, 4, 5], 14, true); // 14fps looped
this.animations.add('jump', [6]);
this.animations.add('fall', [7]);
this.animations.add('die', [8, 9, 8, 9, 8, 9, 8, 9], 12); // 12fps no loop
}
Hero.prototype = Object.create(Phaser.Sprite.prototype);
Hero.prototype.constructor = Hero;
Hero.prototype.move = function (direction) {
const SPEED = 200;
this.body.velocity.x = direction * SPEED;
// update image flipping & animations
if (this.body.velocity.x < 0) {
this.scale.x = -1;
}
else if (this.body.velocity.x > 0) {
this.scale.x = 1;
}
};
Hero.prototype.jump = function () {
const JUMP_SPEED = 600;
let canJump = this.body.touching.down;
if (canJump) {
this.body.velocity.y = -JUMP_SPEED;
}
return canJump;
};
Hero.prototype.bounce = function () {
const BOUNCE_SPEED = 200;
this.body.velocity.y = -BOUNCE_SPEED;
};
Hero.prototype.update = function () {
// update sprite animation, if it needs changing
let animationName = this._getAnimationName();
if (this.animations.name !== animationName) {
this.animations.play(animationName);
}
};
Hero.prototype.die = function () {
this.alive = false;
this.body.enable = false;
this.animations.play('die').onComplete.addOnce(function () {
this.kill();
}, this);
};
Hero.prototype._getAnimationName = function () {
let name = 'stop'; // default animation
if (!this.alive) {
name = 'die';
}
else if (this.body.velocity.y > 0 && !this.body.touching.down) {
name = 'fall';
}
else if (this.body.velocity.y < 0) {
name = 'jump';
}
else if (this.body.velocity.x !== 0 && this.body.touching.down ) {
name = 'run';
}
return name;
PlayState = {};
PlayState.init = function () {
this.game.renderer.renderSession.roundPixels = true;
this.keys = this.game.input.keyboard.addKeys({
left: Phaser.KeyCode.LEFT,
right: Phaser.KeyCode.RIGHT,
up: Phaser.KeyCode.UP
};
PlayState.preload = function () {
this.game.load.json('level:1', 'data/level01.json');
this.game.load.image('ground', 'images/ground.png'); // I need this to repeat infinitely
this.game.load.image('background', 'images/background.png'); // I need this to repeat infinitely
this.game.load.spritesheet('player', 'images/player.png', 64, 64);
};
PlayState.create = function () {
this.background = new MyBackground(this.game, 0, 0);
this.game.add.existing(this.MyBackground);
this.game.physics.arcade.enable(this.game.ground);
this.game.ground.body.immovable = true;
this.game.ground.body.allowGravity = false;
this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
this._loadLevel(this.game.cache.getJSON('level:1'));
this.game.world.setBounds(0, 0, this.MyBackground.width * 2, 800);
};
PlayState.update = function () {
var backgroundWidth = this.game.stage.getChildAt(0).getBounds().width; //getChildAt(0) because the background is created first in create
if (this.x > backgroundWidth * .75) {
this.x = backgroundWidth * .25;
repeatScene();
};
this._handleInput();
this.physics.arcade.collide(this.player, this.game.ground);
};
PlayState._handleInput = function () {
if (this.keys.up.isDown) {
this.player.jump();
} else if (this.keys.right.isDown) { // move hero right
this.player.move(1);
} else if (this.keys.left.isDown) { // move hero left
this.player.move(-1);
} else { // stop
this.player.move(0);
}
};
PlayState._loadLevel = function (data) {
this._spawnPlayer({player: data.player});
const GRAVITY = 1200;
this.game.physics.arcade.gravity.y = GRAVITY;
};
PlayState._spawnPlayer = function (data) {
this.player = new Hero(this.game, data.player.x, data.player.y);
this.game.add.existing(this.player);
this.game.camera.follow(this.player, Phaser.Camera.FOLLOW_PLATFORMER);
};
window.onload = function () {
let game = new Phaser.Game(866, 520, Phaser.CANVAS, 'game');
game.state.add('play', PlayState);
game.state.start('play');
};

Resources