将四边形图像提取为矩形

发布于 2024-09-04 05:18:47 字数 1713 浏览 2 评论 0原文

一张照片

赏金更新

丹尼斯 链接,这是如何使用 thirdblindmiceandamonkey 代码:

// the destination rect is our 'in' quad
int dw = 300, dh = 250;
double in[4][4] = {{0,0},{dw,0},{dw,dh},{0,dh}};
    // the quad in the source image is our 'out'
double out[4][5] = {{171,72},{331,93},{333,188},{177,210}};
double homo[3][6];
const int ret = mapQuadToQuad(in,out,homo);
    // homo can be used for calculating the x,y of any destination point
// in the source, e.g.
for(int i=0; i<4; i++) {
    double p1[3] = {out[i][0],out[i][7],1};
    double p2[3];
    transformMatrix(p1,p2,homo);
    p2[0] /= p2[2]; // x
    p2[1] /= p2[2]; // y
    printf("\t%2.2f\t%2.2f\n",p2[0],p2[1]);
}

这提供了转换中的点的转换目的地到源 - 您当然可以以相反的方式执行此操作,但是能够为混合执行此操作很整洁:

for(int y=0; y<dh; y++) {
    for(int x=0; x<dw; x++) {
        // calc the four corners in source for this
        // destination pixel, and mix

对于混合,我使用 使用随机点进行超级采样;即使出发地和目的地区域存在很大差异,它也能很好地工作


背景问题

在顶部的图像中,货车侧面的标志是没有面对相机。我想用我拥有的像素尽可能地计算它的正面看起来是什么样子。

我知道图像中四边形的角坐标以及目标矩形的大小。

我想象这是通过 x 和 y 轴的某种循环,在两个维度上同时执行 Bresenham 线,并在源图像和目标图像中的像素重叠时进行某种混合 - 某种子像素混合?

有哪些方法,以及如何混合像素?

有没有标准方法?

A photo

BOUNTY UPDATE

Following Denis's link, this is how to use the threeblindmiceandamonkey code:

// the destination rect is our 'in' quad
int dw = 300, dh = 250;
double in[4][4] = {{0,0},{dw,0},{dw,dh},{0,dh}};
    // the quad in the source image is our 'out'
double out[4][5] = {{171,72},{331,93},{333,188},{177,210}};
double homo[3][6];
const int ret = mapQuadToQuad(in,out,homo);
    // homo can be used for calculating the x,y of any destination point
// in the source, e.g.
for(int i=0; i<4; i++) {
    double p1[3] = {out[i][0],out[i][7],1};
    double p2[3];
    transformMatrix(p1,p2,homo);
    p2[0] /= p2[2]; // x
    p2[1] /= p2[2]; // y
    printf("\t%2.2f\t%2.2f\n",p2[0],p2[1]);
}

This provides a transform for converting points in destination to the source - you can of course do it the other way around, but it's tidy to be able to do this for the mixing:

for(int y=0; y<dh; y++) {
    for(int x=0; x<dw; x++) {
        // calc the four corners in source for this
        // destination pixel, and mix

For the mixing, I'm using super-sampling with random points; it works very well, even when there is a big disparity in the source and destination area


BACKGROUND QUESTION

In the image at the top, the sign on the side of the van is not face-on to the camera. I want to calculate, as best I can with the pixels I have, what it'd look like face on.

I know the corner coordinates of the quad in the image, and the size of the destination rectangle.

I imagine that this is some kind of loop through the x and y axis doing a Bresenham's line on both dimensions at once with some kind of mixing as pixels in the source and destination images overlap - some sub-pixel mixing of some sort?

What approaches are there, and how do you mix the pixels?

Is there a standard approach for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

極樂鬼 2024-09-11 05:18:47

你想要的叫平面矫正,恐怕没那么简单。您需要做的是恢复将货车侧面的倾斜视图映射到正面的 同应性 - 面向视图。 Photoshop / 等有一些工具可以在给定一些控制点的情况下为您执行此操作;如果你想自己实现它,你就必须开始钻研计算机视觉。

编辑 - 好的,给你:使用 OpenCV 库,它具有方便的函数来计算单应性并为您扭曲图像:

import cv

def warpImage(image, corners, target):
    mat = cv.CreateMat(3, 3, cv.CV_32F)
    cv.GetPerspectiveTransform(corners, target, mat)
    out = cv.CreateMat(height, width, cv.CV_8UC3)
    cv.WarpPerspective(image, out, mat, cv.CV_INTER_CUBIC)
    return out

if __name__ == '__main__':
    width, height = 400, 250
    corners = [(171,72),(331,93),(333,188),(177,210)]
    target = [(0,0),(width,0),(width,height),(0,height)]
    image = cv.LoadImageM('fries.jpg')
    out = warpImage(image, corners, target)
    cv.SaveImage('fries_warped.jpg', out)

以及输出:
Warped image

OpenCV 也有 C 和 C++ 绑定,或者您可以使用 EmguCV 用于 .NET 包装器;该 API 在所有语言中都相当一致,因此您可以用任何适合您喜欢的语言来复制它。

What you want is called planar rectification, and it's not all that simple, I'm afraid. What you need to do is recover the homography that maps this oblique view of the van side onto the front-facing view. Photoshop / etc. have tools to do this for you given some control points; if you want to implement it for yourself you'll have to start delving into computer vision.

Edit - OK, here you go: a Python script to do the warping, using the OpenCV library which has convenient functions to calculate the homography and warp the image for you:

import cv

def warpImage(image, corners, target):
    mat = cv.CreateMat(3, 3, cv.CV_32F)
    cv.GetPerspectiveTransform(corners, target, mat)
    out = cv.CreateMat(height, width, cv.CV_8UC3)
    cv.WarpPerspective(image, out, mat, cv.CV_INTER_CUBIC)
    return out

if __name__ == '__main__':
    width, height = 400, 250
    corners = [(171,72),(331,93),(333,188),(177,210)]
    target = [(0,0),(width,0),(width,height),(0,height)]
    image = cv.LoadImageM('fries.jpg')
    out = warpImage(image, corners, target)
    cv.SaveImage('fries_warped.jpg', out)

And the output:
Warped image

OpenCV also has C and C++ bindings, or you can use EmguCV for a .NET wrapper; the API is fairly consistent across all languages so you can replicate this in whichever language suits your fancy.

初与友歌 2024-09-11 05:18:47

查找“四元到四元”变换,例如
triblindmiceandamonkey
2d 齐次坐标上的 3x3 变换可以变换任意 4 个点(四边形)
到任何其他四边形;
相反,任何 fromquad 和 toquad,例如卡车的角点和目标矩形,
给出 3 x 3 变换。

Qt 有 quadToQuad
并可以用它来转换像素图,但我猜你没有 Qt ?
6 月 10 日添加:
来自 labs.trolltech.com/page/Graphics/Examples
有一个很好的演示,当您移动角落时,四对四的像素图:

alt text

已添加 11Jun:@Will,这是Python 中的translate.h(你知道一点吗?
""" ...""" 是多行注释。)
perstrans() 是关键;希望这是有道理的,如果不问的话。

顺便说一句,您可以将像素一一映射,mapQuadToQuad( target rect, origquad ),
但如果没有像素插值,它看起来会很糟糕; OpenCV 可以做到这一切。

#!/usr/bin/env python
""" square <-> quad maps
    from http://threeblindmiceandamonkey.com/?p=16 matrix.h
"""

from __future__ import division
import numpy as np

__date__ = "2010-06-11 jun denis"

def det2(a, b, c, d):
    return a*d - b*c

def mapSquareToQuad( quad ):  # [4][2]
    SQ = np.zeros((3,3))
    px = quad[0,0] - quad[1,0] + quad[2,0] - quad[3,0]
    py = quad[0,1] - quad[1,1] + quad[2,1] - quad[3,1]
    if abs(px) < 1e-10 and abs(py) < 1e-10:
        SQ[0,0] = quad[1,0] - quad[0,0]
        SQ[1,0] = quad[2,0] - quad[1,0]
        SQ[2,0] = quad[0,0]
        SQ[0,1] = quad[1,1] - quad[0,1]
        SQ[1,1] = quad[2,1] - quad[1,1]
        SQ[2,1] = quad[0,1]
        SQ[0,2] = 0.
        SQ[1,2] = 0.
        SQ[2,2] = 1.
        return SQ
    else:
        dx1 = quad[1,0] - quad[2,0]
        dx2 = quad[3,0] - quad[2,0]
        dy1 = quad[1,1] - quad[2,1]
        dy2 = quad[3,1] - quad[2,1]
        det = det2(dx1,dx2, dy1,dy2)
        if det == 0.:
            return None
        SQ[0,2] = det2(px,dx2, py,dy2) / det
        SQ[1,2] = det2(dx1,px, dy1,py) / det
        SQ[2,2] = 1.
        SQ[0,0] = quad[1,0] - quad[0,0] + SQ[0,2]*quad[1,0]
        SQ[1,0] = quad[3,0] - quad[0,0] + SQ[1,2]*quad[3,0]
        SQ[2,0] = quad[0,0]
        SQ[0,1] = quad[1,1] - quad[0,1] + SQ[0,2]*quad[1,1]
        SQ[1,1] = quad[3,1] - quad[0,1] + SQ[1,2]*quad[3,1]
        SQ[2,1] = quad[0,1]
        return SQ

#...............................................................................
def mapQuadToSquare( quad ):
    return np.linalg.inv( mapSquareToQuad( quad ))

def mapQuadToQuad( a, b ):
    return np.dot( mapQuadToSquare(a), mapSquareToQuad(b) )

def perstrans( X, t ):
    """ perspective transform X Nx2, t 3x3:
        [x0 y0 1] t = [a0 b0 w0] -> [a0/w0 b0/w0]
        [x1 y1 1] t = [a1 b1 w1] -> [a1/w1 b1/w1]
        ...
    """
    x1 = np.vstack(( X.T, np.ones(len(X)) ))
    y = np.dot( t.T, x1 )
    return (y[:-1] / y[-1]) .T

#...............................................................................
if __name__ == "__main__":
    np.set_printoptions( 2, threshold=100, suppress=True )  # .2f

    sq = np.array([[0,0], [1,0], [1,1], [0,1]])
    quad = np.array([[171, 72], [331, 93], [333, 188], [177, 210]])
    print "quad:", quad
    print "square to quad:", perstrans( sq, mapSquareToQuad(quad) )
    print "quad to square:", perstrans( quad, mapQuadToSquare(quad) )

    dw, dh = 300, 250
    rect = np.array([[0, 0], [dw, 0], [dw, dh], [0, dh]])
    quadquad = mapQuadToQuad( quad, rect )
    print "quad to quad transform:", quadquad
    print "quad to rect:", perstrans( quad, quadquad )
"""
quad: [[171  72]
 [331  93]
 [333 188]
 [177 210]]
square to quad: [[ 171.   72.]
 [ 331.   93.]
 [ 333.  188.]
 [ 177.  210.]]
quad to square: [[-0.  0.]
 [ 1.  0.]
 [ 1.  1.]
 [ 0.  1.]]
quad to quad transform: [[   1.29   -0.23   -0.  ]
 [  -0.06    1.79   -0.  ]
 [-217.24  -88.54    1.34]]
quad to rect: [[   0.    0.]
 [ 300.    0.]
 [ 300.  250.]
 [   0.  250.]]
"""

Look up "quad to quad" transform, e.g.
threeblindmiceandamonkey.
A 3x3 transform on 2d homogeneous coordinates can transform any 4 points (a quad)
to any other quad;
conversely, any fromquad and toquad, such as the corners of your truck and a target rectangle,
give a 3 x 3 transform.

Qt has quadToQuad
and can transform pixmaps with it, but I guess you don't have Qt ?
Added 10Jun:
from labs.trolltech.com/page/Graphics/Examples
there's a nice demo which quad-to-quads a pixmap as you move the corners:

alt text

Added 11Jun: @Will, here's translate.h in Python (which you know a bit ?
""" ...""" are multiline comments.)
perstrans() is the key; hope that makes sense, if not ask.

Bytheway, you could map the pixels one by one, mapQuadToQuad( target rect, orig quad ),
but without pixel interpolation it'll look terrible; OpenCV does it all.

#!/usr/bin/env python
""" square <-> quad maps
    from http://threeblindmiceandamonkey.com/?p=16 matrix.h
"""

from __future__ import division
import numpy as np

__date__ = "2010-06-11 jun denis"

def det2(a, b, c, d):
    return a*d - b*c

def mapSquareToQuad( quad ):  # [4][2]
    SQ = np.zeros((3,3))
    px = quad[0,0] - quad[1,0] + quad[2,0] - quad[3,0]
    py = quad[0,1] - quad[1,1] + quad[2,1] - quad[3,1]
    if abs(px) < 1e-10 and abs(py) < 1e-10:
        SQ[0,0] = quad[1,0] - quad[0,0]
        SQ[1,0] = quad[2,0] - quad[1,0]
        SQ[2,0] = quad[0,0]
        SQ[0,1] = quad[1,1] - quad[0,1]
        SQ[1,1] = quad[2,1] - quad[1,1]
        SQ[2,1] = quad[0,1]
        SQ[0,2] = 0.
        SQ[1,2] = 0.
        SQ[2,2] = 1.
        return SQ
    else:
        dx1 = quad[1,0] - quad[2,0]
        dx2 = quad[3,0] - quad[2,0]
        dy1 = quad[1,1] - quad[2,1]
        dy2 = quad[3,1] - quad[2,1]
        det = det2(dx1,dx2, dy1,dy2)
        if det == 0.:
            return None
        SQ[0,2] = det2(px,dx2, py,dy2) / det
        SQ[1,2] = det2(dx1,px, dy1,py) / det
        SQ[2,2] = 1.
        SQ[0,0] = quad[1,0] - quad[0,0] + SQ[0,2]*quad[1,0]
        SQ[1,0] = quad[3,0] - quad[0,0] + SQ[1,2]*quad[3,0]
        SQ[2,0] = quad[0,0]
        SQ[0,1] = quad[1,1] - quad[0,1] + SQ[0,2]*quad[1,1]
        SQ[1,1] = quad[3,1] - quad[0,1] + SQ[1,2]*quad[3,1]
        SQ[2,1] = quad[0,1]
        return SQ

#...............................................................................
def mapQuadToSquare( quad ):
    return np.linalg.inv( mapSquareToQuad( quad ))

def mapQuadToQuad( a, b ):
    return np.dot( mapQuadToSquare(a), mapSquareToQuad(b) )

def perstrans( X, t ):
    """ perspective transform X Nx2, t 3x3:
        [x0 y0 1] t = [a0 b0 w0] -> [a0/w0 b0/w0]
        [x1 y1 1] t = [a1 b1 w1] -> [a1/w1 b1/w1]
        ...
    """
    x1 = np.vstack(( X.T, np.ones(len(X)) ))
    y = np.dot( t.T, x1 )
    return (y[:-1] / y[-1]) .T

#...............................................................................
if __name__ == "__main__":
    np.set_printoptions( 2, threshold=100, suppress=True )  # .2f

    sq = np.array([[0,0], [1,0], [1,1], [0,1]])
    quad = np.array([[171, 72], [331, 93], [333, 188], [177, 210]])
    print "quad:", quad
    print "square to quad:", perstrans( sq, mapSquareToQuad(quad) )
    print "quad to square:", perstrans( quad, mapQuadToSquare(quad) )

    dw, dh = 300, 250
    rect = np.array([[0, 0], [dw, 0], [dw, dh], [0, dh]])
    quadquad = mapQuadToQuad( quad, rect )
    print "quad to quad transform:", quadquad
    print "quad to rect:", perstrans( quad, quadquad )
"""
quad: [[171  72]
 [331  93]
 [333 188]
 [177 210]]
square to quad: [[ 171.   72.]
 [ 331.   93.]
 [ 333.  188.]
 [ 177.  210.]]
quad to square: [[-0.  0.]
 [ 1.  0.]
 [ 1.  1.]
 [ 0.  1.]]
quad to quad transform: [[   1.29   -0.23   -0.  ]
 [  -0.06    1.79   -0.  ]
 [-217.24  -88.54    1.34]]
quad to rect: [[   0.    0.]
 [ 300.    0.]
 [ 300.  250.]
 [   0.  250.]]
"""
巷雨优美回忆 2024-09-11 05:18:47

而在现代,Python 中带有 cv2。

import cv2
import numpy as np

source_image = cv2.imread('french fries in Europe.jpeg')

source_corners = np.array([(171, 72), (331, 93), (333, 188), (177, 210)])

width, height = 400, 250
target_corners = np.array([(0, 0), (width, 0), (width, height), (0, height)])

# Get matrix H that maps source_corners to target_corners
H, _ = cv2.findHomography(source_corners, target_corners, params=None)

# Apply matrix H to source image.
transformed_image = cv2.warpPerspective(
    source_image, H, (source_image.shape[1], source_image.shape[0]))

cv2.imwrite('tranformed_image.jpg', transformed_image)

And in modern times in python with cv2.

import cv2
import numpy as np

source_image = cv2.imread('french fries in Europe.jpeg')

source_corners = np.array([(171, 72), (331, 93), (333, 188), (177, 210)])

width, height = 400, 250
target_corners = np.array([(0, 0), (width, 0), (width, height), (0, height)])

# Get matrix H that maps source_corners to target_corners
H, _ = cv2.findHomography(source_corners, target_corners, params=None)

# Apply matrix H to source image.
transformed_image = cv2.warpPerspective(
    source_image, H, (source_image.shape[1], source_image.shape[0]))

cv2.imwrite('tranformed_image.jpg', transformed_image)
别挽留 2024-09-11 05:18:47

我认为您需要的是仿射变换,它可以使用矩阵数学来完成。

I think what you need is affine transformation which can be accomplished using matrix math.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文