VideoProcessToolNew.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. package com.izouma.awesomeadmin.util;
  2. import com.izouma.awesomeadmin.service.OSSFileService;
  3. import org.apache.commons.lang3.RandomStringUtils;
  4. import org.apache.commons.lang3.StringUtils;
  5. import org.apache.commons.lang3.time.DateFormatUtils;
  6. import org.bytedeco.javacpp.indexer.UByteRawIndexer;
  7. import org.bytedeco.javacpp.tesseract;
  8. import org.bytedeco.javacv.FFmpegFrameGrabber;
  9. import org.bytedeco.javacv.Frame;
  10. import org.bytedeco.javacv.FrameGrabber;
  11. import org.bytedeco.javacv.OpenCVFrameConverter;
  12. import org.hibernate.validator.internal.util.privilegedactions.GetResource;
  13. import javax.imageio.ImageIO;
  14. import java.awt.image.BufferedImage;
  15. import java.io.ByteArrayInputStream;
  16. import java.io.ByteArrayOutputStream;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.nio.ByteBuffer;
  20. import java.text.SimpleDateFormat;
  21. import java.util.*;
  22. import java.util.regex.Pattern;
  23. import static org.bytedeco.javacpp.lept.pixRead;
  24. import static org.bytedeco.javacpp.opencv_core.*;
  25. import static org.bytedeco.javacpp.opencv_imgcodecs.imencode;
  26. import static org.bytedeco.javacpp.opencv_imgproc.*;
  27. import static org.bytedeco.javacpp.opencv_imgproc.bilateralFilter;
  28. import static org.bytedeco.javacpp.opencv_ml.SVM;
  29. import static org.bytedeco.javacpp.tesseract.PSM_SINGLE_LINE;
  30. public class VideoProcessToolNew {
  31. private OSSFileService ossFileService = new OSSFileService();
  32. public String imgPrefix = "/tmp/";
  33. public Map<String, String> processVideo(String path, int frameSkip) throws FrameGrabber.Exception {
  34. SVM svm = SVM.load(GetResource.class.getClassLoader().getResource("trainneddata/pubg.xml").getPath());
  35. Map<String, String> map = new HashMap<>();
  36. OpenCVFrameConverter.ToMat converterToMat = new OpenCVFrameConverter.ToMat();
  37. long frameCount = 0;
  38. FrameGrabber videoGrabber = new FFmpegFrameGrabber(path);
  39. videoGrabber.start();
  40. Frame vFrame;
  41. do {
  42. vFrame = videoGrabber.grabFrame();
  43. if (vFrame != null) {
  44. frameCount++;
  45. if (frameCount % 200 == 0) {
  46. System.gc();
  47. }
  48. if (frameSkip > 0 && frameCount % frameSkip != 0) {
  49. continue;
  50. }
  51. Mat frame = removeBlackBarAndRotate(converterToMat.convert(vFrame));
  52. if (matchGameOver(svm, frame)) {
  53. Mat filtered = new Mat();
  54. bilateralFilter(frame, filtered, 25, 25 * 2, 25 / 2f);
  55. if (map.get("rank") == null) {
  56. String rank = extractRank(filtered);
  57. if (StringUtils.isNotEmpty(rank))
  58. map.put("rank", rank);
  59. }
  60. if (map.get("total") == null) {
  61. String total = extractTotalNum(filtered);
  62. if (StringUtils.isNotEmpty(total))
  63. map.put("total", total);
  64. }
  65. if (map.get("参赛时间") == null) {
  66. Map<String, String> statistics = getStatistics(filtered);
  67. if (statistics != null)
  68. map.putAll(statistics);
  69. }
  70. filtered.release();
  71. if (map.get("rank") != null
  72. && map.get("total") != null
  73. && map.get("参赛时间") != null
  74. && map.get("评分") != null) {
  75. double score = 0;
  76. double total = 0;
  77. double rank = 0;
  78. try {
  79. score = Double.parseDouble(map.get("评分"));
  80. total = Double.parseDouble(map.get("total"));
  81. rank = Double.parseDouble(map.get("rank").replace("第", ""));
  82. if (score > (total - rank) / total * 100 / 2) {
  83. String filename = "/var/samples/" + DateFormatUtils.format(new Date(), "yyyyMMddHHmmss") + RandomStringUtils.randomNumeric(8) + ".jpg";
  84. org.bytedeco.javacpp.opencv_imgcodecs.imwrite(filename, frame);
  85. map.put("image", uploadImage(frame));
  86. System.out.println(map);
  87. break;
  88. }
  89. } catch (Exception ignore) {
  90. }
  91. }
  92. }
  93. frame.release();
  94. System.out.println(frameCount + " frame processed");
  95. }
  96. } while (vFrame != null);
  97. videoGrabber.stop();
  98. videoGrabber.release();
  99. svm.deallocate();
  100. System.gc();
  101. return map;
  102. }
  103. public boolean matchGameOver(SVM svm, Mat inputImage) {
  104. Mat resized = new Mat();
  105. resize(inputImage, resized, new Size(854, 480));
  106. Mat reshaped = resized.reshape(1, 1);
  107. Mat toPredict = new Mat();
  108. reshaped.convertTo(toPredict, CV_32F);
  109. float res = svm.predict(toPredict);
  110. resized.release();
  111. reshaped.release();
  112. toPredict.release();
  113. return res == 1;
  114. }
  115. public String extractRank(Mat src) {
  116. String result = null;
  117. int m = src.rows();
  118. int n = src.cols();
  119. Mat roi = new Mat(src, new Range(0, (int) (m * 0.093)), new Range((int) (n * 0.44), (int) (n * 0.56)));
  120. imwrite("rank.jpg", roi);
  121. Mat filtered = new Mat(roi.rows(), roi.cols(), CV_8UC1, new Scalar(0));
  122. Mat hsvImg = new Mat();
  123. cvtColor(roi, hsvImg, COLOR_BGR2HSV);
  124. UByteRawIndexer hsvIndexer = hsvImg.createIndexer();
  125. UByteRawIndexer filteredIndexer = filtered.createIndexer();
  126. for (int i = 0; i < roi.rows(); i++) {
  127. for (int j = 0; j < roi.cols(); j++) {
  128. int h = hsvIndexer.get(i, j, 0);
  129. int s = hsvIndexer.get(i, j, 1);
  130. int v = hsvIndexer.get(i, j, 2);
  131. int dh = 0;
  132. if (h > 26) {
  133. dh = h - 26;
  134. } else if (h < 21) {
  135. dh = 21 - h;
  136. }
  137. int ds = 0;
  138. if (s > 161) {
  139. ds = s - 161;
  140. } else if (s < 120) {
  141. ds = 120 - s;
  142. }
  143. int dv = 0;
  144. if (v > 251) {
  145. dv = v - 251;
  146. } else if (v < 238) {
  147. dv = 238 - v;
  148. }
  149. int gray = (int) (255 - Math.min(255, dh * 50)
  150. - Math.min(255, ds * 3)
  151. - Math.min(255, dv * 10));
  152. gray = gray < 0 ? 0 : gray;
  153. // int gray = (h == 26 && Math.abs(s - S) < 50) ? 255 : 0;
  154. filteredIndexer.put(i, j, gray);
  155. }
  156. }
  157. hsvIndexer.release();
  158. hsvImg.release();
  159. filteredIndexer.release();
  160. imwrite("rank_filtered.jpg", filtered);
  161. Mat gray = new Mat();
  162. adaptiveThreshold(filtered, gray, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, 15, 12);
  163. imwrite("rank_gray.jpg", gray);
  164. MatVector contours = new MatVector();
  165. findContours(gray, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
  166. List<Rect> rects = new ArrayList<>();
  167. for (int i = 0; i < contours.size(); i++) {
  168. Mat contour = contours.get(i);
  169. Rect rect = boundingRect(contour);
  170. rects.add(rect);
  171. contour.release();
  172. }
  173. rects.sort((o1, o2) -> o2.area() - o1.area());
  174. for (int i = 0; i < rects.size(); i++) {
  175. Rect rect = rects.get(i);
  176. if (i < 5) {
  177. Mat txtImg = new Mat(filtered, new Range(rect.y(), rect.y() + rect.height()), new Range(rect.x(), rect.x() + rect.width()));
  178. String str = doOCR(txtImg);
  179. txtImg.release();
  180. System.out.println(str);
  181. if (str != null) {
  182. str = str.replaceAll("[ \n]", "");
  183. if (Pattern.matches("^第\\d{1,3}$", str)) {
  184. result = str;
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. filtered.release();
  191. gray.release();
  192. roi.release();
  193. return result;
  194. }
  195. public String extractTotalNum(Mat src) {
  196. String result = null;
  197. int m = src.rows();
  198. int n = src.cols();
  199. Mat roi = new Mat(src, new Range(0, (int) (m * 0.08)), new Range((int) (n * 0.42), (int) (n * 0.58)));
  200. imwrite("total.png", roi);
  201. Mat totalFiltered = new Mat(roi.rows(), roi.cols(), CV_8UC1, new Scalar(0));
  202. Mat hsvImg = new Mat();
  203. cvtColor(roi, hsvImg, COLOR_BGR2HSV);
  204. UByteRawIndexer hsvIndexer = hsvImg.createIndexer();
  205. UByteRawIndexer resultIndexer = totalFiltered.createIndexer();
  206. for (int i = 0; i < roi.rows(); i++) {
  207. for (int j = 0; j < roi.cols(); j++) {
  208. int h = hsvIndexer.get(i, j, 0);
  209. int s = hsvIndexer.get(i, j, 1);
  210. int v = hsvIndexer.get(i, j, 2);
  211. int gray = 255 - 2 * s;
  212. gray = gray < 0 ? 0 : gray;
  213. resultIndexer.put(i, j, gray);
  214. }
  215. }
  216. hsvIndexer.release();
  217. hsvImg.release();
  218. resultIndexer.release();
  219. imwrite("total_filtered.png", totalFiltered);
  220. Mat gray = new Mat();
  221. adaptiveThreshold(totalFiltered, gray, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, 15, 12);
  222. imwrite("rank_gray.jpg", gray);
  223. MatVector contours = new MatVector();
  224. findContours(gray, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
  225. List<Rect> rects = new ArrayList<>();
  226. for (int i = 0; i < contours.size(); i++) {
  227. Mat contour = contours.get(i);
  228. Rect rect = boundingRect(contour);
  229. rects.add(rect);
  230. contour.release();
  231. }
  232. rects.sort((o1, o2) -> o2.area() - o1.area());
  233. for (int i = 0; i < rects.size(); i++) {
  234. Rect rect = rects.get(i);
  235. if (i < 5) {
  236. Mat txtImg = new Mat(totalFiltered, new Range(rect.y(), rect.y() + rect.height()), new Range(rect.x(), rect.x() + rect.width()));
  237. String str = doOCR(txtImg);
  238. txtImg.release();
  239. if (str != null) {
  240. str = str.replaceAll("[ \n]", "");
  241. if (Pattern.matches("^/\\d{1,3}$", str)) {
  242. result = str.replace("/", "");
  243. break;
  244. }
  245. }
  246. }
  247. }
  248. totalFiltered.release();
  249. gray.release();
  250. System.out.println(result);
  251. return result;
  252. }
  253. public String extractMode(Mat src) {
  254. String result = null;
  255. int m = src.rows();
  256. int n = src.cols();
  257. Mat roi = new Mat(src, new Range(0, (int) (m * 0.065)), new Range(0, (int) (n * 0.2)));
  258. imwrite("mode.png", roi);
  259. Mat filtered = new Mat(roi.rows(), roi.cols(), CV_8UC1, new Scalar(0));
  260. Mat hsvImg = new Mat();
  261. cvtColor(roi, hsvImg, COLOR_BGR2HSV);
  262. UByteRawIndexer hsvIndexer = hsvImg.createIndexer();
  263. UByteRawIndexer bgrIndexer = roi.createIndexer();
  264. UByteRawIndexer resultIndexer = filtered.createIndexer();
  265. for (int i = 0; i < roi.rows(); i++) {
  266. for (int j = 0; j < roi.cols(); j++) {
  267. int h = hsvIndexer.get(i, j, 0);
  268. int s = hsvIndexer.get(i, j, 1);
  269. int v = hsvIndexer.get(i, j, 2);
  270. int b = bgrIndexer.get(i, j, 0);
  271. int g = bgrIndexer.get(i, j, 1);
  272. int r = bgrIndexer.get(i, j, 2);
  273. int dr = Math.abs(r - 220);
  274. int dg = Math.abs(g - 220);
  275. int db = Math.abs(b - 220);
  276. int dbgr = Math.abs(b - g) + Math.abs(b - r) + Math.abs(r - g);
  277. int gray = (int) (255 - Math.pow(dr, 2) * 0.015 - Math.pow(dg, 2) * 0.015 - Math.pow(db, 2) * 0.015 - Math.pow(dbgr, 2) * 0.015);
  278. // gray = (int) (gray / 128f * 255);
  279. // gray = 255 - Math.abs(gray - 200) * 2;
  280. if (gray > 220) {
  281. gray = 0;
  282. } else if (gray > 190) {
  283. gray = 220 - 190;
  284. } else {
  285. gray = 255;
  286. }
  287. resultIndexer.put(i, j, gray);
  288. }
  289. }
  290. hsvIndexer.release();
  291. bgrIndexer.release();
  292. hsvImg.release();
  293. resultIndexer.release();
  294. imwrite("mode_filtered.png", filtered);
  295. result = doOCR(filtered, "chi_sim");
  296. if (StringUtils.isNotEmpty(result)) {
  297. result = result.replace(" ", "").replace("\n", "");
  298. }
  299. System.out.println(result);
  300. filtered.release();
  301. roi.release();
  302. return result;
  303. }
  304. public Map<String, String> getStatistics(Mat src) {
  305. imwrite("time.jpg", src);
  306. int m = src.rows();
  307. int n = src.cols();
  308. Mat roi = new Mat(src, new Range((int) (m * 0.569), (int) (m * 0.625)), new Range((int) (n * 0.3), (int) (n * 0.8)));
  309. Mat filtered = timeFilter(roi);
  310. imwrite("time_filtered.jpg", filtered);
  311. Map<String, String> map = new HashMap<>();
  312. Rect[] rects = {
  313. new Rect(0, 0, (int) (filtered.cols() * 0.128), filtered.rows()),
  314. // new Rect((int) (filtered.cols() * 0.128), 0, (int) (filtered.cols() * 0.128), filtered.rows()),
  315. new Rect((int) (filtered.cols() * 0.256), 0, (int) (filtered.cols() * 0.162), filtered.rows()),
  316. // new Rect((int) (filtered.cols() * 0.428), 0, (int) (filtered.cols() * 0.114), filtered.rows()),
  317. // new Rect((int) (filtered.cols() * 0.542), 0, (int) (filtered.cols() * 0.1), filtered.rows()),
  318. // new Rect((int) (filtered.cols() * 0.642), 0, (int) (filtered.cols() * 0.1), filtered.rows()),
  319. new Rect((int) (filtered.cols() * 0.742), 0, (int) (filtered.cols() * 0.1), filtered.rows())
  320. };
  321. String[] names = {
  322. "淘汰",
  323. // "伤害",
  324. "参赛时间",
  325. // "治疗量",
  326. // "救援",
  327. // "助攻",
  328. "评分"
  329. };
  330. int i = 0;
  331. for (Rect rect : rects) {
  332. Mat txtImg = new Mat(filtered, new Range(rect.y(), rect.y() + rect.height()), new Range(rect.x(), rect.x() + rect.width()));
  333. Rect rect1 = boundingRect(txtImg);
  334. int y1 = rect1.y() - 5;
  335. y1 = y1 < 0 ? 0 : y1;
  336. int y2 = rect1.y() + rect1.height() + 5;
  337. y2 = y2 > (txtImg.rows() - 1) ? (txtImg.rows() - 1) : y2;
  338. int x1 = rect1.x() - 5;
  339. x1 = x1 < 0 ? 0 : x1;
  340. int x2 = rect1.x() + rect1.width() + 5;
  341. x2 = x2 > (txtImg.cols() - 1) ? (txtImg.cols() - 1) : x2;
  342. txtImg = txtImg.rowRange(y1, y2).colRange(x1, x2);
  343. bitwise_not(txtImg, txtImg);
  344. resize(txtImg, txtImg, new Size(0, 0), 3, 3, INTER_LINEAR);
  345. String str = doOCR(txtImg);
  346. if (StringUtils.isNotEmpty(str)) {
  347. str = str.replaceAll("[ \n]", "");
  348. }
  349. map.put(names[i], str);
  350. System.out.println(names[i] + str);
  351. imwrite(names[i] + ".png", txtImg);
  352. i++;
  353. }
  354. filtered.release();
  355. roi.release();
  356. if (Pattern.matches("((^([0-9]+[.][0-9]*))|(^\\d{1,2}))分钟", map.get("参赛时间")) &&
  357. Pattern.matches("((^([0-9]+[.][0-9]+)$)|(^\\d{1,2})$)", map.get("评分"))) {
  358. try {
  359. double score = Double.parseDouble(map.get("评分"));
  360. double time = Double.parseDouble(map.get("参赛时间").replace("分钟", ""));
  361. if (score >= 0 && score <= 100 && time >= 0 && time <= 45) {
  362. return map;
  363. }
  364. } catch (Exception ignored) {
  365. }
  366. }
  367. return null;
  368. }
  369. public Mat timeFilter(Mat src) {
  370. int b = 27;
  371. int g = 145;
  372. int r = 211;
  373. int hmin = 28;
  374. int hmax = 28;
  375. int smin = 145;
  376. int smax = 145;
  377. int vmin = 160;
  378. int vmax = 160;
  379. Mat result = new Mat(src.rows(), src.cols(), CV_8UC1, new Scalar(0));
  380. Mat hsvImg = new Mat();
  381. cvtColor(src, hsvImg, COLOR_BGR2HSV);
  382. UByteRawIndexer hsvIndexer = hsvImg.createIndexer();
  383. UByteRawIndexer srcIndexer = src.createIndexer();
  384. UByteRawIndexer resultIndexer = result.createIndexer();
  385. for (int i = 0; i < src.rows(); i++) {
  386. for (int j = 0; j < src.cols(); j++) {
  387. int db = Math.abs(srcIndexer.get(i, j, 0) - b);
  388. int dg = Math.abs(srcIndexer.get(i, j, 1) - g);
  389. int dr = Math.abs(srcIndexer.get(i, j, 2) - r);
  390. int h = hsvIndexer.get(i, j, 0);
  391. int s = hsvIndexer.get(i, j, 1);
  392. int v = hsvIndexer.get(i, j, 2);
  393. int dh = h > hmax ? (h - hmax) : (h < hmin ? (hmin - h) : 0);
  394. int ds = s > smax ? (s - smax) : (s < smin ? (smin - s) : 0);
  395. int dv = v > vmax ? (v - vmax) : (v < vmin ? (vmin - v) : 0);
  396. int gray = 255 - (db * 0 + dg * 3 + dr * 2);
  397. // int gray = 255 - dh * 2 - ds * 2 - dv* 2;
  398. if (gray < 0) gray = 0;
  399. if (gray > 255) gray = 255;
  400. gray *= 1.2;
  401. if (gray > 255) gray = 255;
  402. resultIndexer.put(i, j, gray);
  403. }
  404. }
  405. hsvImg.release();
  406. hsvIndexer.release();
  407. srcIndexer.release();
  408. resultIndexer.release();
  409. return result;
  410. }
  411. private String doOCR(Mat img) {
  412. return doOCR(img, "pubg");
  413. }
  414. private String doOCR(Mat img, String lang) {
  415. imwrite("text.jpg", img);
  416. final tesseract.TessBaseAPI baseApi = new tesseract.TessBaseAPI();
  417. baseApi.Init(GetResource.class.getClassLoader().getResource("trainneddata").getPath(), lang);
  418. baseApi.SetPageSegMode(PSM_SINGLE_LINE);
  419. baseApi.SetImage(pixRead(imgPrefix + "text.jpg"));
  420. String recognizedText = baseApi.GetUTF8Text().getString();
  421. return recognizedText == null ? "" : recognizedText;
  422. }
  423. public Mat removeBlackBarAndRotate(Mat src) {
  424. if (src.cols() < src.rows()) {
  425. rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);
  426. }
  427. Mat gray = new Mat();
  428. cvtColor(src, gray, COLOR_BGR2GRAY);
  429. threshold(gray, gray, 2, 255, THRESH_BINARY);
  430. Rect rect = boundingRect(gray);
  431. Mat dst = new Mat(src, new Range(rect.y(), rect.y() + rect.height()), new Range(rect.x(), rect.x() + rect.width()));
  432. src.release();
  433. gray.release();
  434. rect.deallocate();
  435. return dst;
  436. }
  437. public BufferedImage createBufferedImage(Mat mat) {
  438. ByteBuffer byteBuffer = ByteBuffer.allocate(mat.cols() * mat.rows());
  439. imencode(".jpg", mat, byteBuffer);
  440. byte[] ba = byteBuffer.array();
  441. BufferedImage bi = null;
  442. try {
  443. bi = ImageIO.read(new ByteArrayInputStream(ba));
  444. } catch (IOException e) {
  445. e.printStackTrace();
  446. }
  447. return bi;
  448. }
  449. public String uploadImage(Mat frame) {
  450. try {
  451. BufferedImage image = createBufferedImage(frame);
  452. ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
  453. ImageIO.write(image, "png", baos);//写入流中
  454. byte[] bytes = baos.toByteArray();//转换成字节
  455. InputStream in = new ByteArrayInputStream(bytes);
  456. String path = String.format("images/%s-%s.jpg", new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss").format(new Date()), UUID.randomUUID().toString());
  457. return ossFileService.upload(in, path);
  458. } catch (IOException e) {
  459. e.printStackTrace();
  460. }
  461. return null;
  462. }
  463. private void imwrite(String name, Mat img) {
  464. org.bytedeco.javacpp.opencv_imgcodecs.imwrite(imgPrefix + name, img);
  465. }
  466. }