点是否位于区域内的位置判断


前言

目的:

本文主要记录如何判断点是否位于ROI区域内部。

常见判断方法:

面积和判断法;
夹角和判断法;
凸多边形判断法;
引射线法;

各判断方法适用性:

面积和判断法、夹角和判断法:
【优势】实现较为简单,效率高,不需要循环所有的roi的边,主要参与计算的是多边形的几个顶点;
【劣势】需要多边形是规则的直边,对弧形的多边形则无法处理;
凸多边形判断法:
【优势】实现不难,就是逆时针判断目标点是否一直在各个相邻点形成的边的左侧;
【劣势】需要循环所有的roi的边;另外对于凹多边形,需要进行补边成凸多边形;
引射线法:
【优势】对roi的形状没有任何限制;
【劣势】需要循环所有的roi的边;

小结:

因为我自己的roi是有弧度的,因此选择引射线法,本文也仅对该方法进行程序实现。

一、“引射线法”是什么?

定义:

从任意位置画一条到目标点的水平线,计算该水平线进出平面边界的次数:
如果两边的进出次数都是偶数(包括0),则点在平面外;
如果是奇数,则点在平面内。点正好落在定点或边界时会出现特殊的判断。
——————————————————————————————————————————————————————
在实际使用时,只需要判断一侧的进出次数即可。

在这里插入图片描述

二、实现

1.方法一

设置无穷远处的一个点(横坐标无穷大——大于所有的此时的点即可,纵坐标与目标点相同),作为目标点与远处点的线段端点,查看该线段有roi邻居点连成的线段之间是否相交:

struct Point{
    int Point_id;
    double x,y;
};
//判断两个线段是否交点
double determinant(double v1, double v2, double v3, double v4){
   return (v1*v3-v2*v4);
}

bool intersect(Point aa, Point bb, Point cc, Point dd){
   double delta = determinant(bb.x-aa.x, cc.x-dd.x, bb.y-aa.y, cc.y-dd.y);
   if ( delta<=(1e-6) && delta>=-(1e-6) ){// delta=0,表示两线段重合或平行
       return false;
   }
   double namenda = determinant(cc.x-aa.x, cc.x-dd.x, cc.y-aa.y, cc.y-dd.y) / delta;
   if ( namenda>1 || namenda<0 ){
       return false;
   }
   double miu = determinant(bb.x-aa.x, cc.x-aa.x, bb.y-aa.y, cc.y-aa.y) / delta;
   if ( miu>1 || miu<0 ){
       return false;
   }
   return true;
}
int main(){
	int m=Polygon.size();//roi边界点数组,假设为eigen库函数
	bool flag=false;
	//目标点和无穷远构成的线段的两个端点
    point_object.x=1;
    point_object.y=10;
    point_long.x=INT_MAX/2000;
    point_long.y=10;
    //求解横纵坐标最值
    x_map_max=Polygon.row(0).maxCoeff();
    x_map_min=Polygon.row(0).minCoeff();
    y_map_max=Polygon.row(1).maxCoeff();
    y_map_min=Polygon.row(1).minCoeff();    
	//判断目标点是否在大的roi区域内部
	if(point_object.x > x_map_max||point_object.x <x_map_min||point_object.y >y_map_max||point_object.y<y_map_min){
            cout<<"点不在大的区域内部"<<endl;
    }
    else{
		for(int i=0,j=m-1; i<m; j=i,i++){
		    //目标点需在两个坐标点纵坐标之间,提高判断效率;
	    	if( Polygon(1,i)<=point_object.y && point_object.y<Polygon(1,j) || Polygon(1,j)<=point_object.y&& point_object.y<Polygon(1,i) ){
	            //roi的邻居点构成的线段的两个端点
	            point_A.x=Polygon(0,i);
	            point_A.y=Polygon(1,i);
	            point_B.x=Polygon(0,j);
	            point_B.y=Polygon(1,j);
	            //判断两条线段是否相交
	            if(intersect(point_object,point_long,point_A,point_B)){
	                flag=!flag;
	            }//if
	        }//if
	    }//for
	}
	if(flag){
		cout<<"点在区域内部..."<<endl;
	}
	else{
		cout<<"点不在区域内部..."<<endl;
	}
}

2.方法二

求取与目标点相同的y在roi相邻点的线段L1上的横坐标x,若目标点的x大于上述x,则交点数+1;此方法的思想本质上与方法一相同,只是不需要设置无穷远处的点作为目标点;

在这里插入图片描述
只判断一侧的交点数,且只判断y2<y<y1时的x坐标关系。

//部分核心函数
	
	//roi的极值
	double x_inside_map_max=inside_map.row(0).maxCoeff();
    double x_inside_map_min=inside_map.row(0).minCoeff();
    double y_inside_map_max=inside_map.row(1).maxCoeff();
    double y_inside_map_min=inside_map.row(1).minCoeff();
	bool flag=false;
    if(point_object[b].x > x_inside_map_max||point_object[b].x <x_inside_map_min||point_object[b].y >y_inside_map_max||point_object[b].y<y_inside_map_min){
            cout<<"点不在inside_map的区域内部..."<<endl;
    }else{
         for(int i=0,j=m-1; i<m; j=i,i++){
         	double slope=0;
	        if(inside_map(1,j)!=inside_map(1,i)){                     //确保分母非0 
                slope =(inside_map(0,j)-inside_map(0,i))/(inside_map(1,j)-inside_map(1,i));
            }
            else{
                slope =(inside_map(0,j)-inside_map(0,i))/(0.00001);
            }
            
            bool cond1 = (inside_map(1,j)<point_object[b].y && point_object[b].y<=inside_map(1,i) ) || (inside_map(1,i)<point_object[b].y && point_object[b].y<=inside_map(1,j)); //y在两个点之间
            bool cond2 = (inside_map(0,j)<=point_object[b].x)||(inside_map(0,i)<=point_object[b].x); //x在右侧
            if( cond1 && cond2 ){
            	bool cond3 = ( point_object[b].x > (inside_map(0,i) + slope * (point_object[b].y-inside_map(1,i))) );      //两点式直线方程
                if(cond3){
                        flag=!flag; //有交点
                }//if
             }//if
         }//for
         if(flag){//交点数标志位变化,证明经过奇次变换,有奇数个交点,点在内部;
            cout<<setprecision(15)<<"点在inside_map区域内部..."<<endl;
         }else{
            cout<<"点不在inside_map区域内部..."<<endl;
         }
         

总结

以上都是单边射线与多边形横向存在交点次数的判断实现。
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要计算圆形区域内的像素均值和方差,你需要按照以下步骤进行: 1. 读取 DICOM 图像并解析像素数据。你可以使用类似 DCMTK 或 ITK 等 DICOM 库来完成这个任务。 2. 定义圆形区域。你可以使用一个圆形的中心坐标和半径来表示它。 3. 遍历圆形区域内的像素。你可以使用一个循环来遍历所有位于圆形区域内的像素,并将它们的值加起来。 4. 计算像素均值。将遍历得到的像素值总和除以圆形区域内的像素数,即可得到像素均值。 5. 计算像素方差。对于每个像素,将其值减去均值并平方,然后将所有差的平方加起来并除以像素数,即可得到像素方差。 下面是一个示例代码,它假设圆形区域的中心坐标为 (x0, y0),半径为 r,图像数据存储在名为 data 的一维数组中,其大小为 width*height: ```cpp // 定义圆形区域 int x0 = 100; // 圆心 x 坐标 int y0 = 100; // 圆心 y 坐标 int r = 50; // 半径 // 遍历圆形区域内的像素并计算均值和方差 double sum = 0; double sum2 = 0; int count = 0; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if ((x-x0)*(x-x0) + (y-y0)*(y-y0) <= r*r) { // 判断像素是否在圆形区域内 double value = data[y*width + x]; sum += value; sum2 += value*value; ++count; } } } // 计算均值和方差 double mean = sum / count; double variance = (sum2 - 2*mean*sum + count*mean*mean) / count; ``` 需要注意的是,这个示例代码假设图像数据是以行优先的方式存储的,如果是列优先,则需要调整计算像素值的方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值