利用椭圆方程做一个椭圆的Roi(附源码/例子)

(纯粹原创,转载请注明本文章地址https://blog.csdn.net/smalbig/article/details/104561586)
1.椭圆Roi的由来
使用opencv开发在计算机视觉,有时需要获取一个椭圆形的Roi。比如一个倾斜的圆,在不想或由于现场条件限制无法进行透视矫正时,需要使用椭圆形的Roi对区域内进行各种操作,如二值化,边缘检测,轮廓分析等等。以此,来提高检测速度和精度。

Roi,在我看来就是一个有一定几何形状的点集合,即vector< Point2i > Roi。对图像的操作归根结底就是对像素的操作,图像上像素的位置使用二维点表示的,所以只要获取了感兴趣的二维点,就能对图像进行相应的操作。所以,椭圆Roi,就是获得一个椭圆内所有点的坐标即可。
2.椭圆方程
P是椭圆上任意一点,P(x , y);
F1和F2是椭圆的两个焦点;
c是椭圆的焦距,即焦点到中心的距离;
a是椭圆长轴的大小,即中心到椭圆最远的点;
b是椭圆短轴的大小,即中心点到椭圆最近的点;
|PF1| 和 |PF2| 是 P(x , y)到F1和F2的距离;
椭圆满足:|PF1| + |PF2| = 2a; b² + c² = a²,换言之,只要一个点P(x,y)满足以上式子,它就是椭圆里的点,把所有这样的点存到容器里,就得到一个椭圆Roi。

3.伪代码如图(下载后向右旋转90°即可)
在这里插入图片描述
3.C++实现代码如下:

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;

vector<Point2i>GetEllipoints(int a, int b, Point2i center) {
	a = 300; b = 200; center = Point2i(400, 300);
	vector<Point2i> Ellipoints;
	int c = sqrt(pow((a), 2) - pow((b), 2));
	Point2i F1 = Point2i(center.x - c,center.y);
	Point2i F2 = Point2i(center.x + c, center.y);
	for (int i = center.x - a; i < center.x + a; i++) {
		for (int j = center.y - b; j < center.y + b; j++) {
			int PF1 = sqrt(pow((i - F1.x), 2) + pow((j - F1.y), 2));
			int PF2 = sqrt(pow((i - F2.x), 2) + pow((j - F2.y), 2));
			if (((PF1 + PF2) < 2 * a)| ((PF1 + PF2) < 2 * a)) {
				Ellipoints.push_back(Point2i(i, j));
			}
		}
	}
	return Ellipoints;
}

int main()
{
	vector<Point2i> ellipoints = GetEllipoints(400, 200, Point2i(400,200));
	Mat M(600, 800, CV_8UC1);
	for (int i = 0; i < ellipoints.size(); i++) {
		circle(M, ellipoints.at(i), 1, Scalar(255));
	}
	imshow("elli", M);
	waitKey(0);
    return 0;
}

4.opencv C++例子如下
4.1本例做了一个椭圆区域内的图像取反操作

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;

vector<Point2i>GetEllipoints(int a, int b, Point2i center) {
	//a = 300; b = 200; center = Point2i(400, 300);
	vector<Point2i> Ellipoints;
	int c = sqrt(pow((a), 2) - pow((b), 2));
	Point2i F1 = Point2i(center.x - c,center.y);
	Point2i F2 = Point2i(center.x + c, center.y);
	for (int i = center.x - a; i < center.x + a; i++) {
		for (int j = center.y - b; j < center.y + b; j++) {
			int PF1 = sqrt(pow((i - F1.x), 2) + pow((j - F1.y), 2));
			int PF2 = sqrt(pow((i - F2.x), 2) + pow((j - F2.y), 2));
			if (((PF1 + PF2) < 2 * a)| ((PF1 + PF2) < 2 * a)) {
				Ellipoints.push_back(Point2i(i, j));
			}
		}
	}
	return Ellipoints;
}

int main()
{
	vector<Point2i> ellipoints = GetEllipoints(400, 200, Point2i(700,400));
	Mat M(600, 800, CV_8UC1);	
	Mat explode = imread("C:\\Users\\cdf5f6ce\\Desktop\\explode.png");

	int x, y;
	for (int i = 0; i < ellipoints.size(); i++) {
		x = ellipoints.at(i).x; y = ellipoints.at(i).y;
		explode.at<Vec3b>(y, x)[0] = 255 - explode.at<Vec3b>(y, x)[0];
		explode.at<Vec3b>(y, x)[1] = 255 - explode.at<Vec3b>(y, x)[1];
		explode.at<Vec3b>(y, x)[2] = 255 - explode.at<Vec3b>(y, x)[2];

	}
	imshow("explode", explode);
	waitKey(0);
    return 0;
}

效果如图:
处理前:
在这里插入图片描述
处理后:
在这里插入图片描述
4.2本例在椭圆Roi内进行Canny边缘检测

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;

vector<Point2i>GetEllipoints(int a, int b, Point2i center, vector<Point2i> &edgePoints) {

	vector<Point2i> Ellipoints;
	int c = sqrt(pow((a), 2) - pow((b), 2));
	Point2i F1 = Point2i(center.x - c,center.y);
	Point2i F2 = Point2i(center.x + c, center.y);
	for (int i = center.x - a; i < center.x + a; i++) {
		for (int j = center.y - b; j < center.y + b; j++) {
			int PF1 = sqrt(pow((i - F1.x), 2) + pow((j - F1.y), 2));
			int PF2 = sqrt(pow((i - F2.x), 2) + pow((j - F2.y), 2));
			if (((PF1 + PF2) < 2 * a-2)) {
				Ellipoints.push_back(Point2i(i, j));
			}
			if (((PF1 + PF2) == 2 * a )   | ((PF1 + PF2) == 2 * a-1)| ((PF1 + PF2) == 2 * a+1)
				|((PF1 + PF2) == 2 * a+2) | ((PF1 + PF2) == 2 * a+3)| ((PF1 + PF2) == 2 * a-2)
				| ((PF1 + PF2) == 2 * a-3)| ((PF1 + PF2) == 2 * a-4)| ((PF1 + PF2) == 2 * a-5)
				| ((PF1 + PF2) == 2 * a+4)| ((PF1 + PF2) == 2 * a+5)
				| ((PF1 + PF2) == 2 * a-6)| ((PF1 + PF2) == 2 * a-7)
				| ((PF1 + PF2) == 2 * a+6)| ((PF1 + PF2) == 2 * a+7)) {
				edgePoints.push_back(Point2i(i, j));
			}
		}
	}
	return Ellipoints;
}

int main()
{
	vector<Point2i> edgePoints;
	vector<Point2i> ellipoints = GetEllipoints(400, 200, Point2i(700,400), edgePoints);
	Mat M(600, 800, CV_8UC1);	
	Mat explode = imread("C:\\Users\\cdf5f6ce\\Desktop\\explode.png");

	int x, y;

	vector<Point2i>CannyRoi;
	Mat baseimg = Mat(explode.size(), CV_8UC1);
	for (int i = 0; i < ellipoints.size(); i++) {
		x = ellipoints.at(i).x; y = ellipoints.at(i).y;
		int B = explode.at<Vec3b>(y, x)[0];
		int G = explode.at<Vec3b>(y, x)[1];
		int R = explode.at<Vec3b>(y, x)[2];
		//explode.at<Vec3b>(y, x)[0] = 255 - explode.at<Vec3b>(y, x)[0];
		if (B < 100 & G > 100 & R > 100) {
			explode.at<Vec3b>(y, x)[0] = 255;

			//explode.at<Vec3b>(y, x)[1] = 255 - explode.at<Vec3b>(y, x)[1];
			//explode.at<Vec3b>(y, x)[2] = 255 - explode.at<Vec3b>(y, x)[2];
			explode.at<Vec3b>(y, x)[1] = 255;
			explode.at<Vec3b>(y, x)[2] = 255;
			baseimg.at<uchar>(y, x) = 255;
		}
		else {
			explode.at<Vec3b>(y, x)[0] = 0;
			baseimg.at<uchar>(y, x) = 0;


			//explode.at<Vec3b>(y, x)[1] = 255 - explode.at<Vec3b>(y, x)[1];
			//explode.at<Vec3b>(y, x)[2] = 255 - explode.at<Vec3b>(y, x)[2];
			explode.at<Vec3b>(y, x)[1] = 0;
			explode.at<Vec3b>(y, x)[2] = 0;

		}

	}
	Canny(baseimg, explode, 80, 255);
	threshold(explode, explode, 80, 255, THRESH_BINARY);
	//try {
		for (int i = 0; i < edgePoints.size(); i++) {
			explode.at<uchar>(edgePoints.at(i).y, edgePoints.at(i).x) = 0;

		//explode.at<Vec3b>(edgePoints.at(i).y, edgePoints.at(i).x)[0];
		//explode.at<Vec3b>(edgePoints.at(i).y, edgePoints.at(i).x)[1] = 0;
		//explode.at<Vec3b>(edgePoints.at(i).y, edgePoints.at(i).x)[2] = 0;

		}
	//}
	//catch(cv::Exception){
	//
	//}

	//threshold(CannyRoi, CannyRoi, 26, 255,THRESH_BINARY);
	//imshow("baseimg", baseimg);

	imshow("explode", explode);
	waitKey(0);
    return 0;

处理前:
在这里插入图片描述
处理后:
在这里插入图片描述
(完)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值