最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用C++?OpenCV?實(shí)現(xiàn)從投影圖像恢復(fù)仿射特性

 更新時(shí)間:2021年11月29日 11:23:55   作者:tan_tao375  
我們通過相機(jī)拍攝的圖片存在各種畸變,其中投影畸變使得原本平行的直線不再平行,就會產(chǎn)生照片中近大遠(yuǎn)小的效果。本文將具體介紹如何利用OPenCV實(shí)現(xiàn)從投影圖像恢復(fù)仿射特性,接下來跟著小編一起學(xué)習(xí)吧

原理

我們通過相機(jī)拍攝的圖片存在各種畸變,其中投影畸變使得原本平行的直線不再平行,就會產(chǎn)生照片中近大遠(yuǎn)小的效果,要校正這一畸變,書中給了很多方法,這里是其中的一種。

我們可以將投影變換拆分成相似變換、仿射變換和投影變換三部分, 如下圖,

其中相似變換和仿射變換不會改變infinite line,只有投影變換會改變。因此只要找到畸變圖像中的這條線,就能夠恢復(fù)圖像的仿射特性(相當(dāng)于逆轉(zhuǎn)投影變換)。而要確定這條線的位置,就得至少知道線上的兩個(gè)點(diǎn)。我們知道,所有平行線的交點(diǎn)都在infinite line上面,因此,我們只需要找到圖像上的兩對平行線(原本是平行,圖像上不再平行),求出對應(yīng)的兩個(gè)交點(diǎn),就能找到infinite line了,如下圖

進(jìn)而可以圖像的恢復(fù)仿射特性。

實(shí)現(xiàn)思路

首先我們的畸變圖像如下圖,

利用公式:

l = x1 × x2

可以通過x1、x2的齊次坐標(biāo)求出兩點(diǎn)連線l的齊次坐標(biāo)。在圖中我們找到兩對平行線l1、l2和l3、l4,如下圖

利用公式:

x = l1 × l2

可以通過l1、l2以及l(fā)3、l4的齊次坐標(biāo)分別求出兩對平行線的交點(diǎn)A12、A34,直線A12A34就是我們要找的infinite line。假設(shè)該直線的齊次坐標(biāo)為(l1,l2,l3),那么通過矩陣:

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

就能夠?qū)⒅本€(l1,l2,l3)變換成(0,0,1),即將該直線還原成為infinite line。同理我們也可以利用H矩陣,通過公式:

x = Hx'

還原投影畸變。

主要代碼

代碼一共需要運(yùn)行兩次

第一次運(yùn)行的主函數(shù):

int main()
{
	Mat src = imread("distortion.jpg", IMREAD_GRAYSCALE);
	IplImage *src1 = cvLoadImage("distortion.jpg");
	//第一步,通過鼠標(biāo)獲取圖片中某個(gè)點(diǎn)的坐標(biāo),運(yùn)行第一步時(shí)注釋掉Rectify(points_3d, src, src1);,將獲取到的八個(gè)點(diǎn)寫入
	//points_3d[8]坐標(biāo)數(shù)組中,因?yàn)槭驱R次坐標(biāo),x3 = 1
	GetMouse(src1);
	//輸入畸變圖上的8個(gè)關(guān)鍵點(diǎn)
	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) };
	//第二步,校正圖像,運(yùn)行此步驟時(shí)注釋掉GetMouse(src1);,解除注釋Rectify(points_3d, src, src1);
	//Rectify(points_3d, src, src1);
	imshow("yuantu", src);
	waitKey(0);	
}

其他函數(shù):

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);
}

在彈出來的圖片中點(diǎn)擊任意地方可獲得改點(diǎn)的圖像坐標(biāo)(x1,x2),如下圖:

我選取了a、b、c、d四個(gè)點(diǎn),其中:

ab // cd		  ac // bd

將這四個(gè)點(diǎn)的坐標(biāo)按照a、b、c、d、c、a、d、b的順序填入points_3d[8]坐標(biāo)數(shù)組中,第一次運(yùn)行結(jié)束。

第二次運(yùn)行的主函數(shù):

int main()
{
	Mat src = imread("distortion.jpg", IMREAD_GRAYSCALE);
	IplImage *src1 = cvLoadImage("distortion.jpg");
	//第一步,通過鼠標(biāo)獲取圖片中某個(gè)點(diǎn)的坐標(biāo),運(yùn)行第一步時(shí)注釋掉Rectify(points_3d, src, src1);,將獲取到的八個(gè)點(diǎn)寫入
	//points_3d[8]矩陣中,因?yàn)槭驱R次坐標(biāo),x3 = 1
	//GetMouse(src1);
	//輸入畸變圖上的8個(gè)關(guān)鍵點(diǎn)
	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) };
	//第二步,校正圖像,運(yùn)行此步驟時(shí)注釋掉GetMouse(src1);,解除注釋Rectify(points_3d, src, src1);
	Rectify(points_3d, src, src1);
	imshow("yuantu", src);
	waitKey(0);	
}

校正函數(shù):

void Rectify(Point3d* points, Mat src, IplImage* img)
{
    //通過輸入的8個(gè)點(diǎn)得到4條連線
    vector<vector<float>> lines;
    int num_lines = 4;
    for(int i = 0; i < num_lines; i++)
    {
        //獲取兩點(diǎn)連線
        GetLineFromPoints(points[2 * i], points[2 * i + 1], lines);
    }
    //分別求取兩個(gè)交點(diǎn)
    vector<Point3f> intersect_points;
    int num_intersect_points = 2;
    for (int i = 0; i < num_intersect_points; i++)
    {
        //計(jì)算交點(diǎn)
        GetIntersectPoint(lines[2 * i], lines[2 * i + 1], intersect_points);
    }
    //通過兩個(gè)交點(diǎn)連線求消失線
    vector<vector<float>> vanishing_line;
    GetLineFromPoints(intersect_points[0], intersect_points[1], vanishing_line);
    //恢復(fù)矩陣
    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;
    //定義直線的三個(gè)齊次坐標(biāo)
    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;
    //定義交點(diǎn)的三個(gè)齊次坐標(biāo)
    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);
}

運(yùn)行結(jié)果如下圖:

校正效果和點(diǎn)的選取有關(guān),因?yàn)槭髽?biāo)點(diǎn)擊的那個(gè)點(diǎn)不一定是我們真正想要的點(diǎn),建議一條直線的的兩個(gè)點(diǎn)間距盡量大一些。

完整代碼鏈接??提取碼:qltt?

到此這篇關(guān)于利用C++ OpenCV 實(shí)現(xiàn)從投影圖像恢復(fù)仿射特性的文章就介紹到這了,更多相關(guān)C++ OpenCV 投影圖像恢復(fù)仿射特性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • VC++6.0實(shí)現(xiàn)直線掃描轉(zhuǎn)換的圖文教程

    VC++6.0實(shí)現(xiàn)直線掃描轉(zhuǎn)換的圖文教程

    這篇文章主要給大家介紹了關(guān)于VC++6.0實(shí)現(xiàn)直線掃描轉(zhuǎn)換的相關(guān)資料,文中通過圖文將實(shí)現(xiàn)的步驟一步步介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用VC++6.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-01-01
  • C++適用入門同學(xué)的模板講解

    C++適用入門同學(xué)的模板講解

    人們需要編寫多個(gè)形式和功能都相似的函數(shù),因此有了函數(shù)模板來減少重復(fù)勞動;人們也需要編寫多個(gè)形式和功能都相似的類,于是?C++?引人了類模板的概念,編譯器從類模板可以自動生成多個(gè)類,避免了程序員的重復(fù)勞動
    2022-07-07
  • C++使用jsoncpp庫解析Json

    C++使用jsoncpp庫解析Json

    對json的解析操作是我們?nèi)粘i_發(fā)中經(jīng)常會遇到的一個(gè)需求,下面這篇文章主要給大家介紹了關(guān)于C++使用jsoncpp庫解析Json的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • C++中memcpy和memmove的區(qū)別總結(jié)

    C++中memcpy和memmove的區(qū)別總結(jié)

    這篇文章主要介紹了C++中memcpy和memmove的區(qū)別總結(jié),這個(gè)問題經(jīng)常出現(xiàn)在C++的面試題目中,需要的朋友可以參考下
    2014-10-10
  • C++中的struct和class的區(qū)別詳解

    C++中的struct和class的區(qū)別詳解

    這篇文章主要介紹了C++中的struct和class的區(qū)別詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-08-08
  • C++制作俄羅斯方塊

    C++制作俄羅斯方塊

    俄羅斯方塊寫過好幾次了,每次的感覺都不一樣,都有新的收獲。就像達(dá)芬奇畫雞蛋一樣,雖然都是畫同樣的雞蛋,但是每次都有不同的收獲。&nbsp;
    2016-05-05
  • C++中輸出十六進(jìn)制形式的字符串

    C++中輸出十六進(jìn)制形式的字符串

    這篇文章主要給大家介紹了C++中輸出十六進(jìn)制形式的字符串,文中給出了詳細(xì)的介紹,有需要的朋友可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • C語言return, exit, abort的區(qū)別

    C語言return, exit, abort的區(qū)別

    這篇文章主要介紹了C語言return, exit, abort的區(qū)別,一般情況下,在C語言中退出一個(gè)程序用return,如果在main函數(shù)中,return在清理局部對象之后,會調(diào)用exit函數(shù),和return相比,exit并不會銷毀局部對象,下面一起進(jìn)入文章了解更詳細(xì)內(nèi)容吧,需要的朋友也可以參考一下
    2022-01-01
  • C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序)

    C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng)

    C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評論

四平市| 布尔津县| 莱芜市| 松潘县| 榆树市| 获嘉县| 阳城县| 肥城市| 桂东县| 建始县| 大竹县| 平舆县| 靖宇县| 东乌| 平山县| 偏关县| 西乡县| 扎囊县| 南乐县| 沁源县| 沙河市| 洪湖市| 调兵山市| 民勤县| 绵竹市| 施甸县| 巴中市| 临江市| 通城县| 霞浦县| 岑溪市| 新野县| 海城市| 都昌县| 合川市| 遂昌县| 平乡县| 进贤县| 社旗县| 罗平县| 德钦县|