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

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

  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());//投射变换,将结果赋给finalCv2.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());//投射变换,将结果赋给finalRect 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.hqwc.cn/news/300468.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】LRU缓存的简单模拟实现(leetcode力扣146LRU缓存)

文章目录 一、定义二、LRU模拟实现二、代码实现 一、定义 LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。 Cache的容量有限&#xff0c;因此当Cache的容量用完后&#xff0c;而又有新的内容需要添加进来时&#xff0c; 就…

\r\n和缓冲区/进度条小程序

一 前置知识 带有\n就会立马刷新缓冲区&#xff0c;\r不会刷新缓冲区 刷新的2个场景: 1 ~fflush 缓冲区中存在\r或\n --> \r fflush --> 不换行的\n) 2 ~ 文件关闭自动刷新缓冲区 倒计时小程序0-9 倒计时小程序0-99

PostgreSQL 可观测性最佳实践

简介 软件简述 PostgreSQL 是一种开源的关系型数据库管理系统 (RDBMS)&#xff0c;它提供了许多可观测性选项&#xff0c;以确保数据库的稳定性和可靠性。 可观测性 可观测性&#xff08;Observability&#xff09;是指对数据库状态和操作进行监控和记录&#xff0c;以便在…

中间继电器的文字符号和图形符号

中间继电器的文字符号和图形符号 中间继电器主要用途是当其他继电器触头数量或容量不够时&#xff0c;可借助中间继电器扩充触头数目或增大触头容量&#xff0c;起中间转换作用。将多个中间继电器相组合&#xff0c;还能构成各种逻辑运算电器或计数电器。 中间继电器文字符号…

C# WPF上位机开发(windows pad上的应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 大部分同学可能都认为c# wpf只能用在pc端。其实这是一种误解。c# wpf固然暂时只能运行在windows平台上面&#xff0c;但是windows平台不仅仅是电脑…

iconify图标集离线使用方案简介

1.需求描述 前端项目&#xff0c;技术栈使用Vue3Element Plus&#xff0c;参考了ruoyi-vue-pro项目与vue-element-plus-admin项目&#xff0c;封装了一个Icon组件&#xff0c;图标使用的是iconify,项目部署在内网环境&#xff0c;不能连接互联网&#xff0c;需要部署一套iconi…

Linux操作系统基础知识点

Linux是一种计算机操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年首次发布。Linux操作系统通常与GNU套件一起使用&#xff0c;因此也被称为GNU/Linux。它是一种类UNIX的操作系统&#xff0c;设计为多用户、多任务…

【自定义磨砂动态背景】前端及pyqt6实现

如何实现一个自定义的磨砂动态背景呢&#xff1f; 这种效果看起来特别的高端&#xff0c;很新颖美观。 具体的效果可以看这里的演示&#xff1a;https://www.bilibili.com/video/BV1zj411H7wd/ 其实原理就是底层有多个多彩多边形在移动&#xff0c;然后再盖上一层模糊滤镜。 前…

React Router有几种模式?实现原理?

面试官&#xff1a;说说React Router有几种模式&#xff1f;实现原理&#xff1f; 一、是什么 在单页应用中&#xff0c;一个web项目只有一个html页面&#xff0c;一旦页面加载完成之后&#xff0c;就不用因为用户的操作而进行页面的重新加载或者跳转&#xff0c;其特性如下&a…

Windows系统配置pytorch环境,Jupyter notebook编辑器安装使用(深度学习本地篇)

如今现在好一点的笔记本都自带英伟达独立显卡&#xff0c;对于一些简单的深度学习项目&#xff0c;是不需要连接服务器的&#xff0c;甚至数据量不大的话&#xff0c;cpu也足够进行训练学习。我把电脑上一些以前的笔记整理一下&#xff0c;记录起来&#xff0c;方便自己35岁事业…

C++系列第九篇 数据类型下篇 - 复合类型(指针高级应用)

系列文章 C 系列 前篇 为什么学习C 及学习计划-CSDN博客 C 系列 第一篇 开发环境搭建&#xff08;WSL 方向&#xff09;-CSDN博客 C 系列 第二篇 你真的了解C吗&#xff1f;本篇带你走进C的世界-CSDN博客 C 系列 第三篇 C程序的基本结构-CSDN博客 C 系列 第四篇 C 数据类型…

谷歌 SGE 和生成式 AI 在搜索中:2024 年会发生什么

2024 年&#xff0c;Google 的搜索生成体验将如何影响营销&#xff1f;探索 AI 驱动的搜索趋势、SERP 中的 SGE、自然流量影响等。 最初&#xff0c;Labs 中的 Google 搜索生成体验 &#xff08;SGE&#xff09; 实验预计将于 2023 年 12 月“结束”。但随着谷歌实验室网站的最…