【包围盒计算】计算某个对象所有子对象的包围盒

版权所有。转载请注明出处: IT_yanghui

     在游戏开发中,很多时候不需要知道对象下的子对象是什么,只想给该对象外部加一个物理碰撞或者Collider,或者在开发中需要动态获取该对象添加Collider,然而给每一个子对象分别加,明显不现实,浪费时间且影响帧率。

     此时我们需要计算该对象所有子对象的包围盒。其实很简单的计算方法,授之于渔。

     计算包围盒,需要拿到该对象下所有Renderer,即Renderer[]。通过Renderer去计算包围盒Bounds以及中心点center :

所有Renderer的bounds通过计算得出一个整体(外部)bounds,所有Renderer的中心点center计算得出整体的中心点,有中心点和包围盒,就OK了。

     修改一下,可以添加到Unity-Component下,给策划使用,更加方便。

     代码如下:看懂了再复制粘贴。

static public class BoundsCalculate
    {
        /// <summary>
        /// 获取模型包围盒
        /// </summary>
        public static Bounds BOUNDS(this Transform model)
        {
            Vector3 oldPos = model.position;
            model.position = Vector3.zero;
            Bounds resultBounds = new Bounds(model.CENTER(), Vector3.zero);
            CalculateBounds(model, ref resultBounds);
            model.position = oldPos;
            Vector3 scalueValue = ScaleValue(model);
            resultBounds.size = new Vector3(resultBounds.size.x / scalueValue.x, resultBounds.size.y / scalueValue.y, resultBounds.size.z / scalueValue.z);
            return resultBounds;
        }

        /// <summary>
        /// 获取模型包围盒的中心点
        /// </summary>
        public static Vector3 CENTER(this Transform model)
        {
            Vector3 result = Vector3.zero;
            int counter = 0;
            CalculateCenter(model, ref result, ref counter);
            if (counter == 0) return result;
            return result / counter;
        }
        
        /// <summary>
        /// 给模型包围盒添加Collider
        /// </summary>
        public static Bounds AddBoundsCollider(this Transform model)
        {
            Bounds bounds = model.BOUNDS();
            BoxCollider collider = model.gameObject.AddComponent<BoxCollider>();
            collider.center = bounds.center;
            collider.size = bounds.size;
            return bounds;
        }

        /// <summary>
        /// 计算模型包围盒
        /// </summary>
        private static void CalculateBounds(Transform model, ref Bounds bounds)
        {
            Renderer[] renders = model.GetComponentsInChildren<Renderer>();
            foreach (Renderer child in renders)
            {
                bounds.Encapsulate(child.bounds);
            }
        }
        
        /// <summary>
        /// 计算模型中心点
        /// </summary>
        private static void CalculateCenter(Transform model, ref Vector3 result, ref int counter)
        {
            Renderer[] renders = model.GetComponentsInChildren<Renderer>();
            foreach (Renderer child in renders)
            {
                result += child.bounds.center;
                counter++;
            }
        }

        /// <summary>
        /// 获取模型Scale值
        /// </summary>
        private static Vector3 ScaleValue(Transform model)
        {
            Vector3 result = model.localScale;
            return CalculateScale(model, ref result);
        }
        
        /// <summary>
        /// 计算模型Scale值
        /// </summary>
        private static Vector3 CalculateScale(Transform model, ref Vector3 value)
        {
            if (model.parent)
            {
                Vector3 scale = model.parent.localScale;
                value = new Vector3(value.x * scale.x, value.y * scale.y, value.z * scale.z);
                CalculateScale(model.parent, ref value);
            }
            return value;
        }
        
    }

 

### 非均匀剪裁的概念 在计算机视觉领域,图像的非均匀剪裁是指按照特定区域或不规则形状对原始图像进行切割的操作。这种操作通常用于提取感兴趣的目标对象或者去除不需要的部分。相比传统的矩形剪裁方式,非均匀剪裁更加灵活,能够适应复杂的场景需求。 --- ### 使用OpenCV实现非均匀剪裁的方法 #### 1. 基于掩码(Mask)的剪裁方法 利用掩码可以精确控制哪些部分保留,哪些部分被移除。具体过程如下: - 创建一个与输入图像大小相同的二值掩码图像。 - 将目标区域标记为白色(255),其余背景区域标记为黑色(0)。 - 利用 `cv2.bitwise_and` 对原图和掩码进行按位运算,从而得到剪裁后的图像。 以下是代码示例: ```python import cv2 import numpy as np # 加载图像 image = cv2.imread('input_image.jpg') # 创建掩码 (假设我们只保留中心圆形区域) mask = np.zeros(image.shape[:2], dtype=np.uint8) center = (image.shape[1]//2, image.shape[0]//2) # 圆心位置 radius = min(center) // 2 # 半径 cv2.circle(mask, center, radius, 255, -1) # 应用掩码 result = cv2.bitwise_and(image, image, mask=mask) # 显示结果 cv2.imshow('Original', image) cv2.imshow('Masked Result', result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这种方法适用于任何复杂形状的剪裁任务[^2]。 --- #### 2. 基于轮廓检测的剪裁 如果已知目标对象的具体边界,则可以通过轮廓检测来定位并剪裁该对象。流程包括以下几个方面: - **预处理**:使用灰度转换、高斯模糊以及 Canny 边缘检测等技术增强特征。 - **查找轮廓**:调用 `cv2.findContours` 获取所有可能的对象轮廓。 - **筛选最大面积轮廓**:找到包围目标的主要轮廓。 - **获取边界框**:通过 `cv2.boundingRect` 或者旋转矩形拟合获得目标范围。 - **剪裁图像**:依据上述坐标截取对应子区域。 下面是一个完整的例子: ```python import cv2 # 导入图片 img = cv2.imread('object_to_crop.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到轮廓 contours, _ = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:] if len(contours) != 0: c = max(contours, key=cv2.contourArea) # 取最大的轮廓 x,y,w,h = cv2.boundingRect(c) # 计算外接矩形 cropped_img = img[y:y+h, x:x+w] # 展示最终成果 cv2.imshow("Cropped Image", cropped_img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 此方案特别适合当需要自动识别某个单独实体的情况时采用。 --- #### 3. 自由多边形剪裁 对于非常规几何形态的需求,还可以借助自由绘制或多边形指定的方式完成定制化的剪裁工作流设计思路如下所示: - 定义一个多边形顶点列表表示所需保持下来的片段; - 构建填充好的 ROI (Region Of Interest ,兴趣区)作为新蒙版层; - 同样运用逻辑组合函数作用至源素材之上即可达成目的. 实例演示脚本如下 : ```python points = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32).reshape((-1,1,2)) roi_mask = np.zeros_like(gray) cv2.fillPoly(roi_mask,[points],color=(255)) cropped_result = cv2.bitwise_and(img,img,mask=roi_mask) ``` 这种方式提供了极大的灵活性去满足个性化应用场合下的特殊要求[^3]. --- ### 总结 以上介绍了三种主流的技术手段来进行计算机视觉中的非均质型态修剪作业——即分别依赖遮罩机制、边缘捕捉算法还有手动设定折线路径这三类途径加以阐述说明其各自特点优劣之处以便读者根据实际项目情况选取最合适的解决方案予以采纳实施[^4]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值