OpencvSharp基础学习5 | 图像变换(ROI截取)

这篇具有很好参考价值的文章主要介绍了OpencvSharp基础学习5 | 图像变换(ROI截取)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、本章学习以下几个算子

1.MinAreaRect:最小外接矩形
2.CopyTo: 复制图片(掩膜复制法)
3.GetRotationMatrix2D:计算旋转矩阵
4.WarpAffine:图像变换
5.GetRectSubPix:裁剪图像

二、算子介绍

1.MinAreaRect:最小外接矩形

函数解析:

该函数计算并返回指定点集的最小区域边界斜矩形。

函数原型:
RotatedRect minAreaRect(InputArray points)
函数参数:
points:输入信息,可以为包含点的容器(vector)或是Mat。
函数返回值:

RotatedRect类型,返回包覆输入信息的最小斜矩形,参数有最小外接矩形的中心center,(宽度,高度),旋转角度等

使用注意事项:

(1). 旋转角度θ是水平轴(x轴)逆时针旋转,与碰到的矩形的第一条边的夹角。并且这个边的边长是width,另一条边边长是height。也就是说,在这里,width与height不是按照长短来定义的。
(2). 在opencv中,坐标系原点在左上角,相对于x轴,逆时针旋转角度为负,顺时针旋转角度为正。所以,θ∈(-90度,0]。
(3). 获取的4个顶点中顺序为顺时针,第一个点位为y值最小的点。

2.CopyTo: 复制图片

函数解析:

把一张图片的整张或掩膜区域像素拷贝到另一张图片上。

函数原型:
void copyTo( OutputArray m ); //拷贝整张图(被拷贝的图)
void copyTo( OutputArray m, InputArray mask ); //拷贝掩膜图(被拷贝的图和掩膜图作与运算)
函数参数:
m:输出图像,Mat。
mask:输入掩膜图
函数返回值:

使用注意事项:

(1). 格式为:被拷贝图像.copyTo(输出图像,掩膜图)。
(2). 被拷贝图像和掩膜图大小必须一致,如果已知掩膜图比被拷贝图像大,可以裁剪掉不需要的部分,反之则新建一个新掩膜图用0像素填充,裁剪ROI区域(大小和老掩膜图一致),然后把老掩膜图拷贝到新掩膜图的ROI中。
(3).ROI拷贝:在原图上截取指定区域的ROI,大小和被拷贝图一致,注意此处截取使用关联截取,C++有两种方式cv:Rect和 cv::Range ,C#则用Mat roi = new Mat(cv2.Rect()),然后再使用copyTo进行整图

3.GetRotationMatrix2D:计算旋转矩阵

函数解析:

仿射变换是一种二维坐标(x, y)到二维坐标(u, v)的线性变换,其数学表达式形式如下:
OpencvSharp基础学习5 | 图像变换(ROI截取)
对应的齐次坐标矩阵表示形式为:
OpencvSharp基础学习5 | 图像变换(ROI截取)

仿射变换保持了二维图形的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。
非共线的三对对应点可以确定一个唯一的仿射变换。

函数原型:
Mat getRotationMatrix2D(Point2f center, double angle, double scale)
函数参数:
  Point2f center:表示旋转的中心点
    double angle:表示旋转的角度
    double scale:图像缩放因子
函数返回值:

Mat类型,存放一个2*3的矩阵(变换参数)

使用注意事项:

4.WarpAffine:图像变换

函数解析:

v2.warpAffine()函数主要是利用变换矩阵M对图像进行如旋转、仿射、平移等变换,只需要我们提供一个2*3的变换矩阵M,就可以对图像进行变换。它一般是和cv2.getRotationMatrix2D(旋转和平移)和cv.GetAffineTransform(扭曲仿射变换)两个函数在一起使用,这两个函数是用来获取变换矩阵M,这样就不需要我们自己设置M。

函数原型:
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar& boederValue = Scalar());
函数参数:
src,输入图像,即原图像,填 Mat 类对象那个即可。
dst,输出图像,需要和源图像有一样的类型。
M,2×3 的变换矩阵。因为变换矩阵第三行形式固定,所以忽略。
dsize,输出图像的尺寸。
flags,插值的标识符。默认为 INTER_LINEAR (线性插值)。插值就是根据已知数据点(条件),来预测未知数据点值得方法。在尺寸调整过程中,图像的大小可能发生改变。此时像素与像素之间的关系就不是一一对应关系,因此在尺寸调整过程中,可能会涉及到像素值的插值计算。可选插值方式如下:
INTER_NEAREST(最近邻差值)
INTER_LINEAR(线性插值,默认)
INTER_AREA(区域插值,利用像素区域关系的重采样插值)
INTER_CUBIC(三次样条插值,超过 4×4 像素邻域内的双三次插值)
INTER_LANCZOS4(Lanczos 插值,超过 8×8 像素邻域的 Lanczos 插值)
borderMode,边界扩展类型。默认值为 BORDER_CONSTANT: 
borderValue ,只有当 borderMode取值为 BORDER_CONSTANT 时,这个参数才会被使用,边界会被填充成 borderValue 指定的颜色。 默认是BORDER_CONSTANT(即指定常数值填充) ,实质上,边界处理类型,该枚举型还有:
BORDER_CONSTANT     
iiiiii|abcdefgh|iiiiiii with some specified i(指定常数填充)
BORDER_REPLICATE     
aaaaaa|abcdefgh|hhhhhhh(复制边缘像素填充)
BORDER_REFLECT     
fedcba|abcdefgh|hgfedcb(反射复制边界像素)
BORDER_WRAP     
cdefgh|abcdefgh|abcdefg
BORDER_REFLECT_101     
gfedcb|abcdefgh|gfedcba(对称填充,也就是以最边缘像素为轴)
BORDER_TRANSPARENT     
uvwxyz|absdefgh|ijklmno
BORDER_REFLECT101     
same as BORDER_REFLECT_101
BORDER_DEFAULT     
same as BORDER_REFLECT_101
BORDER_ISOLATED     
do not look outside of ROI
函数返回值:

使用注意事项:

(1). 使用dsize参数控制输出图像尺寸,如果要无损旋转,disze的大小要比原图大,即:
int heightNew = int(src.cols * fabs(sin(angle * CV_PI / 180.0)) + src.rows * fabs(cos(angle * CV_PI / 180.0)));
int widthNew = int(src.cols * fabs(cos(angle * CV_PI / 180.0)) + src.rows * fabs(sin(angle * CV_PI / 180.0)));
(2). 参数M是通过cv2.getRotationMatrix2D(旋转和平移)或者 cv.GetAffineTransform(扭曲仿射变换)获得的变换矩阵。

5.GetRectSubPix:裁剪图像

函数解析:

从原图像中提取一个感兴趣的矩形区域图像。

函数原型:
void getRectSubPix(InputArray image, Size patchSize, Point2f center, OutputArray dst, int patchType=-1 )
函数参数:
InputArray image:输入图像
Size patchSize:获取感兴趣区域矩形的大小
Point2f center:感兴趣区域矩形在原图像中的位置(即感兴趣区域矩形的中心点坐标)
OutputArray patch:输出的图像
int patchType=-1 :表示输出图像的深度。默认-1 ,深度不变
函数返回值:

使用注意事项:

三、案例展示

1.结果展示

OpencvSharp基础学习5 | 图像变换(ROI截取)

2.创造原图

    Mat binMat; //二值图
    Mat srcMat;//原图
    private void button1_Click(object sender, EventArgs e)
    {
        srcMat = new Mat(new OpenCvSharp.Size(400, 400), MatType.CV_8UC1, new  Scalar(50));
       
       
        生成三角形
        //RotatedRect rotateRect = new RotatedRect(new Point2f(200,
        //    200), new Size2f(200, 200),
        //    10);
       
        OpenCvSharp.Point[][] points = new OpenCvSharp.Point[1][];
        points[0] = new OpenCvSharp.Point[3] { new OpenCvSharp.Point(220,280),  new OpenCvSharp.Point(150,150),new OpenCvSharp.Point(280,220)};
        //绘制三角形
        Cv2.DrawContours(srcMat, points, 0, new Scalar(255, 255, 255), -1);
        pictureBox1.Image = BitmapConverter.ToBitmap(srcMat);
        
    }

2.处理原图:二值化原图(可忽略或者其他图像处理方式,把目标展示出来)

    private void button6_Click(object sender, EventArgs e)
    {
        binMat = new Mat();
        Cv2.Threshold(srcMat, binMat, 200, 255, ThresholdTypes.Binary);
        pictureBox6.Image = BitmapConverter.ToBitmap(binMat);
    }

3.求目标ROI区域(这里用最小外接矩形来求),正常需要加面积过滤来过滤干扰

    OpenCvSharp.Point[][] points;
    HierarchyIndex[] hierarchyIndices;
    RotatedRect rotatedRect;
    OpenCvSharp.Point[][] minPoints;
    private void button2_Click(object sender, EventArgs e)
    {
        //查找轮廓
        
        Cv2.FindContours(binMat, out points, out hierarchyIndices,  RetrievalModes.External, ContourApproximationModes.ApproxNone);
        //求最小外接矩形
        Point2f[] minRect;
        rotatedRect = Cv2.MinAreaRect(points[0]);
        Mat minMat = binMat.Clone();
        Point2f[] point2F = rotatedRect.Points();
        //顶点浮点数的中心点转成整数
        OpenCvSharp.Point[] rectVertices = new OpenCvSharp.Point[4];
        for (int i = 0; i < 4; i++)
        {
            rectVertices[i] = new OpenCvSharp.Point(point2F[i].X, point2F[i].Y);
        }
        minPoints = new OpenCvSharp.Point[1][];
        minPoints[0] = rectVertices;
        Cv2.DrawContours(minMat, minPoints, 0, new Scalar(150, 150), 4);
        pictureBox2.Image = BitmapConverter.ToBitmap(minMat);
    }

4.图像变换前裁剪,和变换后作对比参考(实际应用不需要这步)

    private void button9_Click(object sender, EventArgs e)
    {
        Mat mat = new Mat();
        Cv2.GetRectSubPix(binMat, new OpenCvSharp.Size(rotatedRect.Size.Width +  10, rotatedRect.Size.Height + 10), rotatedRect.Center, mat);
        MessageBox.Show("变换前ROI宽高和中心是,宽:" + rotatedRect.Size.Width +  ",高:" + rotatedRect.Size.Height + ",X:" + rotatedRect.Center.X + ",Y:"                     +  rotatedRect.Center.Y);
        pictureBox8.Image = BitmapConverter.ToBitmap(mat);
    }

5.把ROI区域用255掩膜,掩膜图用来拷贝

    private void button7_Click(object sender, EventArgs e)
    {
        //在二值图像中圈出轮廓区域(这里是最小外接矩形)并染白
        Cv2.DrawContours(binMat, minPoints, -1, Scalar.White, -1);
        pictureBox3.Image = BitmapConverter.ToBitmap(binMat);
    }

6.在原图上,扣取掩膜区域的图

    //把掩膜区域的原图抠到此图上
    Mat outRoi;
    private void button4_Click(object sender, EventArgs e)
    {
        outRoi = new Mat(400,400, MatType.CV_8UC1);
        outRoi.SetTo(100);
        //提取Roi,要把目标画到此处
        Mat roi = new Mat(outRoi, new Rect(0, 0, 400, 400));
        
        //将原图通过mask抠图到Roi,这里意思是,将原图srcMat的对应binMat区域中大于1的值抠到新图Roi中,小于1的值ROI图保留原数据
        srcMat.CopyTo(roi, binMat);
        pictureBox4.Image = BitmapConverter.ToBitmap(outRoi);
    }

原则上,5、6都可以省略,这里添加进去是为了测试,把图片ROI区域通过掩膜的方式提取到另一张图上

7.图像变换

    //存放ROI发生旋转变换后的图片(画布)
    Mat afterRotato;
    private void button3_Click(object sender, EventArgs e)
    {
        //存放ROI发生旋转变换后的图片(画布)
        afterRotato = new Mat(srcMat.Size(), MatType.CV_8UC1);
        afterRotato.SetTo(0); //设置像素值,不起作用,因为使用了WarpAffine填充边界
        //获取最小矩形中心(旋转中心)
        Point2f center = rotatedRect.Center;
        //获取最小矩形角度(旋转角度)
        double angel = rotatedRect.Angle;
        //根据中心和角度计算变换矩阵,缩放比率为1
        Mat M = Cv2.GetRotationMatrix2D(center, angel, 1);
        //得到变换后的图像,控制输入图像大小来改变画布大小,填充边界使用默认0值,这里使用BorderTypes.Replicate(复制边缘像素填充)
        Cv2.WarpAffine(outRoi, afterRotato, M, outRoi.Size(),  InterpolationFlags.Linear, BorderTypes.Replicate);
        pictureBox5.Image = BitmapConverter.ToBitmap(afterRotato);
    }

8.变换后裁剪ROI

private void button8_Click(object sender, EventArgs e)
{
Mat mat = new Mat();
Cv2.GetRectSubPix(afterRotato, new OpenCvSharp.Size(rotatedRect.Size.Width+1, rotatedRect.Size.Height+1), rotatedRect.Center, mat);
MessageBox.Show(“变换后ROI宽高和中心是,宽:” + rotatedRect.Size.Width + “,高:” + rotatedRect.Size.Height + “,X:” + rotatedRect.Center.X + “,Y:” + rotatedRect.Center.Y);
pictureBox7.Image = BitmapConverter.ToBitmap(mat);
}

四、总结

1.案例里,创造的裁剪矩形是变换前的最小外接矩形的长宽和中心,把角度归0。因为我们使用ROI本身去变换,最小矩形通过变换后,就是我们裁剪的矩形,当然需要判断一下长短边,这里省略了,关于最小矩形长短边判断后面再总结。
2.在工业视觉中,模板匹配去做初定位,然后绘制ROI去找直线或者圆等应用,其图像变换是在模板中心和模板角度发生,所以绘制的ROI也要通过同样的变换,才能裁剪正常。
3.案例里,是把目标纠正,然后去裁剪。工业视觉中,通常是不肯正的,所以需要用到案例里的4、5步,以上第二点提到,ROI通过同样的变换后,圈中了目标区域,但是当前ROI很可能带有角度,部分裁剪。所以要掩膜把当前ROI复制出来,然后再一次变换为不带角度裁剪,或者直接扩大裁剪区域。

注:文章部分函数解析参考网上资料!如有侵权,连续删除!
转载本文需要标明出处!
谷子彭:1062484747@163.com
文章来源地址https://www.toymoban.com/news/detail-480068.html

到了这里,关于OpencvSharp基础学习5 | 图像变换(ROI截取)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 计算机视觉基础【OpenCV轻松入门】:获取图像的ROI

    OpenCV的基础是处理图像,而图像的基础是矩阵。 因此,如何使用好矩阵是非常关键的。 下面我们通过一个具体的实例来展示如何通过Python和OpenCV对矩阵进行操作,从而更好地实现对图像的处理。 ROI(Region of Interest)是指图像或视频中被选取或感兴趣的特定区域。ROI可以用矩

    2024年02月22日
    浏览(41)
  • [Python从零到壹] 三十七.图像处理基础篇之图像融合处理和ROI区域绘制

    欢迎大家来到“Python从零到壹”,在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近十年的编程经验分享给大家,希望对您有所帮助,文章中不足之处也请海涵。Pyt

    2024年02月07日
    浏览(81)
  • OpenCV学习(五)——图像基本操作(访问图像像素值、图像属性、感兴趣区域ROI和图像边框)

    访问像素值并修改 访问图像属性 设置感兴趣区域(ROI) 分割和合并图像 5.1 访问像素值并修改 访问像素值 修改像素值 简单访问每个像素值并修改比较缓慢,一般不使用。 Numpy数组方法 array.item() 和 array.itemset() 被认为更好,但是它们始终返回标量。 更好的像素访问和编辑方

    2024年02月06日
    浏览(90)
  • C++&Python&C# 三语言OpenCV从零开发(5):ROI截取

    C++PythonCsharp in OpenCV 专栏 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程(附带课程课件资料+课件笔记) ROI,本意是感兴趣区域。但是使用起来就和PS的截取部分区域差不多。 我之前写过一篇Python 的代码 Python+OpenCV 零基础学习笔记(6):ROI 其它的相关文章 OpenCV之感

    2024年01月25日
    浏览(49)
  • OpenCvSharp学习笔记6--改变图像的对比度和亮度

    访问像素值mat.AtT(y,x) 用0初始化矩阵Mat.Zeros 饱和操作SaturateCast.ToByte g(x)=αf(x)+β 用α(0)和β一般称作增益(gain)和偏置(bias),分别控制对比度和亮度 把f(x)看成源图像像素,把g(x)看成输出图像像素 g(i,j)=α⋅f(i,j)+β 其中,i和j表示像素位于 第i行 和 第j列(左上角为第0行、第0列) M

    2024年02月03日
    浏览(62)
  • 数字信号与图像处理实验三:图像处理基础与图像变换

    ​ 通过本实验加深对数字图像的理解,熟悉MATLAB中的有关函数;应用DCT对图像进行变换;熟悉图像常见的统计指标,实现图像几何变换的基本方法。 ​ 选择两幅图像,读入图像并显示,同时使用Matlab计算图像的大小,灰度平均值、协方差矩阵、灰度标准差和相关系数。 DC

    2024年02月04日
    浏览(62)
  • OpenCvSharp (C# OpenCV) 二维码畸变矫正--基于透视变换(附源码)

        本文主要介绍如何使用OpenCvSharp中的透视变换来实现二维码的畸变矫正。     由于CSDN文章中贴二维码会导致显示失败,大家可以直接点下面链接查看图片:     C# OpenCV实现二维码畸变矫正--基于透视变换 (详细步骤 + 代码)      讲解实现步骤之前先看下效果(左边是原图

    2024年02月15日
    浏览(40)
  • 【JAVA学习笔记】 57 - 本章作业

    https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/homework 目录 项目代码 1. 2. 3. 4.试分析HashSet和TreeSet分别如何实现去重的 5. 6. (1)封装个新闻类,包含标题和内容属性,提供get, set方法, 重写toString方法,打印对象时只打印标题; (2)只提供一个带参数的构造器

    2024年02月06日
    浏览(41)
  • [OpenCV学习笔记]Qt+OpenCV实现图像灰度反转、对数变换和伽马变换

    灰度反转是一种线性变换,是将某个范围的灰度值映射到另一个范围内,一般是通过灰度的对调,突出想要查看的灰度区间。 S = L − 1 − r ( r ⊂ [ 0 , L − 1 ] ) S = L -1-r (r subset [0,L-1]) S = L − 1 − r ( r ⊂ [ 0 , L − 1 ]) 比如在以下胸片图像中提取白色絮状形状,在黑色背景下看

    2024年04月13日
    浏览(56)
  • open cv学习 (四)图像的几何变换

    demo1 demo2 demo3 demo4 demo5 demo6 demo7

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包