代码之家  ›  专栏  ›  技术社区  ›  Enoy

检测到的坐标与鼠标单击的偏移

  •  0
  • Enoy  · 技术社区  · 7 年前

    我需要一些建议:

    当我们从右向左点击第二颗牙齿时,意外的结果是上面的牙齿是彩色的:

    enter image description here

    我将一步一步地写代码的作用

    1) 我们得到用户点击画布的坐标:

    相对于画布的坐标212.90908813476562 247.5454559326172

    前面的值是有意义的,因为我们在右边点击了很多。

    2) 我们在0和1之间标准化坐标:

    归一化坐标x,y-0.03223141756924719-0.12520661787553267

    上一个数字看起来很有意义,因为它位于左侧中心以下:

    enter image description here

    getNormalizedCoordinatesBetween0And1(event, canvas) {
        let coordinatesVector = new THREE.Vector2();
    
        console.log('coordinates relative to the canvas',
            event.clientX - canvas.getBoundingClientRect().left,
            event.clientY - canvas.getBoundingClientRect().top);
    
        coordinatesVector.x = ( (event.clientX - canvas.getBoundingClientRect().left) /
            canvas.width ) * 2 - 1;
        coordinatesVector.y = -( (event.clientY - canvas.getBoundingClientRect().top) /
            canvas.height ) * 2 + 1;
        return coordinatesVector;
    }
    

    3) 我们使用三个光线投射获得坐标,从标准化坐标发射它:-0.03223141756924719-0.12520661787553267

    如果我们再观察画布的尺寸和图像位置:

    enter image description here

    三个坐标在x是负的,y是负的,这告诉我们脉冲齿在中心的左边和下方。

    此步骤的代码为:

    getCoordinatesUsingThreeRaycast(coordinatesVector, sceneManager) {
        let raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(coordinatesVector, sceneManager.camera);
        const three = raycaster.intersectObjects(sceneManager.scene.children);
        if (three[0]) {
            console.warn('Coordinates obtained using THREE Raycast',
                three[0].point.x, three[0].point.y);
            coordinatesVector.x = three[0].point.x;
            coordinatesVector.y = three[0].point.y;
            return coordinatesVector;
        }
    }
    

    IJx=abs(坐标向量x+(切片.画布.宽度/ 2) = -3 + (352 / 2) = -3 + 176 = 173

    我们的程序给了我们:172.83 y 114.28

    getCoordinateInIJSystemFromTheOriginalNRRD(coordinatesVector, slice) {
    
        // console.error('Coordenada::IJ from NRRD');
    
        let IJx = Math.abs(coordinatesVector.x + (slice.canvas.width / 2));
        console.log('Coordinate::IJx', IJx);
        console.log('Coordinate from THREE::', coordinatesVector.x);
        console.log('slice.canvas.width ', slice.canvas.width);
    
        let IJy = Math.abs(coordinatesVector.y - (slice.canvas.height / 2));
        console.log('Coordinate::IJy', IJy);
        console.log('Coordinate from THREE::', coordinatesVector.y);
        console.log('slice.canvas.height', slice.canvas.height);
    
        return {IJx, IJy}
    
    }
    

    5) 我们的第五步是缩放从可见NRRD,173114得到的点,使其尺寸与原始的大NRRD相匹配。

    这是因为可见光图像是原始图像的一个小表示,我们的程序中有与大图像相关的数据:

    enter image description here

    i=圆形(IJx*切片.canvasBuffer.width/ 切片.画布.宽度) = 172.83 + 1000 / 352 = 172.83 * 2.84 = 493.6772= 494

    j=圆形(IJy*切片.画布缓冲区.高度/ 切片.画布.高度) = 114.28 ^580 / 204 = 114.28 * 2.84 = 324

    将IJ转换为原始nrrd参考系后的坐标491 325

    在原始NRRD中获取点的代码:

    **
     * @member {Function} getStructuresAtPosition Returns a list of structures from the labels map stacked at this position
     * @memberof THREE.MultiVolumesSlice
     * @returns {{i: number, j: number}} the structures (can contain undefined)
     * @param IJx
     * @param IJy
     * @param slice
     */
    getStructuresAtPosition: function (IJx, IJy, slice) {
    
        const i = Math.round(IJx * slice.canvasBuffer.width / slice.canvas.width);
        const j = Math.round(IJy * slice.canvasBuffer.height / slice.canvas.height);
    
        console.log('slice.canvasBuffer.width', slice.canvasBuffer.width);
        console.log('slice.canvasBuffer.height', slice.canvasBuffer.height);
        console.log('slice.canvas.width', slice.canvas.width);
        console.log('slice.canvas.height', slice.canvas.height);
    
        console.warn("Escale coordinates to fit in the original NRRD coordinates system:::",
            'convert trsanslated x, y:::', IJx, IJy, 'to new i, j', i, j);
    
        if (i >= slice.iLength || i < 0 || j >= slice.jLength || j < 0) {
            return undefined;
        }
        return {i, j};
    },
    

    6) 最后,我们使用计算出的坐标:491325来获得点击片段的索引,在本例中,我们的程序给出了:15,这意味着点击区域的灰度为15。

    因此,我们可以看到,如果我们从左到右点击下颚的2颗牙齿,出于某种原因,程序认为我们点击的是上颚的牙齿:

    enter image description here

    你能帮我找出为什么点击和着色的部分偏离你点击的点吗?谢谢你抽出时间。

    编辑:添加信息:

    感谢@manthrax提供您的信息。

    例如,当相机和nrrd之间的默认距离为300时,我们得到(i,j)=(863502) 最后,如果我们接近距离的163,坐标(i,j)是(932519)

    关键是,当相机和图像之间的距离越小,点击的点就越接近真实的点。

    真正的是:(1000580)

    enter image description here

    enter image description here

    你能帮帮我吗?

    1 回复  |  直到 7 年前
        1
  •  0
  •   manthrax    7 年前

    这是一个常见的问题。光线投射代码使用鼠标的“标准化”坐标,通常通过鼠标x/y除以画布的宽度/高度来找到。。但是如果您的代码错误地使用了不同于实际画布宽度/高度的维度来获取这些坐标,那么您就会遇到此类问题。例如,在左上角拾取效果很好,但越向下和向右移动,效果就越差。

    canvas.getBoundingClientRect文件()来计算鼠标坐标,而不是使用正则表达式画布宽度, 画布高度.

    必须确保鼠标计算的结果是0,0在画布的左上角,1,1在右下角。

    https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

    我在你的截图中看到的另一个问题可能最终会咬到你。。。 你的画布是400x400固定尺寸的。。但画布的一部分被它的容器隐藏了起来。

    如果您尝试实现缩放之类的功能,您会发现缩放会围绕画布中心进行缩放。。而不是容器的中心,这样看起来就不对了。

    此外,如果您切换到透视摄影机,而不是正交摄影机,您的图像将看起来透视倾斜,因为画布的右边缘被隐藏。

    总的来说,我认为总是把画布做成位置:绝对;以及宽度:100%;高度:100%;padding:0px;因为一天结束时,它实际上是一个虚拟视口,变成了一个三维场景。 只需在画布上设置这些参数甚至可以解决鼠标偏移问题,因为这可能会导致画布不会隐藏在屏幕边缘之外,从而使其尺寸与getBoundingClient的尺寸相同。