• OpenCVForUnity 透视矫正、透视变换


    OpenCVForUnity有封裝好的計算透視變換矩陣的方法:

    public static Mat getPerspectiveTransform (Mat src, Mat dst)

    和通過透視變換矩陣實現透視變換的方法:

    public static void warpPerspective (Mat src, Mat dst, Mat M, Size dsize)


    所以要實現透視校正的關鍵在於獲取原始圖片四個交叉點,大致流程: 載入圖像→灰度化→邊緣處理得到邊緣圖像→霍夫變換進行直線檢測→計算得到需要的四個交叉點

    灰度化圖片

    public static void cvtColor (Mat src, Mat dst, int code)

    邊緣處理

    public static void Canny (Mat image, Mat edges, double threshold1, double threshold2)

    霍夫曼線

    public static void HoughLinesP (Mat image, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap)

    第一個參數為輸入圖像,應該為灰度圖, 
    第二個參數為輸出的檢測到的直線的容器 
    第三個參數為以參數極徑單位的分辨率 
    第四個是以弧度為單位的分辨率 
    第五個為一條直線所需最少的的曲線交點

    計算霍夫曼線交叉點 並剔除不合理的點(這個方法根據實際計算出來的點位置自行調整)

     private Vector2 ComputeIntersect(List a, List b)

     private void CullIllegalPoint(ref List corners,float minDis)

    完整代碼:

    1. using System;
    2. using OpenCVForUnity;
    3. using OpenCVForUnityExample;
    4. using UnityEngine;
    5. using UnityEngine;
    6. using System.Collections;
    7. using System.Collections.Generic;
    8. using OpenCVForUnity.CoreModule;
    9. using OpenCVForUnity.ImgprocModule;
    10. using OpenCVForUnity.UnityUtils;
    11. using OpenCVForUnity.UnityUtils.Helper;
    12. using OpenCVForUnity.DnnModule;
    13. using OpenCVForUnity.ObjdetectModule;
    14. using OpenCVForUnity.UtilsModule;
    15. using Unity.Mathematics;
    16. using UnityEditor;
    17. using Range = OpenCVForUnity.CoreModule.Range;
    18. using Rect = OpenCVForUnity.CoreModule.Rect;
    19. public class UIPerspectiveTransform: MonoBehaviour
    20. {
    21. private List corners = new List();
    22. // Use this for initialization
    23. void Start()
    24. {
    25. Texture2D inputTexture = Resources.Load("inputTexture") as Texture2D;
    26. Mat inputMat = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC4);
    27. Mat outputMat = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC4);
    28. Utils.texture2DToMat(inputTexture, inputMat);
    29. Imgproc.cvtColor(inputMat, outputMat, Imgproc.COLOR_RGB2GRAY);
    30. Imgproc.Canny(outputMat, outputMat, 100, 150);
    31. Mat lines = new Mat();
    32. //第五個參數是閾值,通過調整閾值大小可以過濾掉一些干擾線
    33. Imgproc.HoughLinesP(outputMat, lines, 1, Mathf.PI / 180, 60, 50, 10);
    34. //計算霍夫曼線外圍的交叉點
    35. int[] linesArray = new int[lines.cols() * lines.rows() * lines.channels()];
    36. lines.get(0, 0, linesArray);
    37. Debug.Log("length of lineArray " + linesArray.Length);
    38. List<int> a = new List<int>();
    39. List<int> b = new List<int>();
    40. for (int i = 0; i < linesArray.Length - 4; i = i + 4)
    41. {
    42. Imgproc.line(inputMat, new Point(linesArray[i + 0], linesArray[i + 1]),
    43. new Point(linesArray[i + 2], linesArray[i + 3]), new Scalar(255, 0, 0), 2);
    44. }
    45. for (int i = 0; i < linesArray.Length; i = i + 4)
    46. {
    47. a.Add(linesArray[i + 0]);
    48. a.Add(linesArray[i + 1]);
    49. a.Add(linesArray[i + 2]);
    50. a.Add(linesArray[i + 3]);
    51. for (int j = i + 4; j < linesArray.Length; j = j + 4)
    52. {
    53. b.Add(linesArray[j + 0]);
    54. b.Add(linesArray[j + 1]);
    55. b.Add(linesArray[j + 2]);
    56. b.Add(linesArray[j + 3]);
    57. Vector2 temp = ComputeIntersect(a, b);
    58. b.Clear();
    59. if (temp.x > 0 && temp.y > 0 && temp.x < 1000 && temp.y < 1000)
    60. {
    61. corners.Add(temp);
    62. }
    63. }
    64. a.Clear();
    65. }
    66. //剔除重合的點和不合理的點
    67. CullIllegalPoint(ref corners, 20);
    68. if (corners.Count != 4)
    69. {
    70. Debug.Log("The object is not quadrilateral " + corners.Count);
    71. }
    72. Vector2 center = Vector2.zero;
    73. for (int i = 0; i < corners.Count; i++)
    74. {
    75. center += corners[i];
    76. }
    77. center *= 0.25f;
    78. SortCorners(ref corners, center);
    79. //計算轉換矩陣
    80. Vector2 tl = corners[0];
    81. Vector2 tr = corners[1];
    82. Vector2 br = corners[2];
    83. Vector2 bl = corners[3];
    84. Mat srcRectMat = new Mat(4, 1, CvType.CV_32FC2);
    85. Mat dstRectMat = new Mat(4, 1, CvType.CV_32FC2);
    86. srcRectMat.put(0, 0, tl.x, tl.y, tr.x, tr.y, bl.x, bl.y, br.x, br.y);
    87. dstRectMat.put(0, 0, 0.0, inputMat.rows(), inputMat.cols(), inputMat.rows(), 0.0, 0.0, inputMat.rows(), 0);
    88. Mat perspectiveTransform = Imgproc.getPerspectiveTransform(srcRectMat, dstRectMat);
    89. Mat outputMat0 = inputMat.clone();
    90. //圈出四個頂點
    91. //Point t = new Point(tl.x,tl.y);
    92. //Imgproc.circle(outputMat0, t, 6, new Scalar(0, 0, 255, 255), 2);
    93. //t = new Point(tr.x, tr.y);
    94. //Imgproc.circle(outputMat0, t, 6, new Scalar(0, 0, 255, 255), 2);
    95. //t = new Point(bl.x, bl.y);
    96. //Imgproc.circle(outputMat0, t, 6, new Scalar(0, 0, 255, 255), 2);
    97. //t = new Point(br.x, br.y);
    98. //Imgproc.circle(outputMat0, t, 6, new Scalar(0, 0, 255, 255), 2);
    99. //進行透視轉換
    100. Imgproc.warpPerspective(inputMat, outputMat0, perspectiveTransform, new Size(inputMat.rows(), inputMat.cols()));
    101. Texture2D outputTexture = new Texture2D(outputMat0.cols(), outputMat0.rows(), TextureFormat.RGBA32, false);
    102. Utils.matToTexture2D(outputMat0, outputTexture);
    103. gameObject.GetComponent().material.mainTexture = outputTexture;
    104. }
    105. // Update is called once per frame
    106. void Update()
    107. {
    108. }
    109. private Vector2 ComputeIntersect(List<int> a, List<int> b)
    110. {
    111. int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3];
    112. int x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
    113. float d = ((float) (x1 - x2) * (y3 - y4)) - (x3 - x4) * (y1 - y2);
    114. Vector2 temp = Vector2.zero;
    115. if (d == 0)
    116. {
    117. temp.x = -1;
    118. temp.y = -1;
    119. }
    120. else
    121. {
    122. temp.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
    123. temp.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
    124. }
    125. return temp;
    126. }
    127. private void CullIllegalPoint(ref List corners, float minDis)
    128. {
    129. Vector2 a = Vector2.zero;
    130. Vector2 b = Vector2.zero;
    131. List removeList = new List();
    132. for (int i = 0; i < corners.Count; i++)
    133. {
    134. a = corners[i];
    135. for (int j = i + 1; j < corners.Count; j++)
    136. {
    137. b = corners[j];
    138. if (Vector2.Distance(a, b) < minDis)
    139. {
    140. removeList.Add(b);
    141. }
    142. }
    143. }
    144. for (int i = 0; i < removeList.Count; i++)
    145. {
    146. corners.Remove(removeList[i]);
    147. }
    148. }
    149. private void SortCorners(ref List corners, Vector2 center)
    150. {
    151. List top = new List();
    152. List bot = new List();
    153. for (int i = 0; i < corners.Count; i++)
    154. {
    155. if (corners[i].y > center.y)
    156. top.Add(corners[i]);
    157. else
    158. bot.Add(corners[i]);
    159. }
    160. if (top.Count < 2)
    161. {
    162. Vector2 temp = GetMaxFromList(bot);
    163. top.Add(temp);
    164. bot.Remove(temp);
    165. }
    166. if (top.Count > 2)
    167. {
    168. Vector2 temp = GetMinFromList(top);
    169. top.Remove(temp);
    170. bot.Add(temp);
    171. }
    172. Vector2 tl = top[0].x > top[1].x ? top[1] : top[0];
    173. Vector2 tr = top[0].x > top[1].x ? top[0] : top[1];
    174. Vector2 bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
    175. Vector2 br = bot[0].x > bot[1].x ? bot[0] : bot[1];
    176. corners.Clear();
    177. corners.Add(tl);
    178. corners.Add(tr);
    179. corners.Add(br);
    180. corners.Add(bl);
    181. }
    182. private Vector2 GetMaxFromList(List list)
    183. {
    184. Vector2 temp = list[0];
    185. for (int i = 0; i < list.Count; i++)
    186. {
    187. if (list[i].y > temp.y)
    188. {
    189. temp = list[i];
    190. }
    191. }
    192. return temp;
    193. }
    194. private Vector2 GetMinFromList(List list)
    195. {
    196. Vector2 temp = list[0];
    197. for (int i = 0; i < list.Count; i++)
    198. {
    199. if (list[i].y < temp.y)
    200. {
    201. temp = list[i];
    202. }
    203. }
    204. return temp;
    205. }
    206. }

    OpenCV 透视变换【图像归一化矫正】 - fag888 - 博客园

  • 相关阅读:
    模板语法2
    Windows同时安装两个版本JDK,并实现动态切换JAVA8或者JAVA11
    保姆级教程,教你AI数字人应该怎么制作?!
    python常用操作汇总
    42V转5V芯片——高效率、宽压输入范围和强大输出能力
    Java中使用CountDownLatch实现并发流程控制
    在Spring Boot中使用JTA实现对多数据源的事务管理
    进程保活-账号同步实现
    【系统架构设计师】一、计算机系统基础知识(指令系统|存储系统|输入输出技术|总线结构)
    消耗服务器cpu和内存
  • 原文地址:https://blog.csdn.net/qq_42672770/article/details/127568670