返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >如何利用C++ OpenCV 实现从投影图像恢复仿射特性
  • 332
分享到

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

2023-06-21 21:06:57 332人浏览 独家记忆
摘要

如何利用c++ OpenCV 实现从投影图像恢复仿射特性,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。原理我们通过相机拍摄的图片存在各种畸变,其中投影畸

如何利用c++ OpenCV 实现从投影图像恢复仿射特性,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

原理

我们通过相机拍摄的图片存在各种畸变,其中投影畸变使得原本平行的直线不再平行,就会产生照片中近大远小的效果,要校正这一畸变,书中给了很多方法,这里是其中的一种。

我们可以将投影变换拆分成相似变换、仿射变换和投影变换三部分, 如下图,

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

其中相似变换和仿射变换不会改变infinite line,只有投影变换会改变。因此只要找到畸变图像中的这条线,就能够恢复图像的仿射特性(相当于逆转投影变换)。而要确定这条线的位置,就得至少知道线上的两个点。我们知道,所有平行线的交点都在infinite line上面,因此,我们只需要找到图像上的两对平行线(原本是平行,图像上不再平行),求出对应的两个交点,就能找到infinite line了,如下图

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

进而可以图像的恢复仿射特性。

实现思路

首先我们的畸变图像如下图,

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

利用公式:

l = x1 × x2

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

可以通过x1、x2的齐次坐标求出两点连线l的齐次坐标。在图中我们找到两对平行线l1、l2和l3、l4,如下图

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

利用公式:

x = l1 × l2

可以通过l1、l2以及l3、l4的齐次坐标分别求出两对平行线的交点A12、A34,直线A12A34就是我们要找的infinite line。假设该直线的齐次坐标为(l1,l2,l3),那么通过矩阵:

H = ((1,0,0),(0,1,0),(l1,l2,l3))

就能够将直线(l1,l2,l3)变换成(0,0,1),即将该直线还原成为infinite line。同理我们也可以利用H矩阵,通过公式:

x = Hx'

还原投影畸变。

主要代码

代码一共需要运行两次

第一次运行的主函数:

int main(){Mat src = imread("distortion.jpg", IMREAD_GRAYSCALE);IplImage *src1 = cvLoadImage("distortion.jpg");//第一步,通过鼠标获取图片中某个点的坐标,运行第一步时注释掉Rectify(points_3D, src, src1);,将获取到的八个点写入//points_3d[8]坐标数组中,因为是齐次坐标,x3 = 1GetMouse(src1);//输入畸变图上的8个关键点Point3d points_3d[8] = { Point3d(99, 147, 1), Point3d(210, 93, 1), Point3d(144, 184, 1), Point3d(261, 122, 1),Point3d(144, 184, 1), Point3d(99, 147, 1), Point3d(261, 122, 1), Point3d(210, 93, 1) };//第二步,校正图像,运行此步骤时注释掉GetMouse(src1);,解除注释Rectify(points_3d, src, src1);//Rectify(points_3d, src, src1);imshow("yuantu", src);waiTKEy(0);}

其他函数:

void on_mouse(int event, int x, int y, int flags, void* ustc){    CvFont font;    cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA);    if (event == CV_EVENT_LBUTTONDOWN)    {        CvPoint pt = cvPoint(x, y);        char temp[16];        sprintf(temp, "(%d,%d)", pt.x, pt.y);        cvPutText(src, temp, pt, &font, cvScalar(255, 255, 255, 0));        cvCircle(src, pt, 2, cvScalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);        cvShowImage("src", src);    }}void GetMouse(IplImage *img){    src = img;    cvNamedWindow("src", 1);    cvSetMouseCallback("src", on_mouse, 0);    cvShowImage("src", src);    waitKey(0);}

在弹出来的图片中点击任意地方可获得改点的图像坐标(x1,x2),如下图:

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

我选取了a、b、c、d四个点,其中:

ab // cd  ac // bd

将这四个点的坐标按照a、b、c、d、c、a、d、b的顺序填入points_3d[8]坐标数组中,第一次运行结束。

第二次运行的主函数:

int main(){Mat src = imread("distortion.jpg", IMREAD_GRAYSCALE);IplImage *src1 = cvLoadImage("distortion.jpg");//第一步,通过鼠标获取图片中某个点的坐标,运行第一步时注释掉Rectify(points_3d, src, src1);,将获取到的八个点写入//points_3d[8]矩阵中,因为是齐次坐标,x3 = 1//GetMouse(src1);//输入畸变图上的8个关键点Point3d points_3d[8] = { Point3d(99, 147, 1), Point3d(210, 93, 1), Point3d(144, 184, 1), Point3d(261, 122, 1),Point3d(144, 184, 1), Point3d(99, 147, 1), Point3d(261, 122, 1), Point3d(210, 93, 1) };//第二步,校正图像,运行此步骤时注释掉GetMouse(src1);,解除注释Rectify(points_3d, src, src1);Rectify(points_3d, src, src1);imshow("yuantu", src);waitKey(0);}

校正函数:

void Rectify(Point3d* points, Mat src, IplImage* img){    //通过输入的8个点得到4条连线    vector<vector<float>> lines;    int num_lines = 4;    for(int i = 0; i < num_lines; i++)    {        //获取两点连线        GetLineFromPoints(points[2 * i], points[2 * i + 1], lines);    }    //分别求取两个交点    vector<Point3f> intersect_points;    int num_intersect_points = 2;    for (int i = 0; i < num_intersect_points; i++)    {        //计算交点        GetIntersectPoint(lines[2 * i], lines[2 * i + 1], intersect_points);    }    //通过两个交点连线求消失线    vector<vector<float>> vanishing_line;    GetLineFromPoints(intersect_points[0], intersect_points[1], vanishing_line);    //恢复矩阵    float H[3][3] = {{1, 0, 0},                     {0, 1, 0},                     {vanishing_line[0][0], vanishing_line[0][1], vanishing_line[0][2]}};    Mat image = Mat::zeros(src.rows, src.cols, CV_8UC1);    GetRectifingImage(vanishing_line[0], src, image);    int i = 0;}void GetLineFromPoints(Point3d point1, Point3d point2, vector<vector<float>> &lines){    vector<float> line;    //定义直线的三个齐次坐标    float l1 = 0;    float l2 = 0;    float l3 = 0;    l1 = (point1.y * point2.z - point1.z * point2.y);    l2 = (point1.z * point2.x - point1.x * point2.z);    l3 = (point1.x * point2.y - point1.y * point2.x);    //归一化    l1 = l1 / l3;    l2 = l2 / l3;    l3 = 1;    line.push_back(l1);    line.push_back(l2);    line.push_back(l3);     lines.push_back(line);}void GetIntersectPoint(vector<float> line1, vector<float> line2, vector<Point3f> &intersect_points){    Point3f intersect_point;    //定义交点的三个齐次坐标    float x1 = 0;    float x2 = 0;    float x3 = 0;    x1 = (line1[1] * line2[2] - line1[2] * line2[1]);    x2 = (line1[2] * line2[0] - line1[0] * line2[2]);    x3 = (line1[0] * line2[1] - line1[1] * line2[0]);    //归一化    x1 = x1 / x3;    x2 = x2 / x3;    x3 = 1;    intersect_point.x = x1;    intersect_point.y = x2;    intersect_point.z = x3;    intersect_points.push_back(intersect_point);}int Round(float x){    return (x > 0.0) ? floor(x + 0.5) : ceil(x - 0.5);}void GetRectifingImage(vector<float> line, Mat src, Mat dst){    Size size_src = src.size();    for (int i = 0; i < size_src.height; i++)    {        for (int j = 0; j < size_src.width; j++)        {            float x3 = line[0] * j + line[1] * i + line[2] * 1;            int x1 = Round(j / x3);            int x2 = Round(i / x3);            if (x1 < size_src.width && x1 >= 0 && x2 < size_src.height && x2 >= 0)            {                dst.at<uint8_t>(x2, x1) = src.at<uint8_t>(i, j);            }        }    }    imshow("src", src);    imshow("dst", dst);    waitKey(0);}

运行结果如下图:

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

校正效果和点的选取有关,因为鼠标点击的那个点不一定是我们真正想要的点,建议一条直线的的两个点间距尽量大一些。

关于如何利用C++ OpenCV 实现从投影图像恢复仿射特性问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网其他教程频道了解更多相关知识。

--结束END--

本文标题: 如何利用C++ OpenCV 实现从投影图像恢复仿射特性

本文链接: https://lsjlt.com/news/300801.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 利用C++ OpenCV 实现从投影图像恢复仿射特性
    目录原理实现思路主要代码原理 我们通过相机拍摄的图片存在各种畸变,其中投影畸变使得原本平行的直线不再平行,就会产生照片中近大远小的效果,要校正这一畸变,书中给了很多方法,这里是其中的...
    99+
    2024-04-02
  • 如何利用C++ OpenCV 实现从投影图像恢复仿射特性
    如何利用C++ OpenCV 实现从投影图像恢复仿射特性,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。原理我们通过相机拍摄的图片存在各种畸变,其中投影畸...
    99+
    2023-06-21
  • C++ OpenCV如何实现图像修复功能
    本篇文章给大家分享的是有关C++ OpenCV如何实现图像修复功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。前言下面将使用OpenCV C++ 对有瑕疵的图像进行...
    99+
    2023-06-26
  • 如何利用Opencv实现图像的加密解密
    目录1、基础:基于异或操作实现图像加密解密Opencv-python代码实现效果展示:2、进阶:基于混沌序列构成异或模板实现图像加密解密结果展示:总结1、基础:基于异或操作实现图像加...
    99+
    2024-04-02
  • 如何利用Matlab仿真实现图像烟雾识别
    这篇文章主要为大家展示了“如何利用Matlab仿真实现图像烟雾识别”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何利用Matlab仿真实现图像烟雾识别”这篇文章吧。一、算法简介1.1 c-me...
    99+
    2023-06-21
  • C++ opencv如何利用grabCut算法实现抠图
    今天小编给大家分享一下C++ opencv如何利用grabCut算法实现抠图的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解...
    99+
    2023-06-30
  • 使用C++如何实现PatchMatch图像修复算法
    今天小编给大家分享的是使用C++如何实现PatchMatch图像修复算法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。PatchMatch算法出自Barnes的论文PatchMatc...
    99+
    2023-06-14
  • 如何利用Python+OpenCV实现简易图像边缘轮廓检测(零基础)
    目录前言函数基础与三方库cv.threshold(pic,thresh,maxvalue,model)cv.findContours(待处理图片,model(提取模式),method...
    99+
    2024-04-02
  • C语言中如何利用and-or条件判断的特性来实现三元条件判断
    这篇文章主要介绍了C语言中如何利用and-or条件判断的特性来实现三元条件判断,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。利用and-or...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作