I have a screenshot of the infrared output of a Kinect using OpenKinect on a Mac.
I would like to calculate the distance of the green wall and the orange posts. I'm only bothered about a single dimension array, say y = 240 (along the horizontal center of the image).
I have tried using MarvinJ to convert the image to greyscale and save the colour value to an array, but I quickly found that this is not the way to go about this, due to the integer colour values of the greyscale image are very similar and do not represent the depth well enough.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Greyscale Test</title>
</head>
<body>
<script src="https://www.marvinj.org/releases/marvinj-0.9.js"></script>
<script>
image = new MarvinImage();
image.load("ir_test.png", imageLoaded);
function imageLoaded() {
var imageOut = new MarvinImage(image.getWidth(), image.getHeight());
var image2 = new MarvinImage(image.getWidth(), image.getHeight());
Marvin.invertColors(image, image2);
Marvin.invertColors(image2, imageOut);
var y = 240;
var colour_array = [];
for (var x = 0; x < imageOut.getWidth(); x++) { // For loop to loop through the x-axis
var colour = imageOut.getIntComponent0(x, y);
colour_array.push(colour);
}
document.getElementById('colour_array_div').innerHTML = colour_array;
}
</script>
<div id="colour_array_div"></div>
</body>
</html>
What I'm trying to work out is how to convert the colour to a distance, preferably in millimeters.
I ended up converting each pixel to their RGB hex values and then converted the hex value to a decimal number.
This gave me a range of values between 0 and 16777215.
I copied the output to a CSV file then processed the value of each pixel in Excel. I converted the decimal colour value to a distance in meters.
I found the range of the Kinect's depth sensor to be 0.8m-3.5m [https://openkinect.org/wiki/Imaging_Information]
I converted the decimal value to a meter value using an answer from this question: Excel Function name to map one ratio to another
value/(inhi-inlo)*(outhi-outlo)+outlo
Here is a graph of the output:
The code I used to generate the array of decimal colour values is:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Colour Test</title>
</head>
<body>
<script src="https://www.marvinj.org/releases/marvinj-0.9.js"></script>
<script>
image = new MarvinImage();
image.load("ir_test.png", imageLoaded);
function imageLoaded() {
var imageOut = new MarvinImage(image.getWidth(), image.getHeight());
var image2 = new MarvinImage(image.getWidth(), image.getHeight());
Marvin.invertColors(image, image2);
Marvin.invertColors(image2, imageOut);
var y = 240;
var colour_array = [];
for (var x = 0; x < imageOut.getWidth(); x++) { // For loop to loop through the x-axis
var red = imageOut.getIntComponent0(x, y);
var green = imageOut.getIntComponent1(x, y);
var blue = imageOut.getIntComponent2(x, y);
var hex_colour = rgbToHex(red,green,blue);
var colour = parseInt(hex_colour, 16); //https://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript
colour_array.push(colour);
}
document.getElementById('colour_array_div').innerHTML = colour_array;
}
//https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(r, g, b) {
return componentToHex(r) + componentToHex(g) + componentToHex(b);
}
</script>
<div id="colour_array_div"></div>
</body>
</html>
Related
I recently learning an image classifier using TensorFlow js in the browser, I made a simple image classification that can identify an image of Giorno and Jotaro, but when predicting a new image, the result always shows the first example(Jotaro) which I added, I'm trying to check the second function which added second example(Giorno), It just fine in console, and running well, this is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Giorno and Jotaro Classifier</title>
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#tensorflow-models/mobilenet"></script>
<script src="https://cdn.jsdelivr.net/npm/#tensorflow-models/knn-classifier"></script>
</head>
<body>
<h1>Test Image</h1>
<img id="predict" src="anime/test_giorno.jpg" alt="" width="300">
</body>
</html>
<script>
const initScript = async function(){
const ClassifierKNN = knnClassifier.create();
const mobileneModule = await mobilenet.load();
for(let i=1; i<=3;i++){
const im = new Image(300,300);
im.src = 'anime/jotaro/'+i+'.jpg';
im.onload = ()=>{
let trainingImageJotaro = tf.browser.fromPixels(im);
let predJotaro = mobileneModule.infer(trainingImageJotaro,'conv_preds');
if(i)
ClassifierKNN.addExample(predJotaro,"Jotaro");
}
im.onload();
}
for(let i=1; i<=3;i++){
const im2 = new Image(300,300);
im2.src = 'anime/giorno/'+i+'.jpg';
im2.onload = ()=>{
let trainingImageGiorno = tf.browser.fromPixels(im2);
let predGiorno = mobileneModule.infer(trainingImageGiorno,'conv_preds');
ClassifierKNN.addExample(predGiorno,"Giorno");
}
im2.onload();
}
let imgX = document.getElementById('predict');
const tensorX = tf.browser.fromPixels(imgX);
const logitsX = mobileneModule.infer(tensorX,'conv_preds');
let result = await ClassifierKNN.predictClass(logitsX);
console.log('outout:');
console.log(result);
}
initScript();
</script>
the result of the script is always jotaro, but when I switch the loop position like this:
for(let i=1; i<=3;i++){
const im2 = new Image(300,300);
im2.src = 'anime/giorno/'+i+'.jpg';
im2.onload = ()=>{
let trainingImageGiorno = tf.browser.fromPixels(im2);
let predGiorno = mobileneModule.infer(trainingImageGiorno,'conv_preds');
ClassifierKNN.addExample(predGiorno,"Giorno");
}
im2.onload();
}
for(let i=1; i<=3;i++){
const im = new Image(300,300);
im.src = 'anime/jotaro/'+i+'.jpg';
im.onload = ()=>{
let trainingImageJotaro = tf.browser.fromPixels(im);
let predJotaro = mobileneModule.infer(trainingImageJotaro,'conv_preds');
if(i)
ClassifierKNN.addExample(predJotaro,"Jotaro");
}
im.onload();
}
the result always Giorno, can anyone help me with this problem?
Thanks #zer0sign, for sharing the solution in comments. For the benefit of community I am providing solution here (answer section)
This problem has been fixed, above issue occurs because, the second training data is executed after the testing data, therefore the code above only gets 1 label, because the second label has not been executed and therefore the output label of the predicted image always shows the label of the first training data.
EDIT : OK, It was my css page which had a rule on path, 'cause I use svg a lot. Removed that rule and the problem was gone !
I'm facing something pretty annoying and which I do not understand.
I'm using amChart to make a XY chart with multiple series. Not that hard.
The thing is, I can't customize my series ! Bullets and legend are ok, but not series.
Here's a screenshot for better understanding :
MyWeirdChart (new OP can't embed images, sorry)
As you can see I have my custom bullet pushed on my series and my legend is exactly what I want for my chart BUT series are staying unchanged.
Here is my JS draw function :
function drawChart(dateArray, casesArray, deathsArray, healedArray, hospitalizationsArray, reanimationsArray) {
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.data = generateChartData(dateArray, casesArray, deathsArray, healedArray, hospitalizationsArray, reanimationsArray);
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
function pushSeries(field, name, color) {
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = field;
series.dataFields.dateX = "date";
series.name = name;
series.tooltipText = name + ": [b]{valueY}[/]";
series.stroke = am4core.color(color);
series.strokeWidth = 3;
series.fill = am4core.color(color);
series.fillOpacity = 0.5;
let bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.stroke = am4core.color(color);
bullet.circle.strokeWidth = 2;
bullet.circle.fill = am4core.color(color);
bullet.circle.fillOpacity = 0.5;
bullet.circle.radius = 3;
}
pushSeries("cases", "Cas confirmés", "#32B3E3");
pushSeries("healed", "Guéris", "#00C750");
pushSeries("hospitalizations", "Hospitalisations", "#FFBB33");
pushSeries("reanimations", "Réanimations", "#FE3446");
pushSeries("deaths", "Morts", "black");
chart.cursor = new am4charts.XYCursor();
chart.scrollbarX = new am4core.Scrollbar();
chart.legend = new am4charts.Legend();
chart.cursor.maxTooltipDistance = 0;
}
Did I miss something ? I crawled forums and documentations and I'm now helpless.
My code is in my webpack app.js file. But I include amCharts with HTML scripts,
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
not with webpack import. But I guess that if this was the problem, I would not be able to draw a chart at all.
OK, It was my css page which had a rule on path, 'cause I use svg a lot. Removed that rule and the problem was gone !
I create a PDF report with header generated automatically by phantomjs. In the report I have a long div which contains text, blank lines, simple data tables etc.
Since I believe phantomjs might have problem with the page break, I calculate the page break manually, break up the long div into multiple divs with page break at the end of each div.
Here is my calculation in the jQuery(document).ready()
//pagination the Notes pages
if (encData.pnotes && encData.pnotes.length > 0) {
pageCnt++;
var $notes = jQuery('<div id="pageNotes" class="notes" style="width:100%;margin-top:100px;border:1px solid red">' +
pNotesString + '</div>');
$body.append($notes);
var height = 0;
var children = $notes.children();
var p = children.slice(0);
var pages = [];
var counter = 0;
for (var i = 0; i < children.length; i++) {
if (height + children[i].offsetHeight < 1350)
height += children[i].offsetHeight;
else {
pages.push([counter, i]);
height = 0;
counter = i;
}
}
pages.push([counter, children.length]);
for (var i = 0; i < pages.length; i++) {
//first notes page
if (i == 0) {
$notes.children().slice(pages[i][1]).remove();
$notes.after('<div style="border:1px solid black;height:1px"></div><div id="pageNotesBreak" style="page-break-after:always"> </div>');
}
else {
pageCnt++;
var $new = jQuery('<div id="page' + pageCnt + '" class="notes" style="width:100%;margin-top:100px;border:1px solid blue"></div>');
$new.append(p.slice(pages[i][0], pages[i][1]));
$body.append($new);
$body.append('<div style="border:1px solid black;height:1px"></div><div id="pageBreak' + pageCnt + '" style="page-break-after:always"> </div>');
}
}
The "<div style='border:1px solid black;height:1px'>" is just a silly marker to find where my page breaks are on the PDF.
1350px in the estimated height of objects where the page break should be created when I traverse all the children of the long div.
In Chrome, I see that I have a total of 5 pages.
But when it is rendered in PDF, the number of pages goes up to 6 or 7 depending the size of the font, the line height, etc.
Here is the image of the pages
Does anyone know the cause of the problem? And how to solve it in general.
I need to create a screen which automates Google search.
I know JavaScript and I'm trying to get GSE works.
I have a search engine and an API key.
The problem is Google's documentation is cyclic i.e. pages point to each other.
There is no working sample from where I can start my research.
Please help if you know of a working sample.
The documents I have read are:
cselement-devguide
introduction
I know this is an old question, but here is what I did to make the API results formatted like the Google Site Search used to give since they are ending the paid accounts and will have ads now. The API way has an option to pay still for over 100 searches per day, so going with that but had to format the results still, and used the existing one to build the css to do similar styling also.
Search form going to this page is just a simple:
<form action="search-results.htm" id="cse-search-box">
<div>
<input class="" name="q" type="text">
<input class="" type="submit">
</div>
</form>
and then the search results page:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>JSON/Atom Custom Search API Example</title>
<!--<link href="default.css" rel="stylesheet" type="text/css">-->
<link href="google.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="gsc-result-info" id="resInfo-0"></div>
<hr/>
<div id="googleContent"></div>
<script>
//Handler for response from google.
function hndlr(response) {
if (response.items == null) {
//Sometimes there is a strange thing with the results where it says there are 34 results/4 pages, but when you click through to 3 then there is only 30, so page 4 is invalid now.
//So if we get to the invalid one, send them back a page.
window.location.replace("searchresults.htm?start=" + (start - 10) + "&q=" + query);
return;
}
//Search results load time
document.getElementById("resInfo-0").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results (" + response.searchInformation.formattedSearchTime + " seconds)";
//Clear the div first, CMS is inserting a space for some reason.
document.getElementById("googleContent").innerHTML = "";
//Loop through each item in search results
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var content = "";
content += "<div class='gs-webResult gs-result'>" +
"<table class='gsc-table-result'><tbody><tr>";
//Thumbnail image
if (item.pagemap.cse_thumbnail != null)
content += "<td class='gsc-table-cell-thumbnail gsc-thumbnail'><div class='gs-image-box gs-web-image-box gs-web-image-box-portrait'><a class='gs-image' href='" + item.link + "'>" +
"<img class='gs-image' class = 'gs-image-box gs-web-image-box gs-web-image-box-portrait' src='" + item.pagemap.cse_thumbnail[0].src + "'></a></td>";
//Link
content += "<td><a class='gs-title' href='" + item.link + "'>" + item.htmlTitle + "</a><br/>";
//File format for PDF, etc.
if (item.fileFormat != null)
content += "<div class='gs-fileFormat'><span class='gs-fileFormat'>File Format: </span><span class='gs-fileFormatType'>" + item.fileFormat + "</span></div>";
//description text and URL text.
content += item.htmlSnippet.replace('<br>','') + "<br/><div class='gs-bidi-start-align gs-visibleUrl gs-visibleUrl-long' dir='ltr' style='word-break:break-all;'>" + item.htmlFormattedUrl +"</div>" +
"<br/></td></tr></tbody></table></div>";
document.getElementById("googleContent").innerHTML += content;
}
//Page Controls
var totalPages = Math.ceil(response.searchInformation.totalResults / 10);
console.log(totalPages);
var currentPage = Math.floor(start / 10 + 1);
console.log(currentPage);
var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>";
//Page change controls, 10 max.
for (var x = 1; x <= totalPages && x<=10; x++) {
pageControls += "<div class='gsc-cursor-page";
if (x === currentPage)
pageControls += " gsc-cursor-current-page";
var pageLinkStart = x * 10 - 9;
pageControls+="'><a href='search-results.htm?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>";
}
pageControls += "</div></div></div>";
document.getElementById("googleContent").innerHTML += pageControls;
}
//Get search text from query string.
var query = document.URL.substr(document.URL.indexOf("q=") + 2);
var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2);
if (start === "1&" || document.URL.indexOf("start=") === -1)
start = 1;
//Load the script src dynamically to load script with query to call.
// DOM: Create the script element
var jsElm = document.createElement("script");
// set the type attribute
jsElm.type = "application/javascript";
// make the script element load file
jsElm.src = "https://www.googleapis.com/customsearch/v1?key=yourApikeyhere&cx=yoursearchengineidhere&start="+start+"&q=" +query +"&callback=hndlr";
// finally insert the element to the body element in order to load the script
document.body.appendChild(jsElm);
</script>
</body>
</html>
I pared down some odd behavior I was experiencing in SVG and I came up with this test case:
<circle r="10" />
<rect width="18" height="18" />
<polygon points="10,20 30,30 40,15 25,10" />
<script>
var svg = document.querySelector('svg'),
els = document.querySelectorAll('svg *');
for (var i=els.length;i--;){
var el = els[i];
el._dragXForm = el.transform.baseVal.appendItem(svg.createSVGTransform());
setInterval((function(el){
return function(){
var tx = el._dragXForm.matrix;
tx.e += Math.random()*2-1;
tx.f += Math.random()*2-1;
}
})(el),50);
}
</script>
In Safariv5 and Chromev18 on OS X the circle and polygon both jitter, but the rect does not. It does nothing. The SVGMatrix is getting a new value, but the appearance on screen is not updated. (In Firefox, it works as expected.)
If I change the script to remove _dragXForm like so:
for (var i=draggables.length;i--;){
var el = draggables[i];
el.transform.baseVal.appendItem(svg.createSVGTransform());
setInterval((function(el){
return function(){
var tx = el.transform.baseVal.getItem(0).matrix;
tx.e += Math.random()*2-1;
tx.f += Math.random()*2-1;
}
})(el),50);
}
…then the <rect> moves along with the others.
Besides seeming like an insane bug (how can this only affect a <rect>?!) I feel that this has not yet isolated the source of the bug.
What's the simplest possible code that can reproduce this odd behavior? (And if there's already a bug filed for this, I'd love to know about it.)
This code appears to be getting closer to the heart of the matter:
var svg = document.querySelector('svg'),
els = document.querySelectorAll('svg *');
for (var i=els.length;i--;){
var el = els[i],
tx = el.transform.baseVal.appendItem(svg.createSVGTransform());
console.log( el.tagName, tx===el.transform.baseVal.getItem(0) );
setTimeout((function(el,tx){
return function(){
console.log( el.tagName, tx===el.transform.baseVal.getItem(0) );
}
})(el,tx),1);
}
Output:
polygon true // The return value of appendItem is the same as the first item
rect true // The return value of appendItem is the same as the first item
circle true // The return value of appendItem is the same as the first item
polygon true // The returned value is STILL the same as the first item
rect false // The returned value is NO LONGER the same as the first item
circle true // The returned value is STILL the same as the first item