opencv API

1.图像轮廓与图像分割修复

1.1轮廓

API: findContours drawContours

void findContours(InputOutputArray image, OutputArrayOfArrays contours, 
OutputArray hierarchy, int mode, int method, Point offset = Point() );
参数说明
image输入的二值图像,可以是8位单通道图像(如灰度图)或32位浮点型单通道图像。
contours输出的轮廓,表示为vector<vector<Point>>类型的变量。每个轮廓存储为一个点的集合。
hierarchy输出的轮廓层次结构信息,表示为Mat类型的变量。
mode轮廓检测模式,可选值为:
CV_RETR_EXTERNAL:只检测外部轮廓。
CV_RETR_LIST:检测所有轮廓,不建立层次结构。
CV_RETR_CCOMP:检测所有轮廓,建立2层的层次结构。
CV_RETR_TREE:检测所有轮廓,建立完整的层次结构。
method轮廓近似方法,可选值为:
CV_CHAIN_APPROX_NONE:存储所有的轮廓点。
CV_CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线方向上的冗余点。
CV_CHAIN_APPROX_TC89_L1:使用Teesside chain的L1距离。
CV_CHAIN_APPROX_TC89_KCOS:使用Teesside chain的Kosinski距离。
offset可选参数,表示轮廓点坐标的偏移量。
void drawContours(InputOutputArray image, InputArrayOfArrays contours, 
int contourIdx, const Scalar& color, int thickness = 1, int lineType = 8, 
InputArray hierarchy = noArray(), int maxLevel = INT_MAX, 
Point offset = Point() );
参数说明
image输入/输出图像,用于绘制轮廓。
contours输入的轮廓,表示vector<vector<Point>>类型的变量。每个轮廓存储为一个点的集合。
contourIdx要绘制的轮廓的索引,可以是正整数(绘制单个轮廓)或-1(绘制所有轮廓)。
color绘制轮廓的颜色,可以使用RGB格式的颜色值。
thickness可选参数,绘制轮廓的线条粗细,默认值为1。
lineType可选参数,绘制轮廓的线条类型,默认值为8。
hierarchy可选参数,轮廓层次结构信息,表示为Mat类型的变量。
maxLevel可选参数,最大轮廓层次的深度,默认值为INT_MAX。
offset可选参数,轮廓点坐标的偏移量。
Mat src, dst;
int threshold_value = 100;
int threshold_max = 255;
const char* input = "输入";
const char* output = "轮廓";
void contour_Demo(int, void*);
int main()
{
	src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\霍夫圆.png");
	if (!src.data)
	{
		cout << "图片加载出错" << endl;
		return 0;
	}
	namedWindow(output,WINDOW_AUTOSIZE );
	createTrackbar("阈值", output, &threshold_value, threshold_max, contour_Demo);
	contour_Demo(0, 0);
	waitKey();
	return 0;
}
void contour_Demo(int, void*)
{
	Mat gray,outimgae;
	vector<vector<Point>> contour;
	vector<Vec4i> hierachy;//存储层次结构信息
	cvtColor(src, gray, COLOR_BGR2GRAY);
	Canny(gray, outimgae, threshold_value, threshold_value * 2, 3);

	findContours(outimgae, contour, hierachy, RETR_TREE,CHAIN_APPROX_SIMPLE, Point(0, 0));
	dst = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < contour.size(); i++)
	{
		RNG rng(1234);//随机颜色
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(dst, contour, i, color, 1, LINE_AA, hierachy, 0, Point(0, 0));
	}
	imshow(input, src);
	imshow(output, dst);
}

1.2凸包

API:  convexHull

void convexHull(InputArray points, OutputArray hull, 
                bool clockwise = false, bool returnPoints = true);
  • points:输入的点集,可以是Mat类型的变量或vector<Point>类型的变量。
  • hull:输出的凸包,可以是Mat类型的变量或vector<int>类型的变量。凸包是点的索引集合,可以用于在原始点集中获取凸包上的点。
  • clockwise:可选参数,指定是否按顺时针方向输出凸包的点。默认值为false,即按逆时针方向输出凸包的点。
  • returnPoints:可选参数,指定是否将凸包点返回到hull中。如果设置为true,则将凸包点的坐标作为vector<Point>形式存储在hull中;如果设置为false,则将凸包点的索引存储在hull中,类型为vector<int>
Mat src, gray, dst;
int threshold_value = 100;
int threshold_max = 255;
const char* output = "轮廓";
void contour_Demo(int, void*);
int main()
{
	src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\霍夫圆.png");
	if (!src.data)
	{
		cout << "图片加载出错" << endl;
		return 0;
	}
	namedWindow(output, WINDOW_AUTOSIZE);
	blur(src, src, Size(3, 3), Point(-1, -1), BORDER_CONSTANT);
	cvtColor(src, gray, COLOR_BGR2GRAY);

	createTrackbar("阈值", output, &threshold_value, threshold_max, contour_Demo);
	contour_Demo(0, 0);
	waitKey();
	return 0;
}
void contour_Demo(int, void*)
{
	Mat  outimgae;
	vector<vector<Point>> contour;
	vector<Vec4i> hierachy;
	threshold(gray, outimgae, threshold_value, threshold_max, THRESH_BINARY);
	findContours(outimgae, contour, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	vector<vector<Point>> convexhull(contour.size());
	for (size_t i = 0; i < convexhull.size(); i++)
	{
		convexHull(contour[i], convexhull[i], false, true);
	}
	dst = Mat::zeros(src.size(), CV_8UC3);

	for (size_t i = 0; i < contour.size(); i++)
	{
		RNG rng(1234);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(dst, contour, i, color, 1, LINE_AA, hierachy, 0, Point(0, 0));
		drawContours(dst, convexhull, i, color, 1, LINE_AA, Mat(), 0, Point(0, 0));
//这里convexhull的层次为0,因此用Mat()
	}
	imshow(output, dst);
}

1.3轮廓周围绘制矩形框和圆形框

API:  approxPolyDP、boundingRect、minAreaRect、minEnclosingCircle、fitEllipse、

void approxPolyDP(InputArray curve, OutputArray approxCurve, 
                  double epsilon, bool closed);
  • curve:输入的轮廓,可以是一个二维点的向量(std::vector<cv::Point>)或者一个包含轮廓点的矩阵(cv::Mat)。
  • approxCurve:输出的近似多边形的轮廓,与输入轮廓的数据类型相同。
  • epsilon:指定近似精度的参数,是一个正数。较小的值会产生更接近原始轮廓的近似多边形。
  • closed:一个布尔值,指示近似多边形是否封闭。如果为 true,则近似多边形将是封闭的,即首尾相连。
cv::Rect boundingRect(const std::vector<cv::Point>& points);
//得到轮廓周围最小矩形左上交点坐标和右下角点坐标,绘制一个矩形
cv::RotatedRect minAreaRect(const std::vector<cv::Point2f>& points);
//points:输入的点集,可以是一个二维点的向量(std::vector<cv::Point2f>)
//或一个包含点的矩阵(cv::Mat)。
//得到一个旋转的矩形,返回旋转矩形
void minEnclosingCircle(const std::vector<cv::Point2f>& points, 
                        cv::Point2f& center, float& radius);
  • points:输入点集,一个包含二维点的向量(std::vector<cv::Point2f>)。
  • center:输出参数,表示计算得到的圆心位置(cv::Point2f)。
  • radius:输出参数,表示计算得到的圆的半径(float)。
cv::RotatedRect fitEllipse(InputArray points);

fitEllipse 函数对于包含少于5个点的输入点集可能会返回不准确的结果。在使用前,请确保输入的点集足够大,以获得更准确的椭圆拟合结果。

Mat src, gray, dst;
int threshold_value = 120;
int threshold_max = 255;
const char* input = "原图";
RNG rng(1234);
void contour_Demo(int, void*);
int main()
{
	src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\热气球.jpg");
	if (!src.data)
	{
		cout << "图片加载出错" << endl;
		return 0;
	}
	namedWindow(input, WINDOW_AUTOSIZE);

	blur(src, src, Size(3, 3), Point(-1, -1), BORDER_CONSTANT);
	cvtColor(src, gray, COLOR_BGR2GRAY);

	createTrackbar("阈值", input, &threshold_value, threshold_max, contour_Demo);
	contour_Demo(0, 0);
	waitKey();
	return 0;
}
void contour_Demo(int, void*)
{
	Mat  outimgae;
	vector<vector<Point>> contour;
	vector<Vec4i> hierachy;
	threshold(gray, outimgae, threshold_value, threshold_max, THRESH_BINARY);

	findContours(outimgae, contour, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	vector<vector<Point>> contour_ploy(contour.size());
	vector<Rect>ploy_rect(contour.size());
	vector<Point2f>  ccs(contour.size());
	vector<float> randius(contour.size());

	vector<RotatedRect> myllipse(contour.size());
	vector<RotatedRect>myrect(contour.size());
	for (size_t i = 0; i < contour.size(); i++)
	{
		approxPolyDP(Mat(contour[i]), contour_ploy[i], 3, true);
		ploy_rect[i]=boundingRect(contour_ploy[i]);
		minEnclosingCircle(contour_ploy[i], ccs[i], randius[i]);		
		if (contour_ploy[i].size() > 5)
		{
			myllipse[i]=fitEllipse(contour_ploy[i]);
			myrect[i]=minAreaRect(contour_ploy[i]);
		}
	}
	src.copyTo(dst);
	for (size_t i = 0; i < contour.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		rectangle(dst, ploy_rect[i], color, 1, 8);
		circle(dst, ccs[i], randius[i], color, 1, 8);
		if (contour.size() >= 5)
		{
			ellipse(dst, myllipse[i], color, 1, 8);
			Point2f pts[4];
			myrect[i].points(pts);
			for (size_t j = 0; j < 4; j++)
			{
				line(dst, pts[j], pts[(j + 1) %4], color, 1, 8);
			}
		}	
	}
	imshow(input, dst);
}

1.4图像矩

API: mements、contourArea、arcLength

Moments moments(InputArray array, bool binaryImage = false);
  • array:输入的图像或轮廓,可以是一个灰度图像(cv::Mat)或者一个轮廓向量(std::vector<cv::Point>)。
  • binaryImage:可选参数,指示输入数组是否为二进制图像。默认为 false,表示输入为灰度图像。
double contourArea(InputArray contour, bool oriented = false);
  • contour:输入的轮廓,可以是一个点的向量(std::vector<cv::Point>)或一个包含点的矩阵(cv::Mat)。
  • oriented:可选参数,指示是否计算有向面积。默认为 false,表示计算无向面积。
double arcLength(InputArray curve, bool closed);
  • curve:输入的轮廓,可以是一个点的向量(std::vector<cv::Point>)或一个包含点的矩阵(cv::Mat)。
  • closed:指示输入轮廓是否是封闭的参数。为 true,则函数会计算封闭轮廓的周长;
Mat src, gray, dst;
int threshold_value = 73;
int threshold_max = 255;
const char* input = "原图";
RNG rng(1234);
void contour_Demo(int, void*);
int main()
{
	src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\热气球.jpg");
	if (!src.data)
	{
		cout << "图片加载出错" << endl;
		return 0;
	}
	namedWindow(input, WINDOW_AUTOSIZE);

	cvtColor(src, gray, COLOR_BGR2GRAY);
	GaussianBlur(gray, gray, Size(3, 3), 3, BORDER_CONSTANT);

	createTrackbar("阈值", input, &threshold_value, threshold_max, contour_Demo);
	contour_Demo(0, 0);
	waitKey();
	return 0;
}
void contour_Demo(int, void*)
{
	Mat  outimgae;
	vector<vector<Point>> contour;
	vector<Vec4i> hierachy;
	Canny(gray, outimgae, threshold_value, threshold_max, 3,false);
	findContours(outimgae, contour, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	vector<Moments> contour_moments(contour.size());
	vector<Point2f>  ccs(contour.size());
	for (size_t i = 0; i < contour.size(); i++)
	{
		contour_moments[i] = moments(contour[i], false);
		ccs[i] = Point(static_cast<float>(contour_moments[i].m10 / static_cast<float>(contour_moments[i].m00)),
					   static_cast<float>(contour_moments[i].m01 / static_cast<float>(contour_moments[i].m00)));
	}
	src.copyTo(dst);
	Mat src1;
	src1 = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < contour.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		printf("圆心是 %.2f,%.2f\n", ccs[i].x, ccs[i].y);
		printf("轮廓%d 的面积为:%.2f 周长为:%.2f\n", i, contourArea(contour[i]), arcLength(contour[i], true));
		drawContours(dst, contour, i, color,2, 8, hierachy, 0, Point(0, 0));

		circle(dst, ccs[i],2, color, 2, 8);
	}
	imshow(input, dst);
}

1.5点的多边形测试

API: pointPolygonTest

double pointPolygonTest(const cv::InputArray contour, cv::Point2f pt,
                         bool measureDist)
  • contour:表示多边形的轮廓,可以是一个包含多个点的向量或数组。
  • pt:表示要检测的点的坐标,通常为二维平面上的点。
  • measureDist:一个布尔值,用于设置函数是否测量点到多边形的最短距离。

返回值:

  • 返回一个浮点数,表示点与多边形之间的距离或位置关系。如果 measureDist 为 true,则返回值表示点到多边形的最短距离。如果 measureDist 为 false,则返回值的正负和零表示点与多边形的位置关系,如前面所述。

点的多边形测试是通过计算点与多边形之间的位置关系来确定点在多边形内部、外部还是在多边形的边界上。

在代码实现上,你可以按照以下步骤进行点的多边形测试:

  1. 定义一个包含多个顶点的多边形,可以使用向量或数组来表示。
  2. 定义一个要测试的点的坐标。
  3. 调用 pointPolygonTest 函数,传入多边形轮廓和要测试的点。
  4. 根据返回值判断点与多边形之间的位置关系,可以使用条件语句进行判断。
int main()
{
	int r = 100;
	Mat src(4 * r, 4 * r, CV_8UC1);
	vector<Point2f> vect(6);//手动生成一个六边形
	vect[0] = Point((int)r * 1.5,(int) r * 1.5);
	vect[1] = Point((int)r , (int)r * 2);
	vect[2] = Point((int)r * 1.5, (int)r * 2.5);
	vect[3] = Point((int)r * 2.5, (int)r * 2.5);
	vect[4] = Point((int)r * 3, (int)r * 2);
	vect[5] = Point((int)r * 2.5, (int)r * 1.5);
	for (size_t i = 0; i < 6; i++)
	{
		line(src, vect[i], vect[(i + 1) % 6], Scalar(255), 3, 8);
	}
	imshow("六边形", src);

	Mat csrc;
	src.copyTo(csrc);
	vector<vector<Point>> contour;
	vector<Vec4i> hierachy;
	findContours(csrc, contour, hierachy, RETR_TREE,CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat dist_p = Mat::zeros(csrc.size(), CV_32FC1);
	for (size_t row = 0; row < dist_p.rows; row++)
	{
		for (int col = 0; col < dist_p.cols; col++)
		{
			double dist = pointPolygonTest(contour[0], Point2f((float)col, (float)row), true);
			dist_p.at<float>(row, col) = (float)dist;
		}
	}	
	double minValue, maxValue;
	minMaxLoc(dist_p, &minValue, &maxValue, 0, 0);
	Mat outImage = Mat::zeros(src.size(), CV_8UC3);
	for (size_t row = 0; row < outImage.rows; row++)
	{
		for (int col = 0; col < outImage.cols; col++)
		{
			float dist = dist_p.at<float>(row, col);
			if ( dist> 0)
			{
				outImage.at<Vec3b>(row, col)[0] = (int)((1.0 - dist / maxValue) * 255);
			}
			else if (dist < 0)
			{
				outImage.at<Vec3b>(row, col)[1] = (int)(abs((1.0 - dist / minValue) * 255));
			}
			else
			{
				outImage.at<Vec3b>(row, col)[0] = 255;
				outImage.at<Vec3b>(row, col)[1] = 255;
				outImage.at<Vec3b>(row, col)[2] = 255;
			}
		}
	}
	imshow("多边形测试", outImage);
	waitKey();
	return 0;
}

2.角点检测

2.1

2.2Shi-Tomas角点检测

API:

void goodFeaturesToTrack(const cv::Mat& image,            
                         cv::Mat& corners,                
                         int maxCorners,                  
                         double qualityLevel,             
                         double minDistance,               
                         const cv::Mat& mask = cv::noArray(), 
                         int blockSize = 3,               
                         bool useHarrisDetector = false,   
                         double k = 0.04                  
                        );
  • corners:检测到角点的输出量
  • maxCorners:要寻找的角点数目。
  • qualityLevel:角点阈值与最佳角点的关系,又称质量等级,当参数为0.01,表示角点阈值是最佳角点的0.01倍;
  • minDistance:两个角点之间的最小欧式距离
  • mask:掩码矩阵,表示检测角点的区域。
  • blockSize:计算梯度协方差矩阵的尺寸。
  • useHarrisDetector:是否使用Harris角点k: Harris检测角点过程中的常值权重系数。

2.3亚像素级别角点位置优化

API:TermCriteria    cornerSubPix

void cornerSubPix(const cv::Mat& image,        
                  cv::Mat& corners,             
                  cv::Size winSize,             
                  cv::Size zeroZone,            
                  cv::TermCriteria criteria );
  • image:输入图像,必须是CV_8U或者cV_32F的单通道灰度图像。
  • corners:角点坐标,既是输入的角点坐标又是精确后的角点坐标。
  • winSize:搜索窗口尺寸的一半,必须是整数。实际的搜索窗口尺寸比该参数的2倍大1。
  • zeroZone:搜索区域中间死区大小的一半,即不提取像素点的区域,(-1,-1)表示没有死区。
  • criteria:终止角点优化迭代的条件。

TermCriteria是OpenCV库中用于设置迭代终止条件的类。它通常用于在迭代算法中控制停止迭代的条件。

class TermCriteria
{
public:
    int type;       // 终止条件的类型,可以是MAX_ITER、EPS或MAX_ITER + EPS的组合
    int maxCount;   // 最大迭代次数
    double epsilon; // 迭代终止的阈值

    // 构造函数
    TermCriteria(int type, int maxCount, double epsilon);
};

type:终止条件的类型,可以是以下值之一:

  • cv::TermCriteria::COUNT:达到最大迭代次数时终止。
  • cv::TermCriteria::EPS:当迭代过程中的目标函数值变化小于指定的阈值时终止。
  • cv::TermCriteria::COUNT + cv::TermCriteria::EPS:迭代次数达到最大迭代次数,或目标函数值变化小于指定的阈值时终止。

maxCount:最大迭代次数,当迭代次数达到该值时,迭代将停止。

epsilon:迭代终止的阈值,当目标函数值的变化小于该值时,迭代将停止。

TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.01);
cornerSubPix(src_gray, conersSub, winSize, zeroZone, criteria);
//使用

Mat src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\灰原哀.jpg");
Mat src_gray;
const char* tittle = "托马斯角点";

int maxConers = 200;
int maxConersmax = 1000;
double qualityLevel = 0.005;
double minDistance = 0.5;
void Tomas_Demo(int,void*);
int main()
{
	cvtColor(src, src_gray, COLOR_BGR2GRAY);

	namedWindow(tittle, WINDOW_AUTOSIZE);
	createTrackbar("角点数目", tittle, &maxConers, maxConersmax, Tomas_Demo);
	Tomas_Demo(0, 0);
	waitKey();
	return 0;
}
void Tomas_Demo(int,void*)
{
	vector<Point2f> coners;
	goodFeaturesToTrack(src_gray, coners, maxConers, qualityLevel, minDistance, Mat(), 3, false);

	vector<KeyPoint> keyPoints;
	for (size_t i = 0; i < coners.size(); i++)
	{
		KeyPoint keypoint;
		keypoint.pt = coners[i];
		keyPoints.push_back(keypoint);
	}
	drawKeypoints(src, keyPoints, src);
	imshow(tittle, src);

	//亚像素级别角点位置优化
	vector<Point2f> conersSub = coners;
	Size winSize(5, 5);
	Size zeroZone(-1, -1);
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.01);
	cornerSubPix(src_gray, conersSub, winSize, zeroZone, criteria);

	for (size_t i = 0; i < conersSub.size(); i++)
	{
		string str = to_string(i);
		str = "第" + str + "个角点初始坐标:";
		cout << str << coners[i] << "  精细化后坐标:" << conersSub[i] << endl;
	}

}

2.4SIFT特征点检测

API:

int main()
{
	Mat src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\灰原哀.jpg",IMREAD_GRAYSCALE);
	int numFeatures = 1000;
	vector<KeyPoint> keyPoints;
	Ptr<SIFT> detect = SIFT::create(numFeatures);//创建SIFT对象
	//检测特征点
	detect->detect(src, keyPoints, Mat());
	Mat keypoing_img;
	//绘制特征点
	drawKeypoints(src, keyPoints, keypoing_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
	imshow("SIFT KeyPoint", keypoing_img);
	waitKey();
	return 0;
}

2.5积分图计算

int main()
{
	Mat src = imread("C:\\Users\\86133\\Desktop\\opencv图片\\灰原哀.jpg");
	imshow("input", src);
	Mat isum = Mat::zeros(src.rows + 1,src.cols + 1, CV_32FC1);
	Mat isqsum = Mat::zeros(src.rows + 1, src.cols + 1, CV_64FC1);
	integral(src, isum, isqsum);

	Mat iresult;
	normalize(isum, iresult, 0, 255, NORM_MINMAX,CV_8UC1);

	imshow("积分图像", iresult);
	waitKey();
	return 0;
}

2.6FLANN特征匹配

int main()
{
	Mat src1 = imread("C:\\Users\\86133\\Desktop\\opencv图片\\鹤.jpg", IMREAD_GRAYSCALE);
	Mat src2 = imread("C:\\Users\\86133\\Desktop\\opencv图片\\鹤1.png", IMREAD_GRAYSCALE);

	int numFeatures = 400;
	vector<KeyPoint> keyPoints1,keyPoints2;
	Ptr<SIFT> detect = SIFT::create(numFeatures);//创建SIFT对象

	Mat descriptors1, descriptors2;
	detect->detectAndCompute(src1, Mat(), keyPoints1, descriptors1);
	detect->detectAndCompute(src2, Mat(), keyPoints2, descriptors2);

	FlannBasedMatcher matcher;
	vector<DMatch>matches;
	matcher.match(descriptors2, descriptors1, matches);

	double minDist = 1000;
	double maxDist = 0;
	for (size_t i = 0; i < descriptors2.rows; i++)
	{
		double dist = matches[i].distance;
		maxDist = (dist > maxDist ? dist : maxDist);
		minDist = (dist < minDist ? dist : minDist);
	}


	vector<DMatch>goodmatches;
	for (size_t i = 0; i < descriptors2.rows; i++)
	{
		double dist = matches[i].distance;
		if (dist < max(6*minDist, 0.02))
			goodmatches.push_back(matches[i]);
	}
	Mat matchImg;
	drawMatches(src2, keyPoints2, src1, keyPoints1, goodmatches, matchImg,
		Scalar::all(-1),Scalar::all(-1),vector<char>(0),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	imshow("匹配结果", matchImg);
	waitKey();
	return 0;
}

2.6.2平面对象位置识别

API:  findHomography、perspectiveTransform

cv::Mat findHomography(const std::vector<cv::Point2f>& srcPoints,
                       const std::vector<cv::Point2f>& dstPoints,
                       int method = 0,
                       double ransacReprojThreshold = 3,
                       cv::OutputArray mask = noArray(),
                       const int maxIters = 2000,
                       const double confidence = 0.995);
  • srcPoints:原始图像中特征点的坐标。
  • dstPoints:目标图像中特征点的坐标
  • method:计算单应矩阵方法的标志。默认值为0,表示使用标准的线性最小二乘方法。也可以选择cv::RANSAC,表示使用RANSAC算法进行鲁棒拟合。
  • ransacReprojThreshold:重投影的最大误差。
  • mask:掩码矩阵,使用RANSAC算法时表示满足单应矩阵的特征点。
  • maxIters:RANSAC算法迭代的最大次数。
  • confidence:置信区间,取值范围0-1。

返回值:

  • cv::Mat: 返回一个3x3的单应性矩阵,用于将srcPoints中的特征点映射到dstPoints中的特征点。如果无法估计出单应性矩阵,则返回一个空矩阵。
void perspectiveTransform(InputArray src, OutputArray dst, InputArray mtx);
  1. src:输入数组,包含原始的点坐标,类型为InputArray,可以是矩阵或向量的包装器。

  2. dst:输出数组,包含转换后的点坐标,类型为OutputArray,可以是矩阵或向量的包装器。

  3. mtx:透视变换矩阵,类型为InputArray,通常是通过findHomography函数计算得到的单应性矩阵。

需要注意的是,srcdst的维度应当一致,并且它们的类型应当匹配,例如都是cv::Point2fcv::Point3f

vector<Point2f> obj;
vector<Point2f> scene;
for (size_t i = 0; i < goodmatches.size(); i++)
{
	obj.push_back(keyPoints2[goodmatches[i].queryIdx].pt);
	scene.push_back(keyPoints1[goodmatches[i].trainIdx].pt);
}
Mat H = findHomography(obj, scene, RANSAC);//生成透视变换矩阵

vector<Point2f> obj_coners(4);
vector<Point2f> scene_coners(4);
obj_coners[0] = Point(0, 0);
obj_coners[1] = Point(src2.cols, 0);
obj_coners[2] = Point(src2.cols, src2.rows);
obj_coners[3] = Point(0, src2.rows);

perspectiveTransform(obj_coners, scene_coners, H);
line(matchImg, scene_coners[0] + Point2f(src2.cols, 0), scene_coners[1] + Point2f(src2.cols, 0), Scalar(0, 255, 0), 2, 8, 0);
line(matchImg, scene_coners[1] + Point2f(src2.cols, 0), scene_coners[2] + Point2f(src2.cols, 0), Scalar(0, 255, 0), 2, 8, 0);
line(matchImg, scene_coners[2] + Point2f(src2.cols, 0), scene_coners[3] + Point2f(src2.cols, 0), Scalar(0, 255, 0), 2, 8, 0);
line(matchImg, scene_coners[3] + Point2f(src2.cols, 0), scene_coners[0] + Point2f(src2.cols, 0), Scalar(0, 255, 0), 2, 8, 0);

imshow("匹配结果", matchImg);
waitKey();
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值