c# OpenCvSharp透视矫正六步实现透视矫正(八)

news2025/2/6 9:54:22

透视矫正,引用文档拍照扫描,相片矫正这块。

  1. 读取图像Cv2.ImRead();
  2. 预处理(灰度化,高斯滤波、边缘检测)
  3. 轮廓检测(获取到最大轮廓)
  4. 获取最大面积轮廓的四个顶点
  5. 标识最小矩形坐标
  6. 透视矫正显示

完整代码

 // 1、读取图像
 Mat image = Cv2.ImRead("2.jpg", ImreadModes.Color);

 //2、预处理(灰度化,高斯滤波、边缘检测)

 Mat src_gray = new Mat();
 Cv2.CvtColor(image, src_gray, ColorConversionCodes.BGR2GRAY); // 转换为灰度图像
 Cv2.GaussianBlur(src_gray, src_gray, new Size(5, 5), 0, 0); // 进行高斯模糊
 Mat canny_Image = new Mat();
 Cv2.Canny(src_gray, canny_Image, 75, 200);

 //3、轮廓检测
 Point[][] contours;
 HierarchyIndex[] hierarchy;
 Cv2.FindContours(canny_Image, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
 
 // 计算轮廓的面积
 double maxArea = 0;
 int maxAreaIndex = -1;
 for (int i = 0; i < contours.Length; i++)
 {
     double area = Cv2.ContourArea(contours[i]);
     if (area > maxArea)
     {
         maxArea = area;
         maxAreaIndex = i;
     }
 }

 // 获取最大面积的轮廓
 Point[] largestContour = contours[maxAreaIndex];
 //4、获取最大面积轮廓的四个顶点。
 Point[] approx = Cv2.ApproxPolyDP(contours[maxAreaIndex], 0.02 * Cv2.ArcLength(contours[maxAreaIndex], true), true);
 Cv2.DrawContours(image, new Point[][] { approx }, -1, Scalar.Blue, 2);

 //可以注释掉
 for (int i = 0; i < 4; i++)
 {
      // 设置目标图像的四个顶点坐标
    //Cv2.PutText(image, "H"+i, new Point(approx[i].X, approx[i].Y), HersheyFonts.HersheySimplex, 1, new Scalar(0, 0, 255), 2, LineTypes.Link4);
 }
 //5、透视转换
 OpenCvSharp.Point2f[] srcPt = new OpenCvSharp.Point2f[4];
 srcPt[0] = approx[0];
 srcPt[1] = approx[3];
 srcPt[2] = approx[2];
 srcPt[3] = approx[1];

 RotatedRect rect = Cv2.MinAreaRect(srcPt);
 Rect box = rect.BoundingRect();
 OpenCvSharp.Point2f[] dstPt = new OpenCvSharp.Point2f[4];
 //可以注释掉用于观察坐标点是否对齐
 
 dstPt[0].X = 0;
 dstPt[0].Y = 0;
 dstPt[1].X = 0 + box.Width;
 dstPt[1].Y = 0;
 dstPt[2].X = 0 + box.Width;
 dstPt[2].Y = 0 + box.Height;
 dstPt[3].X = 0;
 dstPt[3].Y = 0 + box.Height;

 Mat final = new Mat(box.Height, box.Width, MatType.CV_8UC3);
    
 Mat warpmatrix = Cv2.GetPerspectiveTransform(srcPt, dstPt);//获得变换矩阵
 Cv2.WarpPerspective(image, final, warpmatrix, final.Size());//投射变换,将结果赋给final
 Cv2.ImShow("获取新正四边形", final);
 Cv2.WaitKey(0);
 Rect roi = new Rect(box.X, box.Y, box.Width, box.Height);//坐标 x,y 尺寸 长宽
 Mat croppedImage = new Mat(final, roi);
 for (int i = 0; i < 4; i++)
 {
     // 设置目标图像的四个顶点坐标
     Cv2.PutText(image, "A" + i, new Point(dstPt[i].X, dstPt[i].Y), HersheyFonts.HersheySimplex, 1, new Scalar(0, 0, 255), 2, LineTypes.Link4);
 }
 // 显示结果
 Cv2.ImShow("透视矫正图像", image);
 Cv2.WaitKey(0);

一 、读取图像Cv2.ImRead()

// 1、读取图像
Mat image = Cv2.ImRead("2.jpg", ImreadModes.Color);

二、预处理(灰度化,高斯滤波、边缘检测) 

灰度化:Cv2.CvtColor();

高斯滤波:Cv2.GaussianBlur();

边缘检测:Cv2.Canny();

//2、预处理(灰度化,高斯滤波、边缘检测)

Mat src_gray = new Mat();
Cv2.CvtColor(image, src_gray, ColorConversionCodes.BGR2GRAY); // 转换为灰度图像
Cv2.GaussianBlur(src_gray, src_gray, new Size(5, 5), 0, 0); // 进行高斯模糊
Mat canny_Image = new Mat();
Cv2.Canny(src_gray, canny_Image, 75, 200);

 

三、轮廓检测(获取到最大轮廓) 

通过Cv2.ContourArea()计算轮廓的面积,选出最大轮廓

//3、轮廓检测
Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(canny_Image, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);

// 计算轮廓的面积
double maxArea = 0;
int maxAreaIndex = -1;
for (int i = 0; i < contours.Length; i++)
{
    double area = Cv2.ContourArea(contours[i]);
    if (area > maxArea)
    {
        maxArea = area;
        maxAreaIndex = i;
    }
}

// 获取最大面积的轮廓
Point[] largestContour = contours[maxAreaIndex];

 

四、 获取最大面积轮廓的四个顶点。

Cv2.ApproxPolyDP() 获取4个顶点坐标

//4、获取最大面积轮廓的四个顶点。
Point[] approx = Cv2.ApproxPolyDP(contours[maxAreaIndex], 0.02 * Cv2.ArcLength(contours[maxAreaIndex], true), true);

 标识四个顶点

 //可以注释掉
 for (int i = 0; i < 4; i++)
 {
      // 设置目标图像的四个顶点坐标
    Cv2.PutText(image, "H"+i, new Point(approx[i].X, approx[i].Y), HersheyFonts.HersheySimplex, 1, new Scalar(0, 0, 255), 2, LineTypes.Link4);
 }

五、标识最小矩形坐标

获取顶点内最小矩形Cv2.MinAreaRect(srcPt);

//获取四个顶点坐标最小矩形顶点
RotatedRect rect = Cv2.MinAreaRect(srcPt);
Rect box = rect.BoundingRect();
OpenCvSharp.Point2f[] dstPt = new OpenCvSharp.Point2f[4];
stPt[0].X = box.X;
            dstPt[0].Y = box.Y;
            dstPt[1].X = box.X + box.Width;
            dstPt[1].Y = box.Y;
            dstPt[2].X = box.X + box.Width;
            dstPt[2].Y = box.Y + box.Height;
            dstPt[3].X = box.X;
            dstPt[3].Y = box.Y + box.Height;
            Mat final = new Mat();
            Mat warpmatrix = Cv2.GetPerspectiveTransform(srcPt, dstPt);//获得变换矩阵
            Cv2.WarpPerspective(image, final, warpmatrix, image.Size());//投射变换,将结果赋给final
            Rect roi = new Rect(box.X, box.Y, box.Width, box.Height);//坐标 x,y 尺寸 长宽
            Mat croppedImage = new Mat(final, roi);
            for (int i = 0; i < 4; i++)
            {
                // 设置目标图像的四个顶点坐标
                Cv2.PutText(image, "A" + i, new Point(dstPt[i].X, dstPt[i].Y), HersheyFonts.HersheySimplex, 1, new Scalar(0, 0, 255), 2, LineTypes.Link4);
            }

 

两个坐标点顺序不一样,对齐坐标顺序,进行透视坐标转换

 

 //5、透视转换
 OpenCvSharp.Point2f[] srcPt = new OpenCvSharp.Point2f[4];
 srcPt[0] = approx[0];
 srcPt[1] = approx[3];
 srcPt[2] = approx[2];
 srcPt[3] = approx[1];

 RotatedRect rect = Cv2.MinAreaRect(srcPt);
 Rect box = rect.BoundingRect();
 OpenCvSharp.Point2f[] dstPt = new OpenCvSharp.Point2f[4];
 
 dstPt[0].X = box.X;
 dstPt[0].Y = box.Y;
 dstPt[1].X = box.X + box.Width;
 dstPt[1].Y = box.Y;
 dstPt[2].X = box.X + box.Width;
 dstPt[2].Y = box.Y + box.Height;
 dstPt[3].X = box.X;
 dstPt[3].Y = box.Y + box.Height;
 Mat final = new Mat();

六、透视变换显示

Mat warpmatrix = Cv2.GetPerspectiveTransform(srcPt, dstPt);//获得变换矩阵
Cv2.WarpPerspective(image, final, warpmatrix, final.Size());//投射变换,将结果赋给final
Cv2.ImShow("透视矫正图像", final);

 通过掌握这六个步骤,你可以在C#中使用OpenCvSharp实现透视矫正。祝你成功!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1336775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库优化汇总】使用这8招后,数据库查询从191s优化到30ms!

为什么数据库会慢&#xff1f; 慢的本质 查找的时间复杂度 查找算法 存储数据结构 存储数据结构 数据总量 数据拆分 高负载 CPU、磁盘繁忙 无论是关系型数据库还是NoSQL&#xff0c;任何存储系统决定于其查询性能的主要有三种&#xff1a; 查找的时间复杂度数据…

越南语翻译中文有什么特点,怎样翻译比较好?

近年来&#xff0c;随着中越经济贸易的日益频繁&#xff0c;语言交流已无法避免&#xff0c;越南语翻译的需求也持续增加。那么&#xff0c;越南语有何独特之处&#xff1f;越南语翻译成中文时&#xff0c;又该如何处理呢&#xff1f; 专业人士指出&#xff0c;在进行越南语翻译…

cefsharp120.1.110(cef120.1.10,Chromium120.0.6099.129)升级测试及其他H264版本

一、版本变化 v120.1.80–>v120.1.110 相对于120.1.80 更新了一个安全更新,针对Google 获悉存在针对 CVE-2023-7024 的漏洞。 说明:本版本暂时不支持264,其他H264版本参考119,116,115,114,111,110,109,107,100等版本 v109是支持win7/8/8.1最后一个版本(推荐v100版本) v…

鸿蒙4升级进展:共137款产品加入升级,Mate 20也能升级了

从华为官方发布的鸿蒙升级进展来看&#xff0c;2018年发布的Mate 20系列机型也开始了鸿蒙4系统升级的测试招募。 5年之期已到&#xff0c;再战5年不是梦想&#xff1f; 另外&#xff0c;从明年一季度的升级预告来看&#xff0c;春节前后升级的主要为穿戴手表产品。 目前&…

spring security oauth2搭建认证服务器

如图&#xff08;上面图片的代码在业务项目中&#xff09;&#xff0c;第一步在独立的业务项目中&#xff0c;先获取授权码&#xff08;也叫jsessionId&#xff09;、获取授权码的路径就是 /oauth2/authorize&#xff0c;这个路径是oauth2的框架中被OAuth2AuthorizationEndpoin…

YOLOv7训练数据报错

YOLOv7训练数据报错 错误提示1解决方案问题2解决方案成功运行 错误提示1 fatal: not a git repository (or any of the parent directories): .git Traceback (most recent call last):File "/home/ubuntu/code/yolov7-main/utils/google_utils.py", line 26, in att…

为什么说依赖抽象就变得更加灵活呢?举例

说依赖抽象变得更加灵活的主要原因在于它提供了更大的替换和扩展的空间。让我们通过一个简单的例子来说明&#xff1a; 考虑一个电商系统&#xff0c;其中有一个OrderProcessor类负责处理订单&#xff0c;它依赖于一个PaymentGateway用于处理支付。最初的设计可能如下所示&…

前端,build后index报错,noscript

解决方法&#xff1a; npx update-browserslist-dblatest

CSS、JavaScript实现进度条效果HTML

CSS、JavaScript实现进度条效果HTML 效果图 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>ProgressBar</title><style>* {margin: 0;padding: 0;}body {position…

【HTML5】第2章 HTML5标签和属性

学习目标 掌握文本控制标签的用法&#xff0c;能够使用文本控制标签设置文本样式。 掌握图像标签的用法&#xff0c;能够使用图像标签在网页中嵌入图片。 掌握超链接标签的用法&#xff0c;能够使用超链接实现页面的跳转。 掌握列表标签的用法&#xff0c;能够使用列表标签设…

AMEYA360:思瑞浦发布全新并联基准芯片—:TPR43x系列产品

聚焦高性能模拟芯片和嵌入式处理器的半导体公司——思瑞浦(3PEAK, 股票代码&#xff1a;688536)推出全新并联基准芯片TPR433/TPR434。 TPR433/TPR434基于BCD工艺&#xff0c;电压精度0.5%25C&#xff0c;可广泛应用于电源、照明、工业设备等领域。 TPR433/434产品特性 *通过外部…

互联网加竞赛 YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快&#xff0c;YOLOv6还没用熟YOLOv7就来了&#xff0c;如果有同学的毕设项目想用上最新的技术&#xff0c;不妨看看学长的这篇文章&#xff0c;学长带大家简单的…

右值引用和移动语义以及C++11新增的类功能

正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 右值引用和左值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特…

移动端防截屏录屏技术在百度账户系统实践

作者 | Seven 导读 在移动端应用的开发过程中&#xff0c;保护用户隐私和应用内敏感信息安全是一个不可忽视的课题。随着诈骗手段的升级&#xff0c;“共享屏幕”被诈骗分子频频使用&#xff0c;因为密码被泄露而导致受害者财物受损的事情层出不穷。只要开启了“共享屏幕”–本…

vue3使用Cascader联级选择器的懒加载+回显

效果图 页面代码 // separator是改变文字链接的方式&#xff0c; <el-cascaderseparator"-"v-model"currentRegionList":props"DeptRegionList":options"getRegionList"change"handleRegionListFun"ref"deptRegio…

Java——Windows系统怎么查看某个端口被占用和杀死进程解除占用,看这一篇就够了!!!

Windows系统端口占用 1. netstat -ano2. 查看某端口占用的PID3. tasklist|findstr "PID"4. 解除端口占用 总结 本篇文章介绍一下windows系统中怎么查看某个端口被占用以及如何解除占用。 1. netstat -ano 作用&#xff1a;查看系统中所有端口的占用情况 可以看到本…

面对勒索,金融机构该怎么办?

就在近期&#xff0c;某大行美国子公司被勒索软件攻击&#xff0c;使得部分交易系统中断&#xff0c;该行也在网站确认遭受了勒索软件攻击。这再次引发了金融机构对勒索软件的警惕与担忧&#xff0c;也凸显了一个重要的安全问题&#xff1a;犯罪分子不仅能窃取财产&#xff0c;…

MessageBox和HubSpot:数字化时代综合营销引擎

在数字时代&#xff0c;社交媒体已经成为企业与客户互动的重要平台。然而&#xff0c;随着信息的爆炸性增长&#xff0c;有效管理社交互动变得愈发具有挑战性。企业需要在海量信息中找到并回应关键的用户消息&#xff0c;这正是数字时代社交互动面临的主要挑战。为了解决这一问…

搭建Nginx文件下载站点

一、下载Nginx 首先&#xff0c;确保你的服务器上已经安装了Nginx&#xff0c;使用编译安装&#xff0c;下载最新版Nginx。 wget https://nginx.org/download/nginx-1.25.3.tar.gz tar -xf nginx-1.25.3.tar.gz二、安装Fancyindex和Nginx-Fancyindex-Theme模块 # 下载Fancyin…

k8s中的整体架构 ,pod含义,服务类型,网络通讯等

k8s中的整体架构 &#xff0c;pod含义&#xff0c;服务类型&#xff0c;网络通讯等 k8s整体架构pod内部和pod之间的通讯k8s的组件 k8s整体架构 上图中&#xff0c;较大的红框是k8s中的master节点&#xff0c;负责接受请求&#xff0c;调度任务&#xff0c;管理节点等&#xff0…