Vue how to draw picture and put next to another - javascript

i want to draw image next to another in this same div.
Generaly drawing works fine, but i have problem with placing one picture next to another.
Every time i draw image it is placend in this same div.
My HTML is:
<div id="thumbnailImages">
<canvas
id="thumbnailImage"
/>
</div>
And code:
function thumbnail(video) {
const canvasThumbnail = document.getElementById('thumbnailImage')
const cth = canvasThumbnail.getContext('2d')
const data = video.slice(8)
imgToHTML(data, e => {
const drawingThumbnail = new Image()
drawingThumbnail.src = e.target.result
drawingThumbnail.onload = function () {
canvasThumbnail.width = 128
canvasThumbnail.height = 128
cth.drawImage(drawingThumbnail, 0, 0)
document.getElementById('thumbnails').appendChild(canvasThumbnail)
}
})
}
I would like to have many 'canvas' in 'thumbnailImages' id.
Can you help me?

The issue is that you are reusing the same canvas over and over again. You need to create a new canvas to put next to it:
function thumbnail(video) {
const canvasThumbnail = document.createElement('canvas');
const cth = canvasThumbnail.getContext('2d')
const data = video.slice(8)
imgToHTML(data, e => {
const drawingThumbnail = new Image()
drawingThumbnail.src = e.target.result
drawingThumbnail.onload = function () {
canvasThumbnail.width = 128
canvasThumbnail.height = 128
cth.drawImage(drawingThumbnail, 0, 0)
document.getElementById('thumbnailImages').appendChild(canvasThumbnail)
}
})
}

Related

Blob images does not show up at UI, although I can see them on console

I am trying to create multiple blob images, and show them for a video timeline UI. To create the images, I take screenshots of the video for some certain time frames, and create img elements, then add img.src as blob images' url. The problem is blob images does not show up at UI, although I can see them on console. Any ideas?
Code snippet from creation of blob images:
// draw the video frame to canvas
const ctx = canvas.getContext("2d");
ctx.drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
ctx.canvas.toBlob(
blob => {
resolve(blob);
},
"image/jpeg",
0.75 /* quality */
);
Code Snippet from creation of images:
let img = '';
for (let i = 0; i < count / 3; i++) {
const cover = await GetVideoCover(item.video_url, i);
var url = URL.createObjectURL(cover);
var image = new Image();
image.src = url;
img += "<img src='"+image.src+"'>";
console.log(img)
}
return img;
The console log from console.log(img)line:
actual html img elements:
When I manually update the source as below, it works, but I did not understand why it does not get the source by itself. Any idea would be appreciated.
Try registering an onload event listener on the image element and then handle all code that depends on that image in the event listener, like so:
for (let i = 0; i < count / 3; i++) {
const cover = await GetVideoCover(item.video_url, i);
var url = URL.createObjectURL(cover);
var image = new Image();
image.src = url;
image.addEventListener('load', (event) => {
// perform some magic here e.g append to DOM or draw the image to canvas
}
}
Thank you for the contributions, the answers did not work but they helped me in the process. I solved the problem today and wanted to share it here.
I should have mentioned before as the created images are fed to vis.js.
When I experimented more, I saw vis.js does not append the created objects, but it changes the innerHTML of the timeline. (vis.js might not support blob images as src of img tag)
Then, I decided to give a shot to append element. To do that, I created a new div element, and appended the created images to that div.
I also added an additional promise level to the blob image creation process, since some files were missing.
Code snippet from newly added promise level:
const blobToImage = (itemVideoURL,captureSecond) => {
return new Promise(async (resolve,reject)=> {
let cover = await GetVideoCover(itemVideoURL,captureSecond);
const url = URL.createObjectURL(cover)
let img = new Image()
img.onload = () => {
URL.revokeObjectURL(url)
resolve(img)
}
img.src = url
img.height = '75'
})
}
Code snippet from new function:
let divElement = document.createElement('div');
for (let i = 0; i < count * 3; i++) {
let newImage = await blobToImage(item.video_url,i+1)
divElement.appendChild(newImage)
}
return divElement;
It magically worked.
You should use a single image rather than multiple images.
Just concatanate all images together :
let imgEle1 = document.querySelectorAll(".image")[0];
let imgEle2 = document.querySelectorAll(".image")[1];
let resEle = document.querySelector(".result");
var context = resEle.getContext("2d");
let BtnEle = document.querySelector(".Btn");
BtnEle.addEventListener("click", () => {
resEle.width = imgEle1.width;
resEle.height = imgEle1.height;
context.globalAlpha = 1.0;
context.drawImage(imgEle1, 0, 0);
context.globalAlpha = 0.5;
context.drawImage(imgEle2, 0, 0);
});

Use Image URL to train Tensorflowjs program

I'm trying to use images off the internet to try and train my network. I'm using an Image() object to create the images and pass them to tensorflow. According to my knowledge, Image() returns a HTMLImageElement, however, I'm still getting the following error:
Error: pixels passed to tf.browser.fromPixels() must be either an HTMLVideoElement, HTMLImageElement, HTMLCanvasElement, ImageData in browser, or OffscreenCanvas, ImageData in webworker or {data: Uint32Array, width: number, height: number}, but was Image
Below is the code I'm running:
const tf = require("#tensorflow/tfjs");
require("#tensorflow/tfjs-node")
const mobilenetModule = require("#tensorflow-models/mobilenet");
const knnClassifier = require("#tensorflow-models/knn-classifier");
const { Image } = require("canvas");
const classifier = knnClassifier.create();
const urls = ["https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Solid_white.svg/2048px-Solid_white.svg.png", "https://stone.co.nz/wp-content/uploads/2020/06/Iconic-Black.jpg", "https://media.tarkett-image.com/large/TH_25094225_25187225_001.jpg"];
async function start() {
const mobilenet = await mobilenetModule.load();
const pic0 = new Image();
pic0.src = urls[0];
pic0.onload = () => {
const img0 = tf.browser.fromPixels(pic0);
const logits0 = mobilenet.infer(img0, true);
classifier.addExample(logits0, 0);
}
const pic1 = new Image();
pic1.src = urls[1];
pic1.onload = () => {
const img1 = tf.browser.fromPixels(pic1);
const logits1 = mobilenet.infer(img1, true);
classifier.addExample(logits1, 1);
}
const checkPic = new Image();
checkPic.src = urls[2];
checkPic.onload = () => {
const x = tf.browser.fromPixels(checkPic);
const xlogits = mobilenet.infer(x, true);
const p = classifier.predictClass(xlogits);
console.log(p);
}
}
start();
Please note that I am a js/nodejs newbie 😊
Seems like an oversight by TFJS team so Image type is not recognized.
do this instead:
const pic0 = document.createElement('image')
This creates HTMLImageElement which is "almost" the same as Image element, but has a different signature that TF expects
And best to report on TFJS Git as an issue, it should be easy to resolve

How to retain order of array using each and image.onload

I'm trying to use image.onload function but async issue is occuring. I'm passing the data through array but it is not executing according to array order in the image.onload function. How can I fix this issue?
Object.entries(data).forEach(element => {
const brushtype = element[0]['brush']
const img = new Image();
img.onload = () => {
brushctx.drawImage(img, 0, 0);
}
img.src = brushtype;
}
The problem is the way you're requesting those images.
By doing
Object.entries(data).forEach(element => {
}
it's happening at the same time virtually. Whatever image finished loading will be drawn right-after.
If you want your images to be drawn in a specific order - e.g. the order it's listed in the array - you need to request a new one after the previous finished loading.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let myImages = ['https://picsum.photos/id/1/50/50', 'https://picsum.photos/id/22/50/50', 'https://picsum.photos/id/83/50/50', 'https://picsum.photos/id/64/50/50'];
function loadImages(index) {
let image = new Image();
image.onload = function(e) {
context.drawImage(e.target, index % 2 * 50, parseInt(index / 2) * 50);
if (index + 1 < myImages.length) {
loadImages(index + 1);
}
}
image.src = myImages[index];
}
loadImages(0);
<canvas id='canvas' width='200' height='200'></canvas>
To draw images in order of request you either need to wait until all images have loaded and then draw them only when the earlier image have been draw. This answer gives an example of both approaches.
Note That if there are any load errors none of the images may be drawn. In the second method an error will mean none to all but one are drawn.
Load first then draw
The snippet bellow loads first then draws. It stores the images in an array images and keeps a count of images loading. Counting up for each new image, and when an image load it counts down.
When the counter is zero when know all images have loaded and can then draw them all
var imgCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
img.src = element[0]['brush'];
images.push(img);
imgCount ++;
img.onload = () => {
imgCount --;
if (!imgCount) {
for(const img of images) { brushctx.drawImage(img, 0, 0) }
}
}
}
Draw only when first or previous loaded.
The alternative is to again create an array to hold all the images. But this time we track what has been drawn. Each time an image is loaded, we check if any of the images in the array before it have loaded, then we draw all images until we find a empty image slot.
var drawnCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
const imgIdx = images.length;
img.src = element[0]['brush'];
img.onload = () => {
images[imgIdx] = img;
while (images[drawnCount]) { brushctx.drawImage(images[drawnCount++], 0, 0) }
}
images.push(null);
}

Async await now working in Nuxt component

I have two functions,
One function converts images from whatever format to canvas, then to WEBP image format.
The other function receives the image and console.log the image.
The problem is that when I log the result of the image in the saveToBackend function, I get a result of undefined, but when I console.log the converted image in the convertImage function, I get the image. Please how can i solve the issue?
Below are the functions in my NUXT app
convertImage(file) {
// convert image
let src = URL.createObjectURL(file)
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d')
let userImage = new Image();
userImage.src = src
userImage.onload = function() {
canvas.width = userImage.width;
canvas.height = userImage.height;
ctx.drawImage(userImage, 0, 0);
let webpImage = canvas.toDataURL("image/webp");
console.log(webpImage); // with this i get the image in the console
return webpImage
}
},
async saveToBackend(file, result) {
// convert images to webp
let webpFile = await this.convertImage(file)
console.log(webpFile); // with this i get undefined in the console
}
You can't return webpImage from inside the onload callback. It simply will not wait for onload to execute. You can instead create a Promise that resolves the value of webpImage when onload completes:
convertImage(file) {
return new Promise((resolve) => {
// convert image
let src = URL.createObjectURL(file);
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let userImage = new Image();
userImage.src = src;
userImage.onload = function() {
canvas.width = userImage.width;
canvas.height = userImage.height;
ctx.drawImage(userImage, 0, 0);
let webpImage = canvas.toDataURL("image/webp");
console.log(webpImage); // with this i get the image in the console
// resolve promise so that saveToBackend can await it
return resolve(webpImage);
};
});
}
Hopefully that helps!

Use JavaScript to AutoClick Button

I have the following javascript code, which takes a photo from a webcam and compares it with another photo stored on the server. What I am trying to do is to take the photo from the webcam automatically, without waiting for the user to click on the take photo button. I am just using
document.getElementById('take_snap').click()
but this code is doing nothing. When I click on the button manually my code works perfectly, but the above code doesn't work.
This is my code:
const imageUploads = document.getElementById('take_snap')
const image_url = document.getElementById('results')
var pid=$('#student_id').val();
Promise.all([
faceapi.nets.faceRecognitionNet.loadFromUri('models'),
faceapi.nets.faceLandmark68Net.loadFromUri('models'),
faceapi.nets.ssdMobilenetv1.loadFromUri('models')
]).then(start)
async function start() {
const container = document.createElement('div')
container.style.position = 'relative'
document.body.append(container)
const labeledFaceDescriptors = await loadLabeledImages()
const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors, 0.6)
let image
let canvas
document.body.append('You can start')
imageUploads.click();
imageUploads.addEventListener('click', async () => {
if (image) image.remove()
if (canvas) canvas.remove()
Webcam.snap( function(data_uri) {
// display results in page
document.getElementById('results').innerHTML =
'<img src="'+data_uri+'" id="img_tag"/>';
var filename= upload_img(data_uri)
document.getElementById('results').innerHTML =
'<img src="upload/'+filename+'" id="img_tags"/>';
} );
console.log( document.getElementById('img_tags').getAttribute('src'));
image = await faceapi.fetchImage(document.getElementById('img_tags').getAttribute('src'))
container.append(image)
canvas = faceapi.createCanvasFromMedia(image)
container.append(canvas)
const displaySize = { width: image.width, height: image.height }
faceapi.matchDimensions(canvas, displaySize)
const detections = await faceapi.detectAllFaces(image).withFaceLandmarks().withFaceDescriptors()
const resizedDetections = faceapi.resizeResults(detections, displaySize)
const results = resizedDetections.map(d => faceMatcher.findBestMatch(d.descriptor))
//console.log( 'descriptor'+d.descriptor)
console.log(detections)
results.forEach((result, i) => {console.log('iiiiiiiiiiiii'+i)
const box = resizedDetections[i].detection.box
const drawBox = new faceapi.draw.DrawBox(box, { label: result.toString() })
console.log('resultttt'+ result.toString())
if(result.toString()!=null || result.toString()!='unknown')
{
$('#tamam').show();
}
if(result.toString().indexOf('unknown'))
{
$('#tamam').hide();
}
drawBox.draw(canvas)
})
})
}
as I mentioned above the code works fine when I click on the button manually but it seems that this code not working when using autoclick.
imageUploads.click();

Categories

Resources