Извлечение четырехугольного изображения в прямоугольник
BOUNTY ОБНОВЛЕНИЕ
По ссылке Дениса, вот как использовать код http://threeblindmiceandamonkey.com/?p=16:
// 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, делающая линию Брезенхэма одновременно по обоим измерениям с некоторым смешением, поскольку пиксели в исходном и конечном изображениях перекрываются - какое-то субпиксельное смешивание какого-то рода?
Какие есть подходы и как вы смешиваете пиксели?
Есть ли стандартный подход для этого?
4 ответа
Уважать "quad to quad" transform
Например, три слепых мыши и один ключ.
Преобразование 3х3 по 2d однородным координатам может преобразовать любые 4 точки (квад) в любой другой квад; и наоборот, любой из четверки и четверки, такие как углы вашего грузовика и целевой прямоугольник, дают преобразование 3x3.
Qt имеет quadToQuad и может преобразовывать растровые изображения вместе с ним, но я думаю, у вас нет Qt?
Добавлено 10 июня: с http://labs.trolltech.com/page/Graphics/Examples есть хорошая демонстрация, в которой при перемещении углов используется растровое изображение с четырьмя квадраторами:
Добавлено 11 июня: @Will, вот translate.h в Python (что вы немного знаете?
""" ...""" - это многострочные комментарии.) perstrans()
это ключ; надеюсь, что имеет смысл, если не спросить.
Кстати, вы можете отображать пиксели один за другим, mapQuadToQuad( target rect, orig quad), но без интерполяции пикселей это будет выглядеть ужасно; 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.]]
"""
То, что вы хотите, называется планарным выпрямлением, и, боюсь, не все так просто. Что вам нужно сделать, это восстановить гомографию, которая отображает этот наклонный вид со стороны фургона на фронтальный вид. У Photoshop и т. Д. Есть инструменты, чтобы сделать это для вас, учитывая некоторые контрольные точки; если вы хотите реализовать это для себя, вам придется начать изучать компьютерное зрение.
Редактировать - ОК, вот и все: скрипт Python для деформации, используя библиотеку 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)
И вывод:
OpenCV также имеет привязки C и C++, или вы можете использовать EmguCV для оболочки.NET; API достаточно одинаков для всех языков, поэтому вы можете воспроизвести его на любом языке, который вам подходит.
Я думаю, что вам нужно аффинное преобразование, которое может быть достигнуто с помощью матричной математики.
А в наше время в 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)