(纯粹原创,转载请注明本文章地址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;
处理前:
处理后:
(完)