gpt4 book ai didi

javascript - 在 Node js 中将 360 度 View 转换为等距柱状 View ?

转载 作者:数据小太阳 更新时间:2023-10-29 05:17:21 25 4
gpt4 key购买 nike

这两天我一直在尝试将 360 度相机、单鱼眼图像转换为 node js 中的 equirectangular viewer。在 stackoverflow 中,同样的问题是用伪代码提出和回答的。我一直在尝试将伪代码转换为 Node js并清除一些错误。现在项目运行没有错误,但输出图像是空白的。

从那个伪,我不知道 polar_w、polar_h 和 geo_w、geo_h、geo 和 polar 值,因此,它给出了静态值来显示输出。这是我用来将伪代码转换为 Node js 的链接。 How to convert spherical coordinates to equirectangular projection coordinates? .

这是我尝试将球形图像转换为等距柱状观察器的代码:

 exports.sphereImage=(request, response)=>{


var Jimp = require('jimp');


// Photo resolution

var img_w_px = 1280;
var img_h_px = 720;

var polar_w = 1280;
var polar_h = 720;
var geo_w = 1280;
var geo_h = 720;

var img_h_deg = 70;
var img_w_deg = 30;

// Camera field-of-view angles

var img_ha_deg = 70;
var img_va_deg = 40;


// Camera rotation angles

var hcam_deg = 230;
var vcam_deg = 60;

// Camera rotation angles in radians

var hcam_rad = hcam_deg/180.0*Math.PI;
var vcam_rad = vcam_rad/180.0*Math.PI;

// Rotation around y-axis for vertical rotation of camera

var rot_y = [

[Math.cos(vcam_rad), 0, Math.sin(vcam_rad)],
[0, 1, 0],
[-Math.sin(vcam_rad), 0, Math.cos(vcam_rad)]

];

// Rotation around z-axis for horizontal rotation of camera

var rot_z = [

[Math.cos(hcam_rad), -Math.sin(hcam_rad), 0],
[Math.sin(hcam_rad), Math.cos(hcam_rad), 0],
[0, 0, 1]

];


Jimp.read('./public/images/4-18-2-42.jpg', (err, lenna) => {


polar = new Jimp(img_w_px, img_h_px);
geo = new Jimp(img_w_px, img_h_px);

for(var i=0; i<img_h_px; ++i)
{
for(var j=0; j<img_w_px; ++j)
{
// var p = img.getPixelAt(i, j);

var p = lenna.getPixelColor(i, j)
// var p = getPixels(img, { x: i, y: j })

// Calculate relative position to center in degrees
var p_theta = (j - img_w_px / 2.0) / img_w_px * img_w_deg / 180.0 * Math.PI;
var p_phi = -(i - img_h_px / 2.0) / img_h_px * img_h_deg / 180.0 *Math. PI;

// Transform into cartesian coordinates
var p_x = Math.cos(p_phi) * Math.cos(p_theta);
var p_y = Math.cos(p_phi) * Math.sin(p_theta);
var p_z = Math.sin(p_phi);
var p0 = {p_x, p_y, p_z};

// Apply rotation matrices (note, z-axis is the vertical one)
// First vertically
var p1 = rot_y[1][2][3] * p0;
var p2 = rot_z[1][2][3] * p1;

// Transform back into spherical coordinates
var theta = Math.atan2(p2[1], p2[0]);
var phi = Math.asin(p2[2]);

// Retrieve longitude,latitude
var longitude = theta / Math.PI * 180.0;
var latitude = phi / Math.PI * 180.0;

// Now we can use longitude,latitude coordinates in many different
projections, such as:
// Polar projection
{
var polar_x_px = (0.5*Math.PI + phi)*0.5 * Math.cos(theta)
/Math.PI*180.0 * polar_w;
var polar_y_px = (0.5*Math.PI + phi)*0.5 * Math.sin(theta)
/Math.PI*180.0 * polar_h;
polar.setPixelColor(p, polar_x_px, polar_y_px);
}
// Geographical (=equirectangular) projection
{
var geo_x_px = (longitude + 180) * geo_w;
var geo_y_px = (latitude + 90) * geo_h;
// geo.setPixel(geo_x_px, geo_y_px, p.getRGB());
geo.setPixelColor(p, geo_x_px, geo_y_px);
}
// ...
}
}

geo.write('./public/images/4-18-2-42-00001.jpg');
polar.write('./public/images/4-18-2-42-00002.jpg');



});


}

并尝试了另一种方法,将图像分成四个部分来检测汽车。使用 image-slice 模块将图像分成四部分,并使用 jimp 模块进行读写。但不幸的是,汽车没有被正确检测到。

这是我用于切片图像的代码:

 exports.sliceImage=(request, response)=>{

var imageToSlices = require('image-to-slices');
var lineXArray = [540, 540];
var lineYArray = [960, 960];
var source = './public/images/4-18-2-42.jpg'; // width: 300, height: 300

imageToSlices(source, lineXArray, lineYArray, {
saveToDir: './public/images/',
clipperOptions: {
canvas: require('canvas')
}
}, function() {
console.log('the source image has been sliced into 9 sections!');
});


}//sliceImage

为了从图像中检测汽车,我使用了 opencv4nodejs。未正确检测到汽车。这是我用于检测汽车的代码:

   function runDetectCarExample(img=null){
if(img==null){

img = cv.imread('./public/images/section-1.jpg');
}else
{
img=cv.imread(img);
}
const minConfidence = 0.06;

const predictions = classifyImg(img).filter(res => res.confidence > minConfidence && res.className=='car');

const drawClassDetections = makeDrawClassDetections(predictions);

const getRandomColor = () => new cv.Vec(Math.random() * 255, Math.random() * 255, 255);

drawClassDetections(img, 'car', getRandomColor);
cv.imwrite('./public/images/section-'+Math.random()+'.jpg', img);
var name="distanceFromCamera";
var focalLen= 1.6 ;//Focal length in mm
var realObjHeight=254 ;//Real Height of Object in mm
var cameraFrameHeight=960;//Height of Image in pxl
var imgHeight=960;//Image Height in pxl
var sensorHeight=10;//Sensor height in mm
var R = 6378.1 //#Radius of the Earth
var brng = 1.57 //#Bearing is 90 degrees converted to radians.
var hc=(200/100);//Camera height in m
predictions
.forEach((data)=> {

// imgHeight=img.rows;//Image Height in pxl
// realObjHeight=data.rect.height;
// data.rect[name]=((focalLen)*(realObjHeight)*
(cameraFrameHeight))/((imgHeight)*(sensorHeight));

var dc=(((data.rect.width * focalLen) / img.cols)*2.54)*100; // meters
console.log(Math.floor(parseInt(data.rect.width)));
// var dc=((Math.floor(parseInt(data.rect.width)* 0.264583) * focalLen) / img.cols); // mm


var lat1=13.0002855;//13.000356;
var lon1=80.2046441;//80.204632;
// Gate 13.0002855,80.2046441
// Brazil Polsec : -19.860566, -43.969436
// var d=Math.sqrt((dc*dc)+(hc*hc));
// d=(data.rect[name])/1000;
data.rect[name]=d=dc/1000;
lat1 =toRadians(lat1);
lon1 = toRadians(lon1);
brng =toRadians(90);
// lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
// Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));

// lon2 = lon1 +
Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
// Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));


var lat2 = Math.asin(Math.sin(lat1) * Math.cos(d/6371) +
Math.cos(lat1) * Math.sin(d/6371) * Math.cos(brng));

var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d/6371) * Math.cos(lat1),
Math.cos(d/6371) - Math.sin(lat1) * Math.sin(lat2));

lat2 = toDegrees(lat2);
lon2 = toDegrees(lon2);
data.rect['latLong']=lat2+','+lon2;
// console.log(brng);

});




response.send(predictions);
cv.imshowWait('img', img);
};

这里是鱼眼图,需要转成等距柱状图。

非常感谢任何帮助....

最佳答案

您问的是如何将 360 度鱼眼投影转换为等距柱状投影。

为此,对于鱼眼图像上的每个像素,您需要知道在输出图像上放置的位置。

您的输入图像为 1920x1080,假设您要将其输出为相同大小的等距柱状投影。

输入圆映射定义为:

cx = 960; // center of circle on X-axis
cy = 540; // center of circle on Y-axis
radius = 540; // radius of circle

如果您在输入图像中的 (x,y) 处有一个像素,那么我们可以使用以下方法计算球坐标:

dx = (x - cx) * 1.0 / radius;
dy = (y - cy) * 1.0 / radius;
theta_deg = atan2(dy, dx) / MATH_PI * 180;
phi_deg = acos(sqrt(dx*dx + dy*dy)) / MATH_PI * 180;
outputx = (theta_deg + 180) / 360.0 * outputwidth_px;
outputy = (phi_deg + 90) / 180.0 * outputheight_px;

因此我们将鱼眼图像中的 (x,y) 翻译成等距柱状图像中的 (outputx,outputy)。为了不让实现成为可怕的“读者练习”,这里有一些示例 Javascript 代码使用了 OP 使用的 Jimp 库:

var jimp = require('jimp');
var inputfile = 'input.png';
jimp.read(inputfile, function(err, inputimage)
{
var cx = 960;
var cy = 540;
var radius = 540;
var inputwidth = 1920;
var inputheight = 1080;
var outputwidth = 1920;
var outputheight = 1080;
new jimp(outputwidth, outputheight, 0x000000ff, function(err, outputimage)
{
for(var y=0;y<inputheight;++y)
{
for(var x=0;x<inputwidth;++x)
{
var color = inputimage.getPixelColor(x, y);
var dx = (x - cx) * 1.0 / radius;
var dy = (y - cy) * 1.0 / radius;
var theta_deg = Math.atan2(dy, dx) / Math.PI * 180;
var phi_deg = Math.acos(Math.sqrt(dx*dx + dy*dy)) / Math.PI * 180;
var outputx = Math.round((theta_deg + 180) / 360.0 * outputwidth);
var outputy = Math.round((phi_deg + 90) / 180.0 * outputheight);
outputimage.setPixelColor(color, outputx, outputy);
}
}
outputimage.write('output.png');
});
});

请注意,您仍然需要将像素与相邻像素混合(与调整图像大小时的原因相同)。

此外,在您的情况下,您只有一半的球体(您看不到天空中的太阳)。所以你需要使用 var outputy = Math.round(phi_deg/90.0 * outputheight)。为了保持正确的纵横比,您可能需要将高度更改为 540

另请注意,给定的实现可能根本没有效率,最好直接使用缓冲区。

无论如何,在没有混合的情况下,我得出了如下所示的结果: equirectangular projection


因此,为了进行混合,您可以使用最简单的方法,即最近邻方法。在这种情况下,您应该反转上例中的公式。无需将像素从输入图像移动到输出图像中的正确位置,您可以遍历输出图像中的每个像素并询问我们可以使用哪个输入像素。这将避免黑色像素,但仍可能显示伪像:

var jimp = require('jimp');
var inputfile = 'input.png';
jimp.read(inputfile, function(err, inputimage)
{
var cx = 960;
var cy = 540;
var radius = 540;
var inputwidth = 1920;
var inputheight = 1080;
var outputwidth = 1920;
var outputheight = 1080/2;
var blendmap = {};
new jimp(outputwidth, outputheight, 0x000000ff, function(err, outputimage)
{
for(var y=0;y<outputheight;++y)
{
for(var x=0;x<outputwidth;++x)
{
var theta_deg = 360 - x * 360.0 / outputwidth - 180;
var phi_deg = 90 - y * 90.0 / outputheight;
var r = Math.sin(phi_deg * Math.PI / 180)
var dx = Math.cos(theta_deg * Math.PI / 180) * r;
var dy = Math.sin(theta_deg * Math.PI / 180) * r;
var inputx = Math.round(dx * radius + cx);
var inputy = Math.round(dy * radius + cy);
outputimage.setPixelColor(inputimage.getPixelColor(inputx, inputy), x, y);
}
}
outputimage.write('output.png');
});
});

供引用,以便在笛卡尔坐标系和球坐标系之间进行转换。这些是公式 ( taken from here )。请注意,z 在您的情况下仅为 1,即所谓的“单位”球体,因此您可以将其排除在方程式之外。您还应该了解,由于相机实际上是在三维空间拍摄照片,因此您还需要公式才能在三维空间工作。

Spherical to Cartesian and Cartesian to Spherical

这是生成的输出图像:

Output image using nearest neighbour mapping

由于我在你的问题中看不到你的原始输入图像,为了让任何人测试这个答案的代码,你可以使用下面的图像:

Input image

运行代码:

mkdir /tmp/test
cd /tmp/test
npm install --permanent jimp
cat <<EOF >/tmp/test/main.js
... paste the javascript code from above ...
EOF
curl /image/0zWt6.png > input.png
node main.js

注意:为了进一步改进混合,您应该删除Math.round。因此,例如,如果您需要在 x 处抓取一个像素为 0.75,并且在 x = 0 左侧的像素为白色,而右侧的像素为x = 1 是黑色的。然后您想将两种颜色混合成深灰色(使用比率 0.75)。如果你想要一个好的结果,你必须同时对两个维度执行此操作。但这真的应该是一个新问题恕我直言。

关于javascript - 在 Node js 中将 360 度 View 转换为等距柱状 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51869432/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com