Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java OpenCV鸟瞰视图,无数据丢失_Java_Opencv_Image Processing_3d - Fatal编程技术网

Java OpenCV鸟瞰视图,无数据丢失

Java OpenCV鸟瞰视图,无数据丢失,java,opencv,image-processing,3d,Java,Opencv,Image Processing,3d,我正在使用OpenCV获取捕获帧的鸟瞰视图。这是通过在平面上提供棋盘图案来实现的,棋盘图案将形成鸟瞰视图 虽然看起来相机在这个平面上已经很漂亮了,但为了确定像素和厘米之间的关系,我需要它是完美的 在下一阶段中,捕获帧将被扭曲。它给出了预期的结果: 但是,通过执行此转换,棋盘模式之外的数据正在丢失。我需要的是旋转图像,而不是扭曲已知的四边形 问题:如何通过相机角度旋转图像,使其自上而下 一些代码说明了我目前正在做的事情: Size chessboardSize = new Size(12,

我正在使用OpenCV获取捕获帧的鸟瞰视图。这是通过在平面上提供棋盘图案来实现的,棋盘图案将形成鸟瞰视图

虽然看起来相机在这个平面上已经很漂亮了,但为了确定像素和厘米之间的关系,我需要它是完美的

在下一阶段中,捕获帧将被扭曲。它给出了预期的结果:

但是,通过执行此转换,棋盘模式之外的数据正在丢失。我需要的是旋转图像,而不是扭曲已知的四边形

问题:如何通过相机角度旋转图像,使其自上而下


一些代码说明了我目前正在做的事情:

Size chessboardSize = new Size(12, 8); // Size of the chessboard

Size captureSize = new Size(1920, 1080); // Size of the captured frames

Size viewSize = new Size((chessboardSize.width / chessboardSize.height) * captureSize.height, captureSize.height); // Size of the view

MatOfPoint2f imageCorners; // Contains the imageCorners obtained in a earlier stage

Mat H; // Homography
查找角点的代码:

Mat grayImage = new Mat();
//Imgproc.resize(source, temp, new Size(source.width(), source.height()));
Imgproc.cvtColor(source, grayImage, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(grayImage, grayImage, 0.0, 255.0, Imgproc.THRESH_OTSU);
imageCorners = new MatOfPoint2f();
Imgproc.GaussianBlur(grayImage, grayImage, new Size(5, 5), 5); 
boolean found = Calib3d.findChessboardCorners(grayImage, chessboardSize, imageCorners, Calib3d.CALIB_CB_NORMALIZE_IMAGE + Calib3d.CALIB_CB_ADAPTIVE_THRESH + Calib3d.CALIB_CB_FILTER_QUADS);

if (found) {

    determineHomography();
}
确定单应性的代码:

Point[] data = imageCorners.toArray();

if (data.length < chessboardSize.area()) {
    return;
}

Point[] roi = new Point[] {

    data[0 * (int)chessboardSize.width - 0], // Top left
    data[1 * (int)chessboardSize.width - 1], // Top right
    data[((int)chessboardSize.height - 1) * (int)chessboardSize.width - 0], // Bottom left
    data[((int)chessboardSize.height - 0) * (int)chessboardSize.width - 1], // Bottom right
};

Point[] roo = new Point[] {
    new Point(0, 0),
    new Point(viewSize.width, 0),
    new Point(0, viewSize.height),
    new Point(viewSize.width, viewSize.height)
};

MatOfPoint2f objectPoints = new MatOfPoint2f(), imagePoints = new MatOfPoint2f();

objectPoints.fromArray(roo);
imagePoints.fromArray(roi);

Mat H = Imgproc.getPerspectiveTransform(imagePoints, objectPoints);

[Edit2]更新进度

可能存在更多的旋转,因此我将尝试以下方法:

  • 预处理图像

    您可以应用许多过滤器来去除图像中的噪声,或者规范化照明条件(看起来您发布的图像不需要)。然后简单地对图像进行二值化,以简化进一步的步骤。见相关文件:

  • 检测方形角点

    并将它们的坐标与拓扑一起存储在某个数组中

    double pnt[col][row][2];
    
    其中
    (列,行)
    是棋盘索引,
    [2]
    存储(x,y)。您可以使用
    int
    ,但
    double/float
    将避免在拟合过程中进行不必要的转换和舍入

    可以通过如下方式扫描对角相邻像素来检测角点(除非倾斜/旋转接近45度):

    d1=0.5*(pp[2]-pp[0]);
    d2=0.5*(pp[3]-pp[1]);
    a0=pp[1];
    a1=d1;
    a2=(3.0*(pp[2]-pp[1]))-(2.0*d1)-d2;
    a3=d1+d2+(2.0*(-pp[2]+pp[1])); }
    coordinate = a0+(a1*t)+(a2*t*t)+(a3*t*t*t);
    

    一条对角线应为一种颜色,另一条对角线应为不同颜色。此模式将检测交叉点周围的点簇,以便找到接近这些点并计算其平均值

    如果扫描整个图像,循环轴的上部
    也将对点列表进行排序,因此无需进一步排序。平均后,对网格拓扑中的点进行排序/排序(例如,按两个最近点之间的方向)

  • 拓扑结构

    为了使其健壮,我使用了旋转和倾斜图像,因此拓扑检测有点棘手。经过一段时间的阐述,我得出以下结论:

  • 找到图像中间附近的点
    p0

    这将确保在这一点上有邻居

  • 找到离它最近的点
    p

    但忽略对角线点(
    |x/y |->1
    +/-正方形比例)。从这一点开始计算第一个基向量,现在将其称为
    u

  • 找到离它最近的点
    p

    以与#2相同的方式,但这一次也忽略+/-u方向上的点(
    |(u.v)|/(|u |.| v |)->1
    +/-倾斜/旋转)。从这一点开始计算第二个基向量,现在将其称为
    v

  • 标准化u、v

    我选择了
    u
    向量指向
    +x
    v
    指向
    +y
    方向。因此,具有较大
    |x |
    值的基向量应该是
    u
    ,具有较大
    |y |
    值的基向量应该是
    v
    。因此,如果需要,测试和交换。如果符号错了,就用否定。现在我们有了屏幕中间的基向量(越远,它们可能会改变)

  • 计算拓扑结构

    p0
    点设置为
    (u=0,v=0)
    作为起点。现在遍历所有尚未匹配的点
    p
    。对于每个位置,通过从其位置添加/减去基向量来计算邻居的预测位置。然后找到离该位置最近的点,如果找到该点,它应该是相邻点,因此将其
    (u,v)
    坐标设置为原始点
    +/-1
    。现在更新这些点的基向量并循环整个过程,直到没有找到新的匹配。结果应该是,大多数点都应该计算出它们的
    (u,v)
    坐标,这正是我们所需要的

  • 在此之后,您可以找到
    min(u)、min(v)
    ,并将其移动到
    (0,0)
    ,以便在需要时索引不会为负值

  • 为角点拟合多项式

    例如:

    pnt[i][j][0]=fx(i,j)
    pnt[i][j][1]=fy(i,j)
    
    其中,
    fx,fy
    是多项式函数。您可以尝试任何装配过程。我尝试使用的三次多项式拟合,但结果不如本地的双三次插值(可能是因为测试图像的非均匀失真),因此我切换到双三次插值而不是拟合。这更简单,但使求逆变得非常困难,但可以以牺牲速度为代价来避免。如果需要计算逆矩阵,请参见

    我使用简单的插值立方,如下所示:

    d1=0.5*(pp[2]-pp[0]);
    d2=0.5*(pp[3]-pp[1]);
    a0=pp[1];
    a1=d1;
    a2=(3.0*(pp[2]-pp[1]))-(2.0*d1)-d2;
    a3=d1+d2+(2.0*(-pp[2]+pp[1])); }
    coordinate = a0+(a1*t)+(a2*t*t)+(a3*t*t*t);
    
    其中,
    pp[0..3]
    是4个后续已知控制点(我们的网格交叉点),
    a0..a3
    是计算出的多项式系数,
    坐标
    是曲线上带有参数
    t
    的点。这可以扩展到任意数量的维度

    这条曲线的性质很简单,它是连续的,从
    pp[1]
    开始,到
    pp[2]
    结束,而
    t=
    。通过所有三次曲线的公共序列,确保与相邻段的连续性

  • 重新映射像素

    只需使用
    i,j
    作为浮动值,步长约为像素大小的75%,以避免出现间隙。然后只需简单地循环所有位置
    (i,j)
    计算
    (x,y)
    ,并将源图像中
    (x,y)
    处的像素复制到
    (i*sz,j*sz)+/-offset
    ,其中
    sz
    是所需的像素网格大小