最近体验了一下lightburn的摄像头辅助定位, 在使用摄像头进行定位时,你需要先校准相机镜头,然后在校准相机对齐,由于我们上位机后续也需要类似的功能,所以就需要先抽时间预研一下,以便后续开张工作。
先说一下校准相机镜头,这一步做的目的是将相机拍的照片进行处理,如果相机拍的比较斜,或者那种鱼眼相机,拍的照片是中间被放大,四周被压缩。 类似下面的。
在这一步我们需要将其处理成正常的二维平面。 恢复成下面这样子。
这就是这一步的目的,将变形的图片处理成正常的,以便后续建立坐标系,其他流程的处理。
废话不多说,直接上硬菜。
要解决上文所述的,图片失真的情况,我找到了一个库 这就是 fisheye.js
https://github.com/ericleong/fisheye.js
官方体验地址 https://ericleong.me/fisheye.js/
该库支持 普通图片的的径向透镜畸变,还支持gif的畸变。此外还支持不同通道,不同值的设置。
在该库内部使用WebGL 来实现畸变和恢复。使用着色器程序来处理纹理和是失真的参数。
使用方法
var canvas = document.getElementById('canvas');
var fisheye = new Fisheye(canvas);
var img;
var red = document.getElementById('red');
var green = document.getElementById('green');
var blue = document.getElementById('blue');
var update = function () {
fisheye.setViewport(canvas.width, canvas.height);
fisheye.setDistortion(red.value, green.value, blue.value);
fisheye.clear();
fisheye.draw(img);
};
向构造函数传入一个canvas节点,设置视图的尺寸和三个通道的失真参数就可以看到失真的效果。非常的简单。
由于我们的场景是,摄像机安装在机器的一个固定位置,位置固定,画面尺寸固定, 所有只要得到失真的系数,就能将照片还原正常。
失真参数是一个数字,或者三个数字,表示三个通道。0表示没有失真。
下面是案例源码
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>fisheye.js</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
body>h1 {
text-align: center;
}
h1 {
padding-left: 1em;
padding-right: 1em;
}
h1,
h2 {
font-family: sans-serif;
font-weight: lighter;
font-style: normal;
}
h3 {
font-family: sans-serif;
font-style: bold;
font-variant: small-caps;
}
#sandbox {
display: flex;
justify-content: space-around;
display: -webkit-flex;
-webkit-justify-content: space-around;
width: 100%;
}
#controls {
box-sizing: border-box;
flex-basis: 20vw;
-webkit-flex-basis: 20vw;
padding: 0 1em 0 1em;
}
#controls input {
width: 100%;
}
#picker-container {
position: relative;
width: 100%;
height: 3em;
font-size: 1.25em;
font-family: sans-serif;
margin-top: 1em;
}
#picker-container::before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 1em;
content: 'pick another image';
text-align: center;
}
#picker-container>input {
width: 100%;
height: 100%;
cursor: pointer;
opacity: 0 !important;
}
@media (max-width: 768px) {
canvas {
height: 100vw;
}
#sandbox {
flex-direction: column;
-webkit-flex-direction: column;
}
#controls {
width: 100vw;
padding: 0 10% 10% 10%;
flex-basis: auto;
-webkit-flex-basis: auto;
}
}
</style>
<script src="fisheye/omggif.js"></script>
<script src="fisheye/glif.js"></script>
<script src="fisheye/viewer.js"></script>
<script src="fisheye/droppick.js"></script>
<script src="fisheye/grab.js"></script>
<script src="fisheye/fisheye.js"></script>
</head>
</head>
<body>
<!-- <h1>radial lens distortion with <a href="https://github.com/ericleong/fisheye.js">fisheye.js</a></h1> -->
<h1>径向透镜畸变:鱼眼摄像头照片的矫正</h1>
<div id="sandbox">
<canvas id="canvas" width="640" height="640"></canvas>
<div id="controls">
<h2>distortion</h2>
<div><input id="all" type="range" min="-10" max="10" value="5" step="0.1" /></div>
<h2>color channels</h2>
<div>
<h3>red</h3><input id="red" type="range" min="-10" max="10" value="5" step="0.1" />
</div>
<div>
<h3>green</h3><input id="green" type="range" min="-10" max="10" value="5" step="0.1" />
</div>
<div>
<h3>blue</h3><input id="blue" type="range" min="-10" max="10" value="5" step="0.1" />
</div>
<div id="picker-container"><input id="picker" type="file" accept="image/*" /></div>
</div>
</div>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var fisheye = new Fisheye(canvas);
var img;
var red = document.getElementById('red');
var green = document.getElementById('green');
var blue = document.getElementById('blue');
var update = function () {
fisheye.setViewport(canvas.width, canvas.height);
fisheye.setDistortion(red.value, green.value, blue.value);
fisheye.clear();
fisheye.draw(img);
};
var ie11 = !(window.ActiveXObject) && "ActiveXObject" in window;
var eventType = ie11 ? 'change' : 'input';
red.addEventListener(eventType, update);
green.addEventListener(eventType, update);
blue.addEventListener(eventType, update);
var all = document.getElementById('all');
all.addEventListener(eventType, function () {
console.log(all.value, 'value')
red.value = all.value;
green.value = all.value;
blue.value = all.value;
update();
});
img = new Image();
img.addEventListener('load', update, false);
// img.src = 'fisheye/rainbow-glass.jpg';
img.src = 'fisheye/grib.png';
var gifTimeout;
// drag and drop
droppick(document.getElementById('sandbox'), document.getElementById('picker'), function (items) {
grab(items, function (item) {
debugger
clearTimeout(gifTimeout);
function setSize(width, height) {
if (width > 0.8 * window.innerWidth) {
if (window.matchMedia('(max-width: 768px)').matches) {
canvas.width = Math.round(window.innerWidth * window.devicePixelRatio);
canvas.height = Math.round(canvas.width * (height / width));
canvas.style.width = '100vw'
canvas.style.height = 100 * (height / width) + 'vw';
} else {
canvas.width = Math.round(0.8 * window.innerWidth * window.devicePixelRatio);
canvas.height = Math.round(canvas.width * (height / width));
canvas.style.width = '80vw'
canvas.style.height = 80 * (height / width) + 'vw';
}
} else {
canvas.width = width;
canvas.height = height;
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
}
}
if (item instanceof ArrayBuffer) {
img = document.createElement('canvas');
var view = viewer(img, item, function (timeoutId) {
gifTimeout = timeoutId;
setSize(img.width, img.height);
update();
});
gifTimeout = view();
} else if (item instanceof HTMLImageElement) {
img = item;
setSize(item.naturalWidth, item.naturalHeight);
update();
}
})
});
</script>
</body>
</html>