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

C++ OpenCV實(shí)戰(zhàn)之圖像透視矯正

 更新時(shí)間:2022年01月10日 14:28:48   作者:Zero___Chen  
這篇文章主要介紹了通過C++ OpenCV實(shí)現(xiàn)圖像的透視矯正,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的參考價(jià)值,感興趣的可以了解一下

前言

本文將使用OpenCV C++ 進(jìn)行圖像透視矯正。

一、圖像預(yù)處理

原圖如圖所示。首先進(jìn)行圖像預(yù)處理。將圖像進(jìn)行灰度、濾波、二值化、形態(tài)學(xué)等操作,目的是為了下面的輪廓提取。在這里我還使用了形態(tài)學(xué)開、閉操作,目的是使整個(gè)二值圖像連在一起。大家在做圖像預(yù)處理時(shí),可以根據(jù)圖像特征自行處理。

	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	Mat gaussian;
	GaussianBlur(gray, gaussian, Size(3, 3), 0);

	Mat thresh;
	threshold(gaussian, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	Mat kernel1 = getStructuringElement(MORPH_RECT, Size(7, 7));
	Mat close;
	morphologyEx(open, close, MORPH_CLOSE, kernel1);

如圖就是經(jīng)過圖像預(yù)處理得到的二值圖像。

二、輪廓提取

1.提取最外輪廓

	vector<vector<Point>>contours;	
	findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

使用findContours、RETR_EXTERNAL就可以提取出物體最外輪廓。

2.提取矩形四個(gè)角點(diǎn)

接下來將使用approxPolyDP進(jìn)行多邊形輪廓擬合,目的是為了找到矩形的四個(gè)角點(diǎn)。關(guān)于approxPolyDP API大家可以自行百度查看其用法。

	vector<vector<Point>>conPoly(contours.size());
	vector<Point>srcPts;

	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);

		if (area > 10000)
		{
			double peri = arcLength(contours[i], true);

			approxPolyDP(contours[i], conPoly[i], 0.02*peri, true);
             //獲取矩形四個(gè)角點(diǎn)
			srcPts = { conPoly[i][0],conPoly[i][1],conPoly[i][2],conPoly[i][3] };

		}

	}

3.將矩形角點(diǎn)排序

由于我們之前使用的approxPolyDP獲取的角點(diǎn)是無序的,所以我們得確定各角點(diǎn)所在的位置。在這里我使用的算法是根據(jù)其角點(diǎn)所在圖像位置特征確定左上、左下、右下、右上四個(gè)點(diǎn)。

	int width = src.cols / 2;
	int height = src.rows / 2;
	int T_L, T_R, B_R, B_L;

	for (int i = 0; i < srcPts.size(); i++)
	{
		if (srcPts[i].x < width && srcPts[i].y < height)
		{
			T_L = i;
		}
		if (srcPts[i].x > width && srcPts[i].y < height)
		{
			T_R = i;
		}
		if (srcPts[i].x > width && srcPts[i].y > height)
		{
			B_R = i;
		}
		if (srcPts[i].x < width && srcPts[i].y > height)
		{
			B_L = i;
		}
		
	}

如圖所示。至此已經(jīng)完成了矩形四個(gè)角點(diǎn)的定位。接下來就可以使用透視變換進(jìn)行圖像矯正了。

三、透視矯正

在這里我們需要知道透視變換一個(gè)原理:

變換后,圖像的長(zhǎng)和寬應(yīng)該變?yōu)椋?/p>

長(zhǎng) = max(變換前左邊長(zhǎng),變換前右邊長(zhǎng))

寬 = max(變換前上邊長(zhǎng),變換前下邊長(zhǎng))

設(shè)變換后圖像的左上角位置為原點(diǎn)位置。

	double LeftHeight = EuDis(srcPts[T_L], srcPts[B_L])	
	double RightHeight = EuDis(srcPts[T_R], srcPts[B_R]);
	double MaxHeight = max(LeftHeight, RightHeight);

	double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]);
	double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]);
	double MaxWidth = max(UpWidth, DownWidth);

確定變換后的長(zhǎng)寬之后,就可以使用getPerspectiveTransform、warpPerspective進(jìn)行透視矯正了。

//這里使用的順序是左上、右上、右下、左下順時(shí)針順序。SrcAffinePts、DstAffinePts要一一對(duì)應(yīng)
	Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) };
	Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) };

	Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
	
	Mat DstImg;
	warpPerspective(src, DstImg, M, Point(MaxWidth, MaxHeight));

這就是進(jìn)行透視矯正之后的效果。

四、源碼

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

double EuDis(Point pt1, Point pt2)
{
	return sqrt((pt2.x - pt1.x)*(pt2.x - pt1.x) + (pt2.y - pt1.y)*(pt2.y - pt1.y));
}

int main()
{

	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "No Image!" << endl;
		system("pause");
		return -1;
	}

	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	Mat gaussian;
	GaussianBlur(gray, gaussian, Size(3, 3), 0);

	Mat thresh;
	threshold(gaussian, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	Mat kernel1 = getStructuringElement(MORPH_RECT, Size(7, 7));
	Mat close;
	morphologyEx(open, close, MORPH_CLOSE, kernel1);

	vector<vector<Point>>contours;	
	findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	vector<vector<Point>>conPoly(contours.size());
	vector<Point>srcPts;

	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);

		if (area > 10000)
		{
			double peri = arcLength(contours[i], true);

			approxPolyDP(contours[i], conPoly[i], 0.02*peri, true);

			srcPts = { conPoly[i][0],conPoly[i][1],conPoly[i][2],conPoly[i][3] };

		}

	}

	int width = src.cols / 2;
	int height = src.rows / 2;
	int T_L, T_R, B_R, B_L;

	for (int i = 0; i < srcPts.size(); i++)
	{
		if (srcPts[i].x < width && srcPts[i].y < height)
		{
			T_L = i;
		}
		if (srcPts[i].x > width && srcPts[i].y < height)
		{
			T_R = i;
		}
		if (srcPts[i].x > width && srcPts[i].y > height)
		{
			B_R = i;
		}
		if (srcPts[i].x < width && srcPts[i].y > height)
		{
			B_L = i;
		}
		
	}

	//circle(src, srcPts[T_L], 10, Scalar(0, 0, 255), -1);
	//circle(src, srcPts[T_R], 10, Scalar(0, 255, 255), -1);
	//circle(src, srcPts[B_R], 10, Scalar(255, 0, 0), -1);
	//circle(src, srcPts[B_L], 10, Scalar(0, 255, 0), -1);

	/*
	變換后,圖像的長(zhǎng)和寬應(yīng)該變?yōu)椋?
	長(zhǎng) = max(變換前左邊長(zhǎng),變換前右邊長(zhǎng))
	寬 = max(變換前上邊長(zhǎng),變換前下邊長(zhǎng))
	設(shè)變換后圖像的左上角位置為原點(diǎn)位置。
	*/

	double LeftHeight = EuDis(srcPts[T_L], srcPts[B_L]);
	double RightHeight = EuDis(srcPts[T_R], srcPts[B_R]);
	double MaxHeight = max(LeftHeight, RightHeight);

	double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]);
	double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]);
	double MaxWidth = max(UpWidth, DownWidth);

	Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) };
	Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) };

	Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);

	Mat DstImg;
	warpPerspective(src, DstImg, M, Point(MaxWidth, MaxHeight));
	//imshow("Dst", DstImg);


	imshow("src", src);
	waitKey(0);
	destroyAllWindows();

	system("pause");
	return 0;
}

總結(jié)

本文使用OpenCV C++ 進(jìn)行圖像透視矯正,關(guān)鍵步驟有以下幾點(diǎn)。

1、圖像預(yù)處理,獲取二值圖像。

2、將二值圖像進(jìn)行輪廓提取,定位矩形四個(gè)角點(diǎn),并確定其位置。

3、確定圖像變換后的長(zhǎng)、寬。并將SrcAffinePts、DstAffinePts一一對(duì)應(yīng)之后進(jìn)行透視變換。

到此這篇關(guān)于C++ OpenCV實(shí)戰(zhàn)之圖像透視矯正的文章就介紹到這了,更多相關(guān)C++ OpenCV圖像透視矯正內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實(shí)現(xiàn)雙向冒泡排序算法

    C++實(shí)現(xiàn)雙向冒泡排序算法

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)雙向冒泡排序算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C語言打印正方形實(shí)例代碼

    C語言打印正方形實(shí)例代碼

    大家好,本篇文章主要講的是C語言打印正方形實(shí)例代碼,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C語言淺析指針的使用

    C語言淺析指針的使用

    C語言這門課程在計(jì)算機(jī)的基礎(chǔ)教學(xué)中一直占有比較重要的地位,然而要想突破C語言的學(xué)習(xí),對(duì)指針的掌握是非常重要的,本文將具體針對(duì)指針的基礎(chǔ)做詳盡的介紹
    2022-07-07
  • 推薦幾款C/C++的編譯器、編譯環(huán)境(非常全面的比較)

    推薦幾款C/C++的編譯器、編譯環(huán)境(非常全面的比較)

    這篇文章主要介紹了C/C++編譯器的一些易混淆概念,這里腳本之家小編特為大家分享一下,需要的朋友可以參考下
    2021-06-06
  • MATLAB算法技巧和實(shí)現(xiàn)斐波那契數(shù)列的解決思路

    MATLAB算法技巧和實(shí)現(xiàn)斐波那契數(shù)列的解決思路

    這篇文章主要介紹了MATLAB算法技巧和實(shí)現(xiàn)斐波那契數(shù)列,這篇主要說一下自己在算法設(shè)計(jì)課上用matlab做的兩道算法題,題目解起來都比較簡(jiǎn)單,但是需要些技巧,需要的朋友可以參考下
    2022-12-12
  • C語言八大排序之堆排序

    C語言八大排序之堆排序

    堆排序是利用堆這種數(shù)據(jù)結(jié)構(gòu)而設(shè)計(jì)的一種排序算法,堆排序是一種選擇排序,它的最壞,最好,平均時(shí)間復(fù)雜度均為O(nlogn),它也是不穩(wěn)定排序
    2022-02-02
  • C/C++指針介紹與使用詳解

    C/C++指針介紹與使用詳解

    不知從何時(shí)起對(duì)你一眼萬年,從此,每一天被賦予了特別的意義。時(shí)隔多年,依然揮之不去是你------指針?。?!本篇中幾乎數(shù)據(jù)類型只用了int,但是float、double等也是可以的
    2022-08-08
  • Qt實(shí)現(xiàn)文本編輯器(一)

    Qt實(shí)現(xiàn)文本編輯器(一)

    在Qt中QMainWindow是一個(gè)為用戶提供主窗口程序的類,包含了:菜單欄、工具欄、錨接部件、狀態(tài)欄以及一個(gè)中部件。本文將利用QMainWindow制作一個(gè)文本編輯器,感興趣的可以試一試
    2022-01-01
  • C++對(duì)象模型和this指針詳解

    C++對(duì)象模型和this指針詳解

    這篇文章主要介紹了詳解C++對(duì)象模型和this指針,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-10-10
  • 深入淺析C語言與C++的區(qū)別與聯(lián)系

    深入淺析C語言與C++的區(qū)別與聯(lián)系

    這篇文章主要為大家介紹了深入的分析了C語言與C++的區(qū)別與聯(lián)系,文中通過詳細(xì)的示例進(jìn)行了對(duì)比,以便大家更容易的看懂理解,有需要的朋友可以借鑒參考下
    2021-11-11

最新評(píng)論

大同市| 浑源县| 凌云县| 柳林县| 太和县| 靖州| 自治县| 松溪县| 保亭| 郑州市| 塔城市| 颍上县| 海林市| 房产| 汝南县| 渝北区| 汝州市| 靖远县| 克东县| 玛沁县| 石柱| 咸阳市| 鄢陵县| 安康市| 淮滨县| 黔西县| 老河口市| 和静县| 溧阳市| 北辰区| 哈尔滨市| 嘉荫县| 墨江| 延吉市| 建宁县| 北碚区| 兰溪市| 沛县| 周至县| 日土县| 金堂县|