Коррекция перспективы в OpenCV с использованием python
Я пытаюсь сделать перспективную коррекцию наклоненного прямоугольника (кредитной карты), который наклонен во всех 4 направлениях. Я мог бы найти его четыре угла и соответствующие углы наклона, но я не могу найти точное местоположение координат, где он должен быть спроецирован. Я использую cv2.getPerspectiveTransform для выполнения преобразования.
У меня есть соотношение сторон фактической карты (не наклоненной), я хочу такие координаты, чтобы исходное соотношение сторон сохраняется. Я попытался использовать ограничивающий прямоугольник, но это увеличивает размер карты.
любая помощь будет оценили.
2 ответов
вот как вам нужно следовать...
для удобства я изменил размер вашего изображения до меньшего размера,
- вычислить четырехугольные вершины для исходного изображения, здесь я узнаю вручную,вы можете выбрать обнаружение края, линию Хоу и т. д..
Q1=manual calculation; Q2=manual calculation; Q3=manual calculation; Q4=manual calculation;
- вычислить вершины четырехугольника в целевом изображении, сохраняя соотношение сторон, здесь вы можете взять ширину карты сверху четырехугольника вершины источника и вычислить высоту путем умножения с соотношением сторон.
// compute the size of the card by keeping aspect ratio. double ratio=1.6; double cardH=sqrt((Q3.x-Q2.x)*(Q3.x-Q2.x)+(Q3.y-Q2.y)*(Q3.y-Q2.y)); //Or you can give your own height double cardW=ratio*cardH; Rect R(Q1.x,Q1.y,cardW,cardH);
- теперь у вас есть четырехугольные вершины для источника и назначения, затем примените warpPerspective.
вы можете ссылаться ниже кода C++,
//Compute quad point for edge
Point Q1=Point2f(90,11);
Point Q2=Point2f(596,135);
Point Q3=Point2f(632,452);
Point Q4=Point2f(90,513);
// compute the size of the card by keeping aspect ratio.
double ratio=1.6;
double cardH=sqrt((Q3.x-Q2.x)*(Q3.x-Q2.x)+(Q3.y-Q2.y)*(Q3.y-Q2.y));//Or you can give your own height
double cardW=ratio*cardH;
Rect R(Q1.x,Q1.y,cardW,cardH);
Point R1=Point2f(R.x,R.y);
Point R2=Point2f(R.x+R.width,R.y);
Point R3=Point2f(Point2f(R.x+R.width,R.y+R.height));
Point R4=Point2f(Point2f(R.x,R.y+R.height));
std::vector<Point2f> quad_pts;
std::vector<Point2f> squre_pts;
quad_pts.push_back(Q1);
quad_pts.push_back(Q2);
quad_pts.push_back(Q3);
quad_pts.push_back(Q4);
squre_pts.push_back(R1);
squre_pts.push_back(R2);
squre_pts.push_back(R3);
squre_pts.push_back(R4);
Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts);
int offsetSize=150;
Mat transformed = Mat::zeros(R.height+offsetSize, R.width+offsetSize, CV_8UC3);
warpPerspective(src, transformed, transmtx, transformed.size());
//rectangle(src, R, Scalar(0,255,0),1,8,0);
line(src,Q1,Q2, Scalar(0,0,255),1,CV_AA,0);
line(src,Q2,Q3, Scalar(0,0,255),1,CV_AA,0);
line(src,Q3,Q4, Scalar(0,0,255),1,CV_AA,0);
line(src,Q4,Q1, Scalar(0,0,255),1,CV_AA,0);
imshow("quadrilateral", transformed);
imshow("src",src);
waitKey();
У меня есть лучшее решение, которое очень легко:
- Красный прямоугольник на исходном изображении и углы точек прямоугольника являются исходными точками
- Мы используем cv2.getPerspectiveTransform(src, dst)
который принимает исходные точки и точки назначения в качестве аргументов и возвращает матрицу преобразования, которая преобразует любое изображение в целевое изображение, как показано на диаграмме
- Мы используем эту матрицу преобразования в cv2.warpPerspective()
- Как видите, результаты лучше. Вы получаете очень хороший вид птицы изображения
import cv2
import matplotlib.pyplot as plt
import numpy as np
def unwarp(img, src, dst, testing):
h, w = img.shape[:2]
# use cv2.getPerspectiveTransform() to get M, the transform matrix, and Minv, the inverse
M = cv2.getPerspectiveTransform(src, dst)
# use cv2.warpPerspective() to warp your image to a top-down view
warped = cv2.warpPerspective(img, M, (w, h), flags=cv2.INTER_LINEAR)
if testing:
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
f.subplots_adjust(hspace=.2, wspace=.05)
ax1.imshow(img)
x = [src[0][0], src[2][0], src[3][0], src[1][0], src[0][0]]
y = [src[0][1], src[2][1], src[3][1], src[1][1], src[0][1]]
ax1.plot(x, y, color='red', alpha=0.4, linewidth=3, solid_capstyle='round', zorder=2)
ax1.set_ylim([h, 0])
ax1.set_xlim([0, w])
ax1.set_title('Original Image', fontsize=30)
ax2.imshow(cv2.flip(warped, 1))
ax2.set_title('Unwarped Image', fontsize=30)
plt.show()
else:
return warped, M
im = cv2.imread("so.JPG")
w, h = im.shape[0], im.shape[1]
# We will first manually select the source points
# we will select the destination point which will map the source points in
# original image to destination points in unwarped image
src = np.float32([(20, 1),
(540, 130),
(20, 520),
(570, 450)])
dst = np.float32([(600, 0),
(0, 0),
(600, 531),
(0, 531)])
unwarp(im, src, dst, True)
cv2.imshow("so", im)
cv2.waitKey(0)[![enter image description here][1]][1]
cv2.destroyAllWindows()