暫無描述

xword.js 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // vim:ts=4:sw=4:expandtab
  2. 'use strict';
  3. function plot(elementId, seriesList) {
  4. let plots = [];
  5. for (let i = 0; i < seriesList.length; i++) {
  6. let y = seriesList[i];
  7. let x = [];
  8. for (let i = 0; i < y.length; i++) {
  9. x.push(i);
  10. }
  11. plots.push({x: x, y: y});
  12. }
  13. Plotly.plot(document.getElementById(elementId), plots);
  14. }
  15. function removeColours(src, dst, threshold) {
  16. let from = src.data32S;
  17. let to = dst.data32S;
  18. let pixels = src.rows * src.cols;
  19. for (let i = 0; i < pixels; i++) {
  20. let pixel = from[i];
  21. let r = pixel & 0xFF;
  22. let g = (pixel >> 8) & 0xFF;
  23. let b = (pixel >> 16) & 0xFF;
  24. to[i] = from[i] | (Math.max(r, g, b) - Math.min(r, g, b) > threshold ? 0xFFFFFF : 0);
  25. }
  26. }
  27. function preprocessImage(src, dst, gaussianBlurSize, adaptiveThresholdBlockSize, adaptiveThresholdMeanAdjustment, numDilations) {
  28. cv.GaussianBlur(src, dst, new cv.Size(gaussianBlurSize, gaussianBlurSize), 0);
  29. cv.adaptiveThreshold(dst, dst, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, adaptiveThresholdBlockSize, adaptiveThresholdMeanAdjustment);
  30. let kernel = cv.getStructuringElement(cv.MORPH_CROSS, new cv.Size(3, 3));
  31. try {
  32. cv.dilate(dst, dst, kernel, new cv.Point(-1, -1), numDilations);
  33. } finally {
  34. kernel.delete();
  35. }
  36. }
  37. function morphOpenImage(src, dst, kernelSize, iterations) {
  38. let kernel = cv.getStructuringElement(cv.MORPH_RECT, kernelSize);
  39. try {
  40. cv.morphologyEx(src, dst, cv.MORPH_OPEN, kernel, new cv.Point(-1, -1), iterations);
  41. } finally {
  42. kernel.delete();
  43. }
  44. }
  45. function findBiggestContour(img) {
  46. let contours = new cv.MatVector();
  47. try {
  48. let hierarchy = new cv.Mat();
  49. try {
  50. cv.findContours(img, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
  51. let biggest = null;
  52. let maxArea = 0;
  53. for (let i = 0; i < contours.size(); i++) {
  54. let contour = contours.get(i);
  55. let area = cv.contourArea(contour);
  56. if (area > maxArea) {
  57. maxArea = area;
  58. if (biggest !== null) {
  59. biggest.delete();
  60. }
  61. biggest = contour;
  62. } else {
  63. contour.delete();
  64. }
  65. }
  66. return biggest;
  67. } finally {
  68. hierarchy.delete();
  69. }
  70. } finally {
  71. contours.delete();
  72. }
  73. }
  74. function erodeContour(imageSize, contour, kernelSize, iterations) {
  75. let contourImg = cv.Mat.zeros(imageSize.height, imageSize.width, cv.CV_8U);
  76. try {
  77. let contours = new cv.MatVector();
  78. try {
  79. contours.push_back(contour);
  80. cv.drawContours(contourImg, contours, 0, new cv.Scalar(255), -1);
  81. } finally {
  82. contours.delete();
  83. }
  84. morphOpenImage(contourImg, contourImg, new cv.Size(kernelSize, kernelSize), iterations);
  85. return findBiggestContour(contourImg);
  86. } finally {
  87. contourImg.delete();
  88. }
  89. }
  90. function getContourCorners(imageSize, contour) {
  91. let topLeft = new cv.Point(imageSize.width, imageSize.height);
  92. let topRight = new cv.Point(-1, imageSize.height);
  93. let bottomLeft = new cv.Point(imageSize.width, -1);
  94. let bottomRight = new cv.Point(-1, -1);
  95. for (let i = 0; i < contour.rows; i++) {
  96. let vertex = new cv.Point(contour.data32S[i * 2], contour.data32S[i * 2 + 1]);
  97. let sum = vertex.x + vertex.y;
  98. let diff = vertex.x - vertex.y;
  99. if (sum < topLeft.x + topLeft.y) {
  100. topLeft = vertex;
  101. }
  102. if (sum > bottomRight.x + bottomRight.y) {
  103. bottomRight = vertex;
  104. }
  105. if (diff < bottomLeft.x - bottomLeft.y) {
  106. bottomLeft = vertex;
  107. }
  108. if (diff > topRight.x - topRight.y) {
  109. topRight = vertex;
  110. }
  111. }
  112. return [topLeft, topRight, bottomRight, bottomLeft];
  113. }
  114. function segmentLength(p1, p2) {
  115. let dx = p1.x - p2.x;
  116. let dy = p1.y - p2.y;
  117. return Math.sqrt(dx ** 2 + dy ** 2);
  118. }
  119. function getLongestSide(corners) {
  120. let previous = corners[corners.length - 1];
  121. let max = 0;
  122. for (let i = 0; i < corners.length; i++) {
  123. let current = corners[i];
  124. let length = segmentLength(previous, current);
  125. if (length > max) {
  126. max = length;
  127. }
  128. previous = current;
  129. }
  130. return max;
  131. }
  132. function extractSquare(img, corners) {
  133. let longest = getLongestSide(corners);
  134. let end = longest - 1;
  135. let sourceRect = cv.matFromArray(4, 1, cv.CV_32FC2, [corners[0].x, corners[0].y, corners[1].x, corners[1].y, corners[2].x, corners[2].y, corners[3].x, corners[3].y]);
  136. try {
  137. let destRect = cv.matFromArray(4, 1, cv.CV_32FC2, [0, 0, end, 0, end, end, 0, end]);
  138. try {
  139. let m = cv.getPerspectiveTransform(sourceRect, destRect);
  140. try {
  141. let destImg = new cv.Mat();
  142. try {
  143. cv.warpPerspective(img, destImg, m, new cv.Size(longest, longest));
  144. return destImg;
  145. } catch (err) {
  146. destImg.delete();
  147. throw err;
  148. }
  149. } finally {
  150. m.delete();
  151. }
  152. } finally {
  153. destRect.delete();
  154. }
  155. } finally {
  156. sourceRect.delete();
  157. }
  158. }
  159. function indexOfMax(arr) {
  160. return arr.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);
  161. }
  162. function getFundamentalFrequency(mag) {
  163. mag = mag.slice(0, Math.ceil(mag.length / 2));
  164. mag[0] = 0;
  165. return indexOfMax(mag);
  166. }
  167. function createMatVector(length) {
  168. let vec = new cv.MatVector();
  169. try {
  170. let mat = new cv.Mat();
  171. try {
  172. for (let i = 0; i < length; i++) {
  173. vec.push_back(mat);
  174. }
  175. } finally {
  176. mat.delete();
  177. }
  178. return vec;
  179. } catch (err) {
  180. vec.delete();
  181. throw err;
  182. }
  183. }
  184. function getLineFFT(img, lineDetectorElementSize, axis) {
  185. let lines = new cv.Mat();
  186. try {
  187. morphOpenImage(img, lines, axis === 1 ? new cv.Size(lineDetectorElementSize, 1) : new cv.Size(1, lineDetectorElementSize), 1);
  188. let sums = new cv.Mat();
  189. try {
  190. cv.reduce(lines, sums, axis, cv.REDUCE_SUM, cv.CV_32FC1);
  191. let fft = new cv.Mat();
  192. try {
  193. cv.dft(sums, fft, cv.DFT_COMPLEX_OUTPUT, 0);
  194. return fft;
  195. } catch (err) {
  196. fft.delete();
  197. throw err;
  198. }
  199. } finally {
  200. sums.delete();
  201. }
  202. } finally {
  203. lines.delete();
  204. }
  205. }
  206. function getFFTMagnitude(fft) {
  207. let planes = createMatVector(2);
  208. try {
  209. cv.split(fft, planes);
  210. let real = planes.get(0);
  211. try {
  212. let imag = planes.get(1);
  213. try {
  214. let ret = [];
  215. let length = Math.max(real.cols, real.rows);
  216. for (let i = 0; i < length; i++) {
  217. ret.push(Math.sqrt(real.data32F[i] ** 2 + imag.data32F[i] ** 2))
  218. }
  219. return ret;
  220. } finally {
  221. imag.delete();
  222. }
  223. } finally {
  224. real.delete();
  225. }
  226. } finally {
  227. planes.delete();
  228. }
  229. }
  230. function getLineFrequency(img, lineDetectorElementSize, axis) {
  231. let fft = getLineFFT(img, lineDetectorElementSize, axis);
  232. try {
  233. return getFundamentalFrequency(getFFTMagnitude(fft));
  234. } finally {
  235. fft.delete();
  236. }
  237. }