首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【OpenCV】透视变换 Perspective Transformation(续)

  • 23-09-22 20:42
  • 3023
  • 12606
blog.csdn.net

透视变换的原理和矩阵求解请参见前一篇《透视变换 Perspective Transformation》。在OpenCV中也实现了透视变换的公式求解和变换函数。

求解变换公式的函数:

Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[])
输入原始图像和变换之后的图像的对应4个点,便可以得到变换矩阵。之后用求解得到的矩阵输入perspectiveTransform便可以对一组点进行变换:

void perspectiveTransform(InputArray src, OutputArray dst, InputArray m)
注意这里src和dst的输入并不是图像,而是图像对应的坐标。应用前一篇的例子,做个相反的变换:

  1. int main( )
  2. {
  3. Mat img=imread("boy.png");
  4. int img_height = img.rows;
  5. int img_width = img.cols;
  6. vector corners(4);
  7. corners[0] = Point2f(0,0);
  8. corners[1] = Point2f(img_width-1,0);
  9. corners[2] = Point2f(0,img_height-1);
  10. corners[3] = Point2f(img_width-1,img_height-1);
  11. vector corners_trans(4);
  12. corners_trans[0] = Point2f(150,250);
  13. corners_trans[1] = Point2f(771,0);
  14. corners_trans[2] = Point2f(0,img_height-1);
  15. corners_trans[3] = Point2f(650,img_height-1);
  16. Mat transform = getPerspectiveTransform(corners,corners_trans);
  17. cout<
  18. vector ponits, points_trans;
  19. for(int i=0;i
  20. for(int j=0;j
  21. ponits.push_back(Point2f(j,i));
  22. }
  23. }
  24. perspectiveTransform( ponits, points_trans, transform);
  25. Mat img_trans = Mat::zeros(img_height,img_width,CV_8UC3);
  26. int count = 0;
  27. for(int i=0;i
  28. uchar* p = img.ptr(i);
  29. for(int j=0;j
  30. int y = points_trans[count].y;
  31. int x = points_trans[count].x;
  32. uchar* t = img_trans.ptr(y);
  33. t[x*3] = p[j*3];
  34. t[x*3+1] = p[j*3+1];
  35. t[x*3+2] = p[j*3+2];
  36. count++;
  37. }
  38. }
  39. imwrite("boy_trans.png",img_trans);
  40. return 0;
  41. }

得到变换之后的图片:


注意这种将原图变换到对应图像上的方式会有一些没有被填充的点,也就是右图中黑色的小点。解决这种问题一是用差值的方式,再一种比较简单就是不用原图的点变换后对应找新图的坐标,而是直接在新图上找反向变换原图的点。说起来有点绕口,具体见前一篇《透视变换 Perspective Transformation》的代码应该就能懂啦。

除了getPerspectiveTransform()函数,OpenCV还提供了findHomography()的函数,不是用点来找,而是直接用透视平面来找变换公式。这个函数在特征匹配的经典例子中有用到,也非常直观:

  1. int main( int argc, char** argv )
  2. {
  3. Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
  4. Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );
  5. if( !img_object.data || !img_scene.data )
  6. { std::cout<< " --(!) Error reading images " << std::endl; return -1; }
  7. //-- Step 1: Detect the keypoints using SURF Detector
  8. int minHessian = 400;
  9. SurfFeatureDetector detector( minHessian );
  10. std::vector keypoints_object, keypoints_scene;
  11. detector.detect( img_object, keypoints_object );
  12. detector.detect( img_scene, keypoints_scene );
  13. //-- Step 2: Calculate descriptors (feature vectors)
  14. SurfDescriptorExtractor extractor;
  15. Mat descriptors_object, descriptors_scene;
  16. extractor.compute( img_object, keypoints_object, descriptors_object );
  17. extractor.compute( img_scene, keypoints_scene, descriptors_scene );
  18. //-- Step 3: Matching descriptor vectors using FLANN matcher
  19. FlannBasedMatcher matcher;
  20. std::vector< DMatch > matches;
  21. matcher.match( descriptors_object, descriptors_scene, matches );
  22. double max_dist = 0; double min_dist = 100;
  23. //-- Quick calculation of max and min distances between keypoints
  24. for( int i = 0; i < descriptors_object.rows; i++ )
  25. { double dist = matches[i].distance;
  26. if( dist < min_dist ) min_dist = dist;
  27. if( dist > max_dist ) max_dist = dist;
  28. }
  29. printf("-- Max dist : %f ", max_dist );
  30. printf("-- Min dist : %f ", min_dist );
  31. //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
  32. std::vector< DMatch > good_matches;
  33. for( int i = 0; i < descriptors_object.rows; i++ )
  34. { if( matches[i].distance < 3*min_dist )
  35. { good_matches.push_back( matches[i]); }
  36. }
  37. Mat img_matches;
  38. drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
  39. good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
  40. vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
  41. //-- Localize the object from img_1 in img_2
  42. std::vector obj;
  43. std::vector scene;
  44. for( size_t i = 0; i < good_matches.size(); i++ )
  45. {
  46. //-- Get the keypoints from the good matches
  47. obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
  48. scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
  49. }
  50. Mat H = findHomography( obj, scene, RANSAC );
  51. //-- Get the corners from the image_1 ( the object to be "detected" )
  52. std::vector obj_corners(4);
  53. obj_corners[0] = Point(0,0); obj_corners[1] = Point( img_object.cols, 0 );
  54. obj_corners[2] = Point( img_object.cols, img_object.rows ); obj_corners[3] = Point( 0, img_object.rows );
  55. std::vector scene_corners(4);
  56. perspectiveTransform( obj_corners, scene_corners, H);
  57. //-- Draw lines between the corners (the mapped object in the scene - image_2 )
  58. Point2f offset( (float)img_object.cols, 0);
  59. line( img_matches, scene_corners[0] + offset, scene_corners[1] + offset, Scalar(0, 255, 0), 4 );
  60. line( img_matches, scene_corners[1] + offset, scene_corners[2] + offset, Scalar( 0, 255, 0), 4 );
  61. line( img_matches, scene_corners[2] + offset, scene_corners[3] + offset, Scalar( 0, 255, 0), 4 );
  62. line( img_matches, scene_corners[3] + offset, scene_corners[0] + offset, Scalar( 0, 255, 0), 4 );
  63. //-- Show detected matches
  64. imshow( "Good Matches & Object detection", img_matches );
  65. waitKey(0);
  66. return 0;
  67. }

代码运行效果:



findHomography()函数直接通过两个平面上相匹配的特征点求出变换公式,之后代码又对原图的四个边缘点进行变换,在右图上画出对应的矩形。这个图也很好地解释了所谓透视变换的“Viewing Plane”。


(转载请注明作者和出处:http://iyenn.com/index/link?url=http://blog.csdn.net/xiaowei_cqu 未经允许请勿用于商业用途)



文章知识点与官方知识档案匹配,可进一步学习相关知识
OpenCV技能树首页概览20473 人正在系统学习中
注:本文转载自blog.csdn.net的xiaowei_cqu的文章"http://blog.csdn.net/xiaowei_cqu/article/details/26478135"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top