• 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 - 博客园

  • 相关阅读:
    git学习
    景联文科技提供3D点云-图像标注服务
    【C语言深入理解指针(2)】
    vector
    Codeforces 1696E. Placing Jinas 高维前缀和、组合数取模
    05.jvm常量池02
    非常详细的git-flow分支管理流程配置及使用
    算法-乘积尾零
    自动驾驶学习笔记(三)——场景设计
    如何选择适合爬虫的动态住宅套餐
  • 原文地址:https://blog.csdn.net/qq_42672770/article/details/127568670