我使用getHomography和warpPerspective将图像从前视角更改为出价视图。
它的作用是图像扭曲到所需的视角,但裁剪关闭。它将扭曲的图像移动到图像框之外。我假设原因是因为操作导致负坐标。
我已经手动计算了翻译矩阵的计算点,而不是通过使用任何opencv:s函数来计算,因为棋盘函数未能检测到正确的点。
我想这可以通过对转换矩阵进行其他更改来解决。但那怎么办?另外,有没有办法确保变换后的图像沿x轴居中,然后将y轴调整到所需的位置?
现在完成工作的代码段:
cv::Mat image; // image is loaded with the original image
cv::Mat warpPers; // The container for the resulting image
cv::Mat H;
std::vector<cv::Point2f> src;
std::vector<cv::Point2f> dst;
// In reality several more points.
src.push_back(cv::Point2f(264,301));
src.push_back(cv::Point2f(434,301));
src.push_back(cv::Point2f(243,356));
src.push_back(cv::Point2f(476,356));
dst.push_back(cv::Point2f(243,123));
dst.push_back(cv::Point2f(476,123));
dst.push_back(cv::Point2f(243,356));
dst.push_back(cv::Point2f(476,356));
H = cv::findHomography(src, dst, CV_RANSAC);
cv::warpPerspective(image,
newPers,
H,
cv::Size(3000,3000),
cv::INTER_NEAREST | CV_WARP_FILL_OUTLIERS
);
cv::namedWindow("Warped persp", cv::WINDOW_AUTOSIZE );
cv::imshow( "Warped persp", newPers);
答案 0 :(得分:7)
Opencv提供了非常方便的方式来进行转换。你唯一要做的就是通过findHomography来处理单应性返回。 实际上,您提供的图像中的某些点可能位于x轴或y轴的负部分。 所以你必须在扭曲图像之前做一些检查。
步骤1:使用findHomography找到单应性H. 你会得到一个经典的单应性结构
H = [ h00, h01, h02;
h10, h11, h12;
h20, h21, 1];
步骤2:在变形后搜索图像角落的位置
所以让我来定义角落的顺序:
(0,0) ________ (0, w)
| |
|________|
(h,0) (h,w)
要做到这一点,只需创建一个类似的矩阵:
P = [0, w, w, 0;
0, 0, h, h;
1, 1, 1, 1]
使用H制作产品并获得扭曲的坐标:
P' = H * P
步骤3:使用这些新的4点检查x和y的最小值,并获得扭曲图像的大小 之后,您已经完成了这样的产品:
P' = [s1*x1, s2*x2, s3*x3, s4*x4;
s1*y1, s2*y2, s3*y3, s4*y4;
s1 , s2 , s3 , s4]
因此,要获得新的有效坐标,只需将第1行和第2行除以第3行
之后检查第一行上列的最小值,以及第二行上行的最小值(使用cvReduce)
找到包含图像的边界框(即warpPerspective函数的dst矩阵的维度),用cvReduce查找每行的最大值
让minx成为第一行(即列)的最小值,maxx(1行的最大值) miny和maxy为第二排。
因此扭曲图像的大小应为cvSize(maxx-minx,maxy-miny)
步骤4:对单应性添加校正 检查minx和/或miny是否为负,如果minx < 0然后将-minx添加到h02并且如果miny&lt; 0,然后将-miny添加到h12
所以H应该是:
H = [ h00, h01, h02-minx; //if minx <0
h10, h11, h12-miny; //if miny <0
h20, h21, 1];
第5步:扭曲图像
答案 1 :(得分:1)
如果我理解正确,那么基本上的问题就是需要一种方法来计算正确的偏移量,以平移扭曲的图像。我将解释如何获得正确的偏移量进行翻译。想法是,两幅图像中的匹配特征在最终缝合的图像中应具有相同的坐标。
假设我们按以下方式引用图片:
si
):需要变形的图像di
):透视图“源图片”将变形的图片wsi
):源图像
将其扭曲到目标图像透视图之后以下是您需要执行的操作,以便计算平移的偏移量:
在对好的匹配进行采样并从单应性图中找到蒙版之后,存储最佳匹配的关键点(一个距离最小且为整数的(应从单应性计算中获得的蒙版中值为1))在si
和di
中。假设分别在si and
di is
bm_si and
bm_di`中最匹配的关键点。
bm_si = [x1, y1,1]
bm_di = [x2, y2, 1]
只需将bm_si
与单应性矩阵(wsi
)相乘即可找到H
在bm_wsi = np.dot(H,bm_si)
中的位置。
bm_wsi = [x/bm_wsi[2] for x in bm_wsi]
di
根据要在si
变形(= {wsi
)的输出上放置bm_di
的位置,调整si
让我们说,如果您要从左图向右图(例如,左图为di
,右图为di
)变形,那么您将wsi
置于右图bm_di[0] += si.shape[0]
边,因此x_offset = bm_di[0] - bm_si[0]
完成上述步骤后
y_offset = bm_di[1] - bm_si[1]
si
使用计算出的偏移量找到新的单应性矩阵并扭曲T = np.array([[1, 0, x_offset], [0, 1, y_offset], [0, 0, 1]])
。
translated_H = np.dot(T.H)
wsi_frame_size = tuple(2*x for x in si.shape)
stitched = cv2.warpPerspective(si, translated_H, wsi_frame_size)
stitched[0:si.shape[0],si.shape[1]:] = di
list_1 = [i for i in list_1 if i[0] != i[1]]
答案 2 :(得分:0)
我认为这个问题OpenCV warpperspective与当前问题cv::warpPerspective only shows part of warped image
类似所以我也在这里给你答案https://stackoverflow.com/a/37275961/15485:
请尝试以下homography_warp
。
void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst);
src
是源图片。
H
是你的单应性。
dst
是扭曲的图像。
homography_warp
按照https://stackoverflow.com/users/1060066/matt-freeman的答案调整你的单应性https://stackoverflow.com/a/8229116/15485
// Convert a vector of non-homogeneous 2D points to a vector of homogenehous 2D points.
void to_homogeneous(const std::vector< cv::Point2f >& non_homogeneous, std::vector< cv::Point3f >& homogeneous)
{
homogeneous.resize(non_homogeneous.size());
for (size_t i = 0; i < non_homogeneous.size(); i++) {
homogeneous[i].x = non_homogeneous[i].x;
homogeneous[i].y = non_homogeneous[i].y;
homogeneous[i].z = 1.0;
}
}
// Convert a vector of homogeneous 2D points to a vector of non-homogenehous 2D points.
void from_homogeneous(const std::vector< cv::Point3f >& homogeneous, std::vector< cv::Point2f >& non_homogeneous)
{
non_homogeneous.resize(homogeneous.size());
for (size_t i = 0; i < non_homogeneous.size(); i++) {
non_homogeneous[i].x = homogeneous[i].x / homogeneous[i].z;
non_homogeneous[i].y = homogeneous[i].y / homogeneous[i].z;
}
}
// Transform a vector of 2D non-homogeneous points via an homography.
std::vector<cv::Point2f> transform_via_homography(const std::vector<cv::Point2f>& points, const cv::Matx33f& homography)
{
std::vector<cv::Point3f> ph;
to_homogeneous(points, ph);
for (size_t i = 0; i < ph.size(); i++) {
ph[i] = homography*ph[i];
}
std::vector<cv::Point2f> r;
from_homogeneous(ph, r);
return r;
}
// Find the bounding box of a vector of 2D non-homogeneous points.
cv::Rect_<float> bounding_box(const std::vector<cv::Point2f>& p)
{
cv::Rect_<float> r;
float x_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x;
float x_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x;
float y_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y;
float y_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y;
return cv::Rect_<float>(x_min, y_min, x_max - x_min, y_max - y_min);
}
// Warp the image src into the image dst through the homography H.
// The resulting dst image contains the entire warped image, this
// behaviour is the same of Octave's imperspectivewarp (in the 'image'
// package) behaviour when the argument bbox is equal to 'loose'.
// See http://octave.sourceforge.net/image/function/imperspectivewarp.html
void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst)
{
std::vector< cv::Point2f > corners;
corners.push_back(cv::Point2f(0, 0));
corners.push_back(cv::Point2f(src.cols, 0));
corners.push_back(cv::Point2f(0, src.rows));
corners.push_back(cv::Point2f(src.cols, src.rows));
std::vector< cv::Point2f > projected = transform_via_homography(corners, H);
cv::Rect_<float> bb = bounding_box(projected);
cv::Mat_<double> translation = (cv::Mat_<double>(3, 3) << 1, 0, -bb.tl().x, 0, 1, -bb.tl().y, 0, 0, 1);
cv::warpPerspective(src, dst, translation*H, bb.size());
}