opencv截取旋转矩形区域图像(C#)

本文介绍了一种在OpenCV中截取旋转矩形区域的方法,通过向量空间变换,避免了整体图像旋转造成的资源浪费。适用于工程中特定图形的精确提取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:最近在工程中需要用到截取RotatedRect中的图形,保存为Mat做后续处理。发现opencv文档中没有这个api,最开始想到的方案是将整张图片进行相应的旋转,然后再从中截取正矩形,但是我们要获取的是部分区域,将整张图片进行旋转会造成很多的资源浪费。所以需要自行实现一个旋转矩形的方案。

实现方法

原理是利用向量空间变换,如图
在这里插入图片描述
通过

Point2f[] points=rotatedRect.Points();

可获取RotatedRect四个端点的坐标。先选定一个点为输出Mat左上端点,这里采取的是离原图左上角最近的端点(即x2+y2最小)。然后再选取相邻的2个端点,作向量Vx及Vy。这里可以根据需求来选定Vx和Vy的方向,比如要求输出Mat的Width大于Height,那就选定长的一边为Vx。这里直接选定左上端点到顺时针方向的端点的向量为Vx,即如图所示。
在选定好Vx和Vy后,进行向量空间的变换。设在输出的Mat中任一一个坐标点(i,j),对应在输出Mat中的任一坐标点(x,y)。设左上端点坐标(x0,y0) (即图中点2),
满足:
设目标RotatedRect长宽为width height,有
在这里插入图片描述

然后做一个二重循环,将j从0循环到height,i从0循环到width,就可以得到输出Mat所有像素的信息。
下面为一个截取BGR类型的Mat的RotatedRect的代码

///<Summary>
///利用向量运算截取一个RotatedRect区域
///</Summary>
///<param name="img">类型为CV_U8C3的Mat</param>
///<param name="rotatedRect">RotatedRect</param>
public static Mat sliceRotetedImg8UC3(Mat img,RotatedRect rotatedRect){
    // Rect bounding=rotatedRect.BoundingRect();
    Point2f[] points=rotatedRect.Points();
    int topLeftIndex=0;
    double topLeftR=points[0].X*points[0].X+points[0].Y*points[0].Y;
    for(int i=1;i<4;i++){
        double r=points[i].X*points[i].X+points[i].Y*points[i].Y;
        if(r<topLeftR){
            topLeftIndex=i;
            topLeftR=r;
        }
    }
    double x1=points[(topLeftIndex+1)%4].X-points[topLeftIndex].X,y1=points[(topLeftIndex+1)%4].Y-points[topLeftIndex].Y;
    double x2=points[(topLeftIndex+3)%4].X-points[topLeftIndex].X,y2=points[(topLeftIndex+3)%4].Y-points[topLeftIndex].Y;
    double vX1=x1,vY1=y1,vX2=x2,vY2=y2;
    int width=(int)Math.Sqrt(vX1*vX1+vY1*vY1),height=(int)Math.Sqrt(vX2*vX2+vY2*vY2);
    Mat ret=new Mat(new Size(width,height),MatType.CV_8UC3);
    // Console.WriteLine($"width={width},height={height}");
    var indexer1=img.GetGenericIndexer<Vec3b>();
    var indexer2=ret.GetGenericIndexer<Vec3b>();
    for(int j=0;j<ret.Height;j++){
        for(int i=0;i<ret.Width;i++){
            double kx=(double)i/width,ky=(double)j/height;
            int x=(int)(points[topLeftIndex].X+kx*vX1+ky*vX2),y=(int)(points[topLeftIndex].Y+kx*vY1+ky*vY2);
            indexer2[j,i]=indexer1[y,x];
        }
    }
    return ret;
}
### 使用 C#OpenCV 实现图像矩形区域截取 为了使用 C#OpenCV 来实现从图像截取矩形区域的功能,可以通过 `OpenCvSharp` 库完成此操作。以下是具体的方法: #### 加载库和初始化环境 确保已经安装了 `OpenCvSharp4` 及其依赖项。 ```csharp using Cv = OpenCvSharp; ``` #### 读取原始图像 通过 `Cv2.ImRead()` 方法加载要处理的图片文件。 ```csharp string imagePath = "path_to_your_image.jpg"; var image = Cv2.ImRead(imagePath); if (image.Empty()) { Console.WriteLine("Could not open or find the image!"); } else { Cv2.ImShow("Original Image", image); Cv2.WaitKey(0); // Wait for a key press indefinitely. } ``` #### 定义矩形框的位置参数 设定想要裁剪出来的矩形位置及其大小,即左上角顶点坐标 `(x,y)` 和宽高 `(width,height)`。 ```csharp int x = 50, y = 60; // Top-left corner coordinates of ROI rectangle int width = 150, height = 200; // Width and Height of ROI rectangle ``` #### 裁剪矩形区域图像数据 利用数组切片的方式获取感兴趣区(Region Of Interest, ROI),并将其赋值给新变量用于后续显示或保存。 ```csharp Mat roiImage = image.SubMat(new Rect(x, y, width, height)); // 或者更直观的形式: // Mat roiImage = image.Range(y, y + height).Range(x, x + width); Cv2.ImShow("ROI Cropped Image", roiImage); Cv2.WaitKey(0); ``` #### 将结果另存为新文件 最后一步就是把得到的结果存储到磁盘上的另一个路径下。 ```csharp string outputPath = "cropped_output_image.png"; roiImage.Save(outputPath); Console.WriteLine($"Saved cropped image to {outputPath}"); ``` 以上代码片段展示了如何基于指定坐标的矩形边界,在一幅输入图象里提取子图,并展示出来以及保存至本地硬盘[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值