c++ opencv 片段

Opencv 判断点在轮廓中

//8UC1 转 CV_8U
Py_Image_Region.convertTo(Py_Image_Region, CV_8U, 255);
if (Py_Image_Region.at<uchar>(y, x) == 255) 
{  //在区域里  }
else
{  //在区域外  }

**Opencv c++ 灰度图转彩色图 **

//灰度图转彩色图
cv::Mat grayToRGB(const cv::Mat input_img)
{
	//创建一个和灰度图一样大小的0值图
    cv::Mat three_channel = cv::Mat::zeros(input_img.rows, input_img.cols, CV_8UC3);
    std::vector<cv::Mat> channels;
    //得到3张单通道图
    for (int i = 0; i < 3; i++)
        channels.push_back(input_img);
        
    //RGB通道图的合并
    cv::merge(channels, three_channel);
    return three_channel;
}
//  或者
cv::cvtColor(bmp, bmp, cv::COLOR_GRAY2BGR);

Opencv c++ SVM手写字符识别 一共3步

第一步
裁剪图片
//Mat grayImg, blurImg;
//Mat Train_Chars = imread("D:\\InPut_Image\\OCR\\digits.png");
//cvtColor(Train_Chars, grayImg, COLOR_BGR2GRAY);
//char ad[128] = { 0 };
//int  filename = 0, filenum = 0;
//int b = 20;
//int m = grayImg.rows / b;   //原图为1000*2000
//int n = grayImg.cols / b;   //裁剪为5000个20*20的小图块
//for (int i = 0; i < m; i++)
//{
//	int offsetRow = i * b;  //行上的偏移量
//	if (i % 5 == 0 && i != 0)
//	{
//		filename++;
//		filenum = 0;
//	}
//	for (int j = 0; j < n; j++)
//	{
//		int offsetCol = j * b; //列上的偏移量
//		sprintf_s(ad, "D:\\InPut_Image\\OCR\\%d\\%d.jpg", filename, filenum++);
//		//截取20*20的小块
//		Mat tmp;
//		grayImg(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp);
//		imwrite(ad, tmp);
//	}
//}

	//第二步
	vector<string> imgspath0;
	vector<string> imgspath1;
	vector<string> imgspath2;
	getFiles("D:\\InPut_Image\\OCR\\train3\\0", imgspath0);
	getFiles("D:\\InPut_Image\\OCR\\train3\\1", imgspath1);
	getFiles("D:\\InPut_Image\\OCR\\train3\\2", imgspath2);
	Mat Train_Data0, Train_Label0;
	Mat Train_Data1, Train_Label1;
	Mat Train_Data2, Train_Label2;
	for (int i = 0; i < imgspath0.size(); i++)
	{
		Mat img0 = imread(imgspath0[i], 0);
		img0.convertTo(img0, CV_32FC1);
		Train_Data0.push_back(img0.reshape(0, 1));
		Train_Label0.push_back(0);
	
		Mat img1 = imread(imgspath1[i], 0);
		img1.convertTo(img1, CV_32FC1);
		Train_Data1.push_back(img1.reshape(0, 1));
		Train_Label1.push_back(1);
	
		Mat img2 = imread(imgspath2[i], 0);
		img2.convertTo(img2, CV_32FC1);
		Train_Data2.push_back(img2.reshape(0, 1));
		Train_Label2.push_back(2);
	
	}
	Train_Data0.push_back(Train_Data1);
	Train_Data0.push_back(Train_Data2);
	Train_Label0.push_back(Train_Label1);
	Train_Label0.push_back(Train_Label2);
	
	cout << "开始训练" << endl;
	配置SVM训练器参数
	Ptr<ml::SVM>svm = ml::SVM::create();//构造SVN模型
	svm->setType(ml::SVM::C_SVC);
	svm->setKernel(ml::SVM::LINEAR);
	svm->setDegree(0);
	svm->setGamma(1);
	svm->setCoef0(0);
	svm->setC(1);
	svm->setNu(0);
	svm->setP(0);
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 1000, 0.01));
	//训练
	svm->train(Train_Data0, ml::SampleTypes::ROW_SAMPLE, Train_Label0);
	//保存模型
	svm->save("./svm3.yml"); 
	cout << "结束" << endl;
	
	//第三步
	string filename = "./svm3.yml";
	Ptr<ml::SVM> svm = ml::StatModel::load<ml::SVM>(filename);
	vector<string> imgspath0;
	vector<string> imgspath1;
	vector<string> imgspath2;
	getFiles("D:\\InPut_Image\\OCR\\test3\\0", imgspath0);
	getFiles("D:\\InPut_Image\\OCR\\test3\\1", imgspath1);
	getFiles("D:\\InPut_Image\\OCR\\test3\\2", imgspath2);
	for (int i = 0; i < imgspath0.size(); i++)
	{
		Mat img0 = imread(imgspath0[i], 0);
		Mat img1 = imread(imgspath1[i], 0);
		Mat img2 = imread(imgspath2[i], 0);
	
		Mat RoiFloat;//将图像转化成CV_32FC1
		img0.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		float f = svm->predict(RoiFloat);
		cout << f << "  ";
		if (f != 0)
		{
			cout << "" << endl;
		}
		img1.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		f = svm->predict(RoiFloat);
		cout << f << "  ";
		if (f != 1)
		{
			cout << "" << endl;
		}
		img2.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		f = svm->predict(RoiFloat);
		cout << f << endl;
		if (f != 2)
		{
			cout << "" << endl;
		}
	}

Opencv c++ RandomTree 手写字符识别 一共3步

	//第一步 和SVM一样
	//第二步
	vector<string> imgspath0;
	vector<string> imgspath1;
	vector<string> imgspath2;
	getFiles("D:\\InPut_Image\\OCR\\train3\\0", imgspath0);
	getFiles("D:\\InPut_Image\\OCR\\train3\\1", imgspath1);
	getFiles("D:\\InPut_Image\\OCR\\train3\\2", imgspath2);
	Mat Train_Data0, Train_Label0;
	Mat Train_Data1, Train_Label1;
	Mat Train_Data2, Train_Label2;
	for (int i = 0; i < imgspath0.size(); i++)
	{
		Mat img0 = imread(imgspath0[i], 0);
		img0.convertTo(img0, CV_32FC1);
		Train_Data0.push_back(img0.reshape(0, 1));
		Train_Label0.push_back(0);

		Mat img1 = imread(imgspath1[i], 0);
		img1.convertTo(img1, CV_32FC1);
		Train_Data1.push_back(img1.reshape(0, 1));
		Train_Label1.push_back(1);

		Mat img2 = imread(imgspath2[i], 0);
		img2.convertTo(img2, CV_32FC1);
		Train_Data2.push_back(img2.reshape(0, 1));
		Train_Label2.push_back(2);

	}
	Train_Data0.push_back(Train_Data1);
	Train_Data0.push_back(Train_Data2);
	Train_Label0.push_back(Train_Label1);
	Train_Label0.push_back(Train_Label2);
	
	Ptr<ml::RTrees>forest_ = cv::ml::RTrees::create();
	forest_->setMaxDepth(10); //树的最大深度
	forest_->setPriors(cv::Mat());
	forest_->setRegressionAccuracy(0.01); //设置回归精度
	forest_->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 50, 0.01));//终止标准
	//forest_->setMinSampleCount(10); //节点的最小样本数量	样本少默认设置	
	//forest_->setUseSurrogates(false);
	forest_->setMaxCategories(38);
	forest_->setCalculateVarImportance(true); //计算变量的重要性
	forest_->setActiveVarCount(0);//在每个树节点上随机选择的特征子集的大小,用于找到最佳分割。如果将其设置为0,则大小将设置为特征总数的平方根。默认值为0
	Ptr<ml::TrainData>RandomTree = ml::TrainData::create(Train_Data0, ml::ROW_SAMPLE, Train_Label0);
	forest_->train(RandomTree);
	forest_->save("./RandomTree3.yml");

	//=======参数说明============================================================================================================
	
	//在每个树节点上随机选择的特征子集的大小,用于找到最佳分割。如果将其设置为0,则大小将设置为特征总数的平方根。默认值为0。
	forest_->getActiveVarCount();
	//forest_->setActiveVarCount();

	//计算变量的重要性
	forest_->getCalculateVarImportance();
	//forest_->setCalculateVarImportance();

	//如果CVFolds > 1,则算法使用K折交叉验证过程修剪构建的决策树,其中K等于CVFolds。默认值为10。
	forest_->getCVFolds();
	//forest_->setCVFolds();

	//将分类变量的可能值聚集到K <= maxCategories集群中,以找到次优分割。如果训练过程试图进行分割的所有离散变量的值超过maxCategories,
	// 那么精确的最佳子集估计可能需要很长时间,因为算法是指数型的。相反,在这种情况下,许多决策树引擎(包括我们的实现)试图通过将所有
	// 样本l聚类到maxCategories集群(即一些类别合并在一起)来找到次优拆分。聚类只适用于n > max_categories可能值的分类变量的n > 2类分类
	// 问题。在回归和2类分类的情况下,不使用聚类可以有效地找到最优分裂,因此在这些情况下不使用参数。默认值为10。
	forest_->getMaxCategories();
	//forest_->setMaxCategories();

	//树的最大可能深度。即训练算法试图在节点深度小于maxDepth时分割节点。根节点的深度为零。如果满足其他终止条件
	// (请参阅此处的训练过程ml_intro_trees大纲),和 / 或如果树被修剪,则实际深度可能会更小。默认值是INT MAX。
	forest_->getMaxDepth();
	//forest_->setMaxDepth();

	//如果一个节点中的样本数量少于此参数,则该节点将不会被分割。默认值为10。
	forest_->getMinSampleCount();
	//forest_->setMinSampleCount();

	//先验类概率的数组,按类标签值排序。该参数可用于将决策树的首选项调优到某个类。例如,如果您想检测一些罕见的异常事件,
	// 那么训练库可能包含比异常更多的正常案例,因此只要将每个案例都视为正常,就可以获得非常好的分类性能。为了避免这种情况,
	// 可以指定先验,其中人为地增加异常概率(高达0.5甚至更大),因此错误分类的异常的权重变得更大,并且适当地调整树。
	// 你也可以把这个参数看作预测类别的权重,它决定了你给错误分类的相对权重。也就是说,如果第一类的权重为1,第二类的权重为10,
	// 那么在预测第二类时每犯一次错误就相当于在预测第一类时犯了10次错误。默认值为空。
	forest_->getPriors();
	//forest_->setPriors();

	//回归树的终止准则。如果一个节点的估计值与该节点中训练样本的值之间的所有绝对差值小于此参数,
	// 则该节点将不会进一步分裂。默认值为0.01度
	forest_->getRegressionAccuracy();
	//forest_->setRegressionAccuracy();

	//终止条件,指定训练算法何时停止。当训练指定数量的树并将其添加到集合中时,或者当达到足够的精度(以OOB误差测量)时。
	// 一般来说,摩尔树的准确率更高。然而,精度的提高通常会减弱,渐近线会通过一定数量的树。
	// 还要记住,树的数量线性地增加了预测时间。默认值 TermCriteria(TermCriteria::MAX_ITERS + TermCriteria::EPS, 50, 0.1)
	forest_->getTermCriteria();
	//forest_->setTermCriteria();

	//如果为真,那么被修剪过的树枝就会被物理地从树上移除。否则,它们将被保留,
	// 并且有可能从原始未修剪(或修剪较少)的树中获得结果。默认值为true。
	forest_->getTruncatePrunedTree();
	//forest_->setTruncatePrunedTree();

	//如果这是真的,那么修剪将更加严厉。这将使树更紧凑,更能抵抗训练数据噪声,但不太准确。默认值为true。
	forest_->getUse1SERule();
	//forest_->setUse1SERule();

	//如果为真,则将构建代理分割。这些拆分允许处理丢失的数据并正确计算变量的重要性。默认值为false。
	forest_->getUseSurrogates();
	//forest_->setUseSurrogates();

	//===================================================================================================================


	//第三步
	string filename = "./RandomTree3.yml";
	Ptr<ml::RTrees> RandomTree = ml::StatModel::load<ml::RTrees>(filename);
	vector<string> imgspath0;
	vector<string> imgspath1;
	vector<string> imgspath2;
	getFiles("D:\\InPut_Image\\OCR\\test3\\0", imgspath0);
	getFiles("D:\\InPut_Image\\OCR\\test3\\1", imgspath1);
	getFiles("D:\\InPut_Image\\OCR\\test3\\2", imgspath2);
	for (int i = 0; i < imgspath0.size(); i++)
	{
		Mat img0 = imread(imgspath0[i], 0);
		Mat img1 = imread(imgspath1[i], 0);
		Mat img2 = imread(imgspath2[i], 0);
	
		Mat RoiFloat;//将图像转化成CV_32FC1
		img0.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		float f = RandomTree->predict(RoiFloat);
		cout << f << "  ";
		if (f != 0)
		{
			cout << "" << endl;
		}
		img1.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		f = RandomTree->predict(RoiFloat);
		cout << f << "  ";
		if (f != 1)
		{
			cout << "" << endl;
		}
		img2.convertTo(RoiFloat, CV_32FC1);
		RoiFloat = RoiFloat.reshape(0, 1);
		f = RandomTree->predict(RoiFloat);
		cout << f << endl;
		if (f != 2)
		{
			cout << "" << endl;
		}
	}

Opencv c++ 轮廓点的亚像素

	// 参数设置
	Size winSize = Size(1, 1);
	Size zerozone = Size(-1, -1);
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 50, 0.001);
	vector<Point2f> del_contour;
	cornerSubPix(grayImg, del_contour, winSize, zerozone, criteria);

Opencv c++ 点到线段的距离

//点到线段距离
double GetDistance(cv::Point A, cv::Point B) {
	return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
double GetNearest(cv::Point p, cv::Point P1, cv::Point P2) {
	double a = GetDistance(p, P1);
	double b = GetDistance(p, P2);
	double c = GetDistance(P1, P2);
	if (a * a > b * b + c * c)
		return b;
	if (b * b > a * a + c * c)
		return a;
	double l = (a + b + c) * 0.5;
	double s = sqrt(l * (l - a) * (l - b) * (l - c));
	return 2 * s / c;
}

Opencv c++ 判断两线段相交

//判断两线段相交
bool IsIntersect(cv::Point p1, cv::Point p2, cv::Point p3, cv::Point p4)
{
	bool flag = false;
	double d = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x);
	if (d != 0)
	{
		double r = ((p1.y - p3.y) * (p4.x - p3.x) - (p1.x - p3.x) * (p4.y - p3.y)) / d;
		double s = ((p1.y - p3.y) * (p2.x - p1.x) - (p1.x - p3.x) * (p2.y - p1.y)) / d;
		if ((r >= 0) && (r <= 1) && (s >= 0) && (s <= 1))
		{
			flag = true;
		}
	}
	return flag;
}

Opencv c++ 判断线段和区域是否相交

//判断线段和区域是否相交
bool Is_Line_Rect_intersect(vector<cv::Point>L1,cv::Rect r2)
{
	if (IsIntersect(L1[0], L1[1], r2.tl(), cv::Point(r2.x + r2.width, r2.y))) { return true; }
	if (IsIntersect(L1[0], L1[1], r2.tl(), cv::Point(r2.x, r2.y + r2.height))) { return true; }
	if (IsIntersect(L1[0], L1[1], r2.br(), cv::Point(r2.x + r2.width, r2.y))) { return true; }
	if (IsIntersect(L1[0], L1[1], r2.br(), cv::Point(r2.x, r2.y + r2.height))) { return true; }
	return false;
}

Opencv c++ 判断两个区域是否相交

//判断两个区域是否相交
bool Is_Rects_intersect(cv::Rect r1, cv::Rect r2)
{
	int nMaxLeft = 0;
	int nMaxTop = 0;
	int nMinRight = 0;
	int nMinBottom = 0;

	//計算兩矩形可能的相交矩形的邊界  
	nMaxLeft = r1.x >= r2.x ? r1.x : r2.x;
	nMaxTop = r1.y >= r2.y ? r1.y : r2.y;
	nMinRight = (r1.x + r1.width) <= (r2.x + r2.width) ? (r1.x + r1.width) : (r2.x + r2.width);
	nMinBottom = (r1.y + r1.height) <= (r2.y + r2.height) ? (r1.y + r1.height) : (r2.y + r2.height);
	// 判斷是否相交  
	if (nMaxLeft > nMinRight || nMaxTop > nMinBottom)
	{
		return false;
	}
	else
	{
		return true;
	}
}

Opencv c++ 获取图像梯度图

void sobel_amp(Mat& InImage, Mat& DstImage, bool Is_abs = true)
{
	if (InImage.empty()) { return; }
	Mat Dx, Dy;
	cv::Sobel(InImage, Dx, CV_32F, 1, 0);
	if (Is_abs) { cv::convertScaleAbs(Dx, Dx); }
	cv::Sobel(InImage, Dy, CV_32F, 0, 1);
	if (Is_abs) { cv::convertScaleAbs(Dy, Dy); }
	cv::addWeighted(Dx, 0.5, Dy, 0.5, 0, DstImage);
}

Opencv c++ 得到两条线段交点

//得到交点
cv::Point get_point(cv::Point p1, cv::Point p2, cv::Point p3, cv::Point p4)
{

	double ka, kb;
	ka = (double)(p2.y - p1.y) / (double)(p2.x - p1.x); //求出LineA斜率
	kb = (double)(p4.y - p3.y) / (double)(p4.x - p3.x); //求出LineB斜率

	cv::Point crossPoint;
	crossPoint.x = (ka * p1.x - p1.y - kb * p3.x + p3.y) / (ka - kb);
	crossPoint.y = (ka * kb * (p1.x - p3.x) + ka * p3.y - kb * p1.y) / (ka - kb);
	return crossPoint;
}

Opencv c++ 得到半径为R的核,用于腐蚀膨胀

cv::Mat get_circle_kernel(int R)
{
	Mat a = Mat::zeros(Size(R * 2 + 1, R * 2 + 1), CV_8UC1);
	circle(a, cv::Point(R, R), R, Scalar(1), -1);
	return a;
}

**Opencv c++ **

cv::Point get_point(cv::Point p1, cv::Point p2, cv::Point p3, cv::Point p4)
{

	double ka, kb;
	ka = (double)(p2.y - p1.y) / (double)(p2.x - p1.x); //求出LineA斜率
	kb = (double)(p4.y - p3.y) / (double)(p4.x - p3.x); //求出LineB斜率

	cv::Point crossPoint;
	crossPoint.x = (ka * p1.x - p1.y - kb * p3.x + p3.y) / (ka - kb);
	crossPoint.y = (ka * kb * (p1.x - p3.x) + ka * p3.y - kb * p1.y) / (ka - kb);
	return crossPoint;
}

**Opencv c++ 返回指定形状(矩形、椭圆、十字)和尺寸 核 **

cv::Mat kernel= getStructuringElement(MORPH_RECT,Size(3,3));

**Opencv c++ **


**Opencv c++ 图像压缩 cv::imencode **

Mat img = imread("D:\1.bmp", 0);
string strtype = ".jpg";
std::vector<uchar> vecImg;
std::vector<int> vecCompression_params(2);
//
vecCompression_params[0] = cv::ImwriteFlags::IMWRITE_JPEG_QUALITY;
vecCompression_params[1] = 60;
cv::imencode(strtype, img, vecImg, vecCompression_params);

Opencv c++ 创建空间坐标系

/// <summary>
/// 创建空间坐标系
/// </summary>
/// <param name="coord"></param>
/// <param name="angle"></param>
/// <param name="scale"></param>
void Create_Mat2D(Point2f coord,double angle,double scale)
{
	Mat M = getRotationMatrix2D(Point2f(0, 0), angle, scale);
	M.convertTo(M, CV_32F);
	M.at<float>(0, 2) = coord.x;
	M.at<float>(1, 2) = coord.y;
	M.convertTo(M, CV_64FC1);

//空间坐标系中的点 转 到图片上的对应点
	vector<Point2f> srcVec;
	vector<Point2f> dstVec;
	srcVec.push_back(Point2f(300, 0));
	cv::transform(srcVec, dstVec, M);
}

Opencv c++ 获取两线段角度

/// <summary>
///  获取两线段角度
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <param name="p4"></param>
/// <param name="angle"> -180°到 180°  逆时针为+   顺时针为-</param>
void angle_LL(Point2f p1, Point2f p2, Point2f p3, Point2f p4, double& angle)
{
	double x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
	double a1 = -(y2 - y1), b1 = x2 - x1, c1 = (y2 - y1) * x1 - (x2 - x1) * y1; // 一般式:a1x+b1y1+c1=0
	double offset_x = p1.x - p3.x;	//将第二条线的起始点移动到第一条
	double offset_y = p1.y - p3.y;
	double x3 = p3.x + offset_x, y3 = p3.y + offset_y, x4 = p4.x + offset_x, y4 = p4.y + offset_y;

	angle = atan2(x2 - x1, y2 - y1) - atan2(x4 - x1, y4 - y1);
	if (angle > CV_PI)
		angle -= 2 * CV_PI;
	if (angle < -CV_PI)
		angle += 2 * CV_PI;

	angle = angle * 180.0 / CV_PI;;
}

**Opencv c++ 得到线段与水平线X的角度 **

/// <summary>
/// 得到线段与水平线X的角度 
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns> -180°到 180°  逆时针为+   顺时针为- </returns>
void angle_lx(Point2f p1, Point2f p2, double& angle)
{
	double x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
	double a1 = -(y2 - y1), b1 = x2 - x1, c1 = (y2 - y1) * x1 - (x2 - x1) * y1; // 一般式:a1x+b1y1+c1=0
	double x3 = p1.x, y3 = p1.y, x4 = p1.x + 100, y4 = p1.y;
	double a2 = -(y4 - y3), b2 = x4 - x3, c2 = (y4 - y3) * x3 - (x4 - x3) * y3; // 一般式:a2x+b2y1+c2=0
	bool IfIntersection = false;                                                             // 判断结果
	double x0 = 0, y0 = 0;                                                      // 交点
	//double angle = 0;                                                           // 夹角
	// 判断相交
	if (b1 == 0 && b2 != 0) // l1垂直于x轴,l2倾斜于x轴
		IfIntersection = true;
	else if (b1 != 0 && b2 == 0) // l1倾斜于x轴,l2垂直于x轴
		IfIntersection = true;
	else if (b1 != 0 && b2 != 0 && a1 / b1 != a2 / b2)
		IfIntersection = true;
	if (IfIntersection)
	{
		angle = -atan2((y2 - y1), (x2 - x1)) * 180 / CV_PI;
	}
}

Opencv c++ 获取两线段交点

/// <summary>
/// 获取两线段交点
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <param name="p4"></param>
/// <param name="intersection"></param>
/// <param name="IfIntersection"></param>
void intersection_LL(Point2f p1, Point2f p2, Point2f p3, Point2f p4, Point2f& intersection, bool& IfIntersection)
{
	double x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
	double a1 = -(y2 - y1), b1 = x2 - x1, c1 = (y2 - y1) * x1 - (x2 - x1) * y1; // 一般式:a1x+b1y1+c1=0
	double x3 = p3.x, y3 = p3.y, x4 = p4.x, y4 = p4.y;
	double a2 = -(y4 - y3), b2 = x4 - x3, c2 = (y4 - y3) * x3 - (x4 - x3) * y3; // 一般式:a2x+b2y1+c2=0
	IfIntersection = false;                                                             // 判断结果
	double x0 = 0, y0 = 0;                                                      // 交点
	// 判断相交
	if (b1 == 0 && b2 != 0) // l1垂直于x轴,l2倾斜于x轴
		IfIntersection = true;
	else if (b1 != 0 && b2 == 0) // l1倾斜于x轴,l2垂直于x轴
		IfIntersection = true;
	else if (b1 != 0 && b2 != 0 && a1 / b1 != a2 / b2)
		IfIntersection = true;
	if (IfIntersection)
	{
		//计算交点
		x0 = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
		y0 = (a1 * c2 - a2 * c1) / (a2 * b1 - a1 * b2);
	}
	intersection = Point2f(x0, y0);
}

**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


**Opencv c++ **


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值