From b0975b880ede82de639f61001f12b3e60d287d11 Mon Sep 17 00:00:00 2001 From: yuxue Date: Sat, 30 May 2020 00:42:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=99=8D=E5=99=AA=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/yuxue/train/SVMTrain.java | 2 +- src/main/java/com/yuxue/util/ImageUtil.java | 409 +++++++++++++------- 2 files changed, 261 insertions(+), 150 deletions(-) diff --git a/src/main/java/com/yuxue/train/SVMTrain.java b/src/main/java/com/yuxue/train/SVMTrain.java index 98effbd6..9290df93 100644 --- a/src/main/java/com/yuxue/train/SVMTrain.java +++ b/src/main/java/com/yuxue/train/SVMTrain.java @@ -52,7 +52,7 @@ public class SVMTrain { public static void main(String[] arg) { // 训练, 生成svm.xml库文件 - train(); + // train(); // 识别,判断样本文件是否是车牌 pridect(); diff --git a/src/main/java/com/yuxue/util/ImageUtil.java b/src/main/java/com/yuxue/util/ImageUtil.java index f84e3cb8..d7bbe75d 100644 --- a/src/main/java/com/yuxue/util/ImageUtil.java +++ b/src/main/java/com/yuxue/util/ImageUtil.java @@ -1,8 +1,11 @@ package com.yuxue.util; +import java.time.Duration; +import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.Vector; @@ -41,33 +44,38 @@ public class ImageUtil { private static Map debugMap = Maps.newLinkedHashMap(); static { debugMap.put("yuantu", 0); // 原图 - debugMap.put("gaussianBlur", 1); // 高斯模糊 - debugMap.put("gray", 2); // 图像灰度化 - debugMap.put("sobel", 3); // Sobel 运算,得到图像的一阶水平方向导数 - debugMap.put("threshold", 4); //图像二值化 - debugMap.put("morphology", 5); // 图像闭操作 - debugMap.put("clearSmallConnArea", 6); // 降噪 - debugMap.put("clearAngleConn", 7); // 降噪 - debugMap.put("clearHole", 8); // 降噪 - - - debugMap.put("contours", 9); // 提取外部轮廓 - debugMap.put("screenblock", 10); // 外部轮廓筛选 - debugMap.put("crop", 11); // 切图 - debugMap.put("resize", 12); // 切图resize - - // debugMap.put("char_threshold", 10); - // debugMap.put("char_clearLiuDing", 11); // 去除柳钉 - // debugMap.put("specMat", 12); - // debugMap.put("chineseMat", 13); - // debugMap.put("char_auxRoi", 14); + debugMap.put("gaussianBlur", 0); // 高斯模糊 + debugMap.put("gray", 0); // 图像灰度化 + debugMap.put("sobel", 0); // Sobel 运算,得到图像的一阶水平方向导数 + debugMap.put("threshold", 0); //图像二值化 + debugMap.put("morphology", 0); // 图像闭操作 + debugMap.put("clearInnerHole", 0); // 降噪 + debugMap.put("clearSmallConnArea", 0); // 降噪 + debugMap.put("clearAngleConn", 0); // 降噪 + debugMap.put("clearHole", 0); // 降噪 + debugMap.put("contours", 0); // 提取外部轮廓 + debugMap.put("screenblock", 0); // 外部轮廓筛选 + debugMap.put("crop", 0); // 切图 + debugMap.put("resize", 0); // 切图resize + debugMap.put("char_threshold", 0); + debugMap.put("char_clearLiuDing", 0); // 去除柳钉 + debugMap.put("specMat", 0); + debugMap.put("chineseMat", 0); + debugMap.put("char_auxRoi", 0); + + // 设置index, 用于debug生成文件时候按名称排序 + Integer index = 100; + for (Entry entry : debugMap.entrySet()) { + entry.setValue(index); + index ++; + } } public static void main(String[] args) { - + Instant start = Instant.now(); String tempPath = DEFAULT_BASE_TEST_PATH + "test/"; String filename = tempPath + "/100_yuantu.jpg"; - // filename = tempPath + "/100_yuantu4.jpg"; + filename = tempPath + "/100_yuantu4.jpg"; // filename = tempPath + "/109_crop_0.png"; Mat src = Imgcodecs.imread(filename); @@ -97,7 +105,9 @@ public class ImageUtil { // ImageUtil.rgb2Hsv(src, debug, tempPath); // ImageUtil.getHSVValue(src, debug, tempPath); - System.err.println("done!!!"); + Instant end = Instant.now(); + System.err.println("总耗时:" + Duration.between(start, end).toMillis()); + } @@ -113,7 +123,7 @@ public class ImageUtil { Mat dst = new Mat(); Imgproc.GaussianBlur(inMat, dst, new Size(DEFAULT_GAUSSIANBLUR_SIZE, DEFAULT_GAUSSIANBLUR_SIZE), 0, 0, Core.BORDER_DEFAULT); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("gaussianBlur") + 100) + "_gaussianBlur.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("gaussianBlur") + "_gaussianBlur.jpg", dst); } return dst; } @@ -130,7 +140,7 @@ public class ImageUtil { Mat dst = new Mat(); Imgproc.cvtColor(inMat, dst, Imgproc.COLOR_BGR2GRAY); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("gray") + 100) + "_gray.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("gray") + "_gray.jpg", dst); } inMat.release(); return dst; @@ -170,7 +180,7 @@ public class ImageUtil { abs_grad_y.release(); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("sobel") + 100) + "_sobel.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("sobel") + "_sobel.jpg", dst); } return dst; } @@ -207,7 +217,7 @@ public class ImageUtil { abs_grad_x.release(); abs_grad_y.release(); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("sobel") + 100) + "_sobel.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("sobel") + "_sobel.jpg", dst); } return dst; } @@ -225,7 +235,7 @@ public class ImageUtil { Mat dst = new Mat(); Imgproc.threshold(inMat, dst, 100, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("threshold") + 100) + "_threshold.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("threshold") + "_threshold.jpg", dst); } inMat.release(); return dst; @@ -249,23 +259,22 @@ public class ImageUtil { Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, size); Imgproc.morphologyEx(inMat, dst, Imgproc.MORPH_CLOSE, element); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("morphology") + 100) + "_morphology0.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("morphology") + "_morphology0.jpg", dst); } + // 填补内部孔洞,为了去除小连通区域的时候,降低影响 + Mat a = clearInnerHole(dst, 8, 16, debug, tempPath); + // 去除小连通区域 - Mat a = clearSmallConnArea(dst, 3, 10, debug, tempPath); - Mat b = clearSmallConnArea(a, 10, 3, debug, tempPath); + Mat b = clearSmallConnArea(a, 1, 10, debug, tempPath); + // 按斜边去除 - // Mat e = clearSmallConnArea(b, 2, debug, tempPath); - - // 去除孔洞 - Mat c = clearHole(b, 3, 10, debug, tempPath); - Mat d = clearHole(c, 10, 3, debug, tempPath); + // Mat e = clearAngleConn(b, 5, debug, tempPath); - if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("morphology") + 100) + "_morphology2.jpg", d); - } - return d; + // 填补边缘孔洞 + // Mat d = clearHole(a, 4, 2, debug, tempPath); + + return b; } @@ -294,7 +303,7 @@ public class ImageUtil { // 将轮廓描绘到原图 Imgproc.drawContours(result, contours, -1, new Scalar(0, 0, 255, 255)); // 输出带轮廓的原图 - Imgcodecs.imwrite(tempPath + (debugMap.get("contours") + 100) + "_contours.jpg", result); + Imgcodecs.imwrite(tempPath + debugMap.get("contours") + "_contours.jpg", result); } return contours; } @@ -343,13 +352,13 @@ public class ImageUtil { Mat img_crop = new Mat(); Imgproc.getRectSubPix(src, rect_size, mr.center, img_crop); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("crop") + 100) + "_crop_" + j + ".png", img_crop); + Imgcodecs.imwrite(tempPath + debugMap.get("crop") + "_crop_" + j + ".png", img_crop); } // 处理切图,调整为指定大小 Mat resized = new Mat(HEIGHT, WIDTH, TYPE); Imgproc.resize(img_crop, resized, resized.size(), 0, 0, Imgproc.INTER_CUBIC); if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("resize") + 100) + "_resize_" + j + ".png", resized); + Imgcodecs.imwrite(tempPath + debugMap.get("resize") + "_resize_" + j + ".png", resized); j++; } dst.add(resized); @@ -361,7 +370,7 @@ public class ImageUtil { // 将轮廓描绘到原图 Imgproc.drawContours(result, mv, -1, new Scalar(0, 0, 255, 255)); // 输出带轮廓的原图 - Imgcodecs.imwrite(tempPath + (debugMap.get("screenblock") + 100) + "_screenblock.jpg", result); + Imgcodecs.imwrite(tempPath + debugMap.get("screenblock") + "_screenblock.jpg", result); } return dst; } @@ -548,6 +557,95 @@ public class ImageUtil { } } + + /** + * 清除白色区域的内部黑色孔洞 + * rowLimit != colsLimit, 使用长方形比正方形好 + * 该算法比较耗时 + * @param inMat + * @param rowLimit + * @param colsLimit + * @param debug + * @param tempPath + * @return + */ + public static Mat clearInnerHole(Mat inMat, int rowLimit, int colsLimit, Boolean debug, String tempPath) { + Instant start = Instant.now(); + int uncheck = 0, normal = 2, replace = 3, white = 255, black = 0; + + Mat dst = new Mat(inMat.size(), CvType.CV_8UC1); + inMat.copyTo(dst); + + // 初始化的图像全部为0,未检查; 全黑图像 + Mat label = new Mat(inMat.size(), CvType.CV_8UC1); + + // 标记所有的白色区域 + for (int i = 0; i < inMat.rows(); i++) { + for (int j = 0; j < inMat.cols(); j++) { + // 白色点较少,遍历白色点速度快 + if (inMat.get(i, j)[0] == white && label.get(i, j)[0] == uncheck) { // 对于二值图,0代表黑色,255代表白色 + label.put(i, j, normal); // 中心点 + + // 执行两次,交换row 跟col; + int condition = 0; + do { + int x1 = i; + int x2 = i + rowLimit >= inMat.rows() ? inMat.rows() - 1 : i + rowLimit; + int y1 = j; + int y2 = j + colsLimit >= inMat.cols() ? inMat.cols() - 1 : j + colsLimit ; + + int count = 0; + // 遍历四条边 + for (int k = x1; k < x2; k++) { + if(inMat.get(k, y1)[0] == black || inMat.get(k, y2)[0] == black) { + count++; + } + } + for (int k = y1; k < y2; k++) { + if(inMat.get(x1, k)[0] == black || inMat.get(x2, k)[0] == black) { + count++; + } + } + + // 根据中心点+limit,定位四个角生成一个矩形, + // 矩形四条边都是白色,内部的黑点标记为 要被替换的对象 + if(count == 0 ) { + for (int n = x1; n < x2; n++) { + for (int m = y1; m < y2; m++) { + if (inMat.get(n, m)[0] == black && label.get(n, m)[0] == uncheck) { + label.put(n, m, replace); + } + } + } + } + int ex = rowLimit; + rowLimit = colsLimit; + colsLimit = ex; + + condition++; + } while (condition == 1); + } + } + } + + + for (int i = 0; i < inMat.rows(); i++) { + for (int j = 0; j < inMat.cols(); j++) { + if(label.get(i, j)[0] == replace) { + dst.put(i, j, white); + } + } + } + label.release(); + if (debug) { + Imgcodecs.imwrite(tempPath + debugMap.get("clearInnerHole") + "_clearInnerHole.jpg", dst); + Instant end = Instant.now(); + System.out.println("clearInnerHole执行耗时:" + Duration.between(start, end).toMillis()); + } + return dst; + } + + /** * 清除二值图像的黑洞 * 按矩形清理 @@ -558,8 +656,8 @@ public class ImageUtil { * @param tempPath */ public static Mat clearHole(Mat inMat, int rowLimit, int colsLimit, Boolean debug, String tempPath) { - int uncheck = 0, black = 1, white = 2; - + Instant start = Instant.now(); + int uncheck = 0, normal = 2, replace = 3, white = 255, black = 0; Mat dst = new Mat(inMat.size(), CvType.CV_8UC1); inMat.copyTo(dst); @@ -569,53 +667,64 @@ public class ImageUtil { // 标记所有的白色区域 for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if (inMat.get(i, j)[0] > 10) { // 对于二值图,0代表黑色,255代表白色 - label.put(i, j, white); // 中心点 - - int x1 = i - rowLimit < 0 ? 0 : i - rowLimit; - int x2 = i + rowLimit >= inMat.rows() ? inMat.rows()-1 : i + rowLimit; - int y1 = j - colsLimit < 0 ? 0 : j - colsLimit ; - int y2 = j + colsLimit >= inMat.cols() ? inMat.cols()-1 : j + colsLimit ; - - int count = 0; - if(inMat.get(x1, y1)[0] > 10) {// 左上角 - count++; - } - if(inMat.get(x1, y2)[0] > 10) { // 左下角 - count++; - } - if(inMat.get(x2, y1)[0] > 10) { // 右上角 - count++; - } - if(inMat.get(x2, y2)[0] > 10) { // 右下角 - count++; - } + if (inMat.get(i, j)[0] == white) { // 对于二值图,0代表黑色,255代表白色 + label.put(i, j, normal); // 中心点 + + // 执行两次,交换row 跟col; + int condition = 0; + do { + int x1 = i; + int x2 = i + rowLimit >= inMat.rows() ? inMat.rows() - 1 : i + rowLimit; + int y1 = j; + int y2 = j + colsLimit >= inMat.cols() ? inMat.cols() - 1 : j + colsLimit ; + + int count = 0; + if(inMat.get(x1, y1)[0] == white) {// 左上角 + count++; + } + if(inMat.get(x1, y2)[0] == white) { // 左下角 + count++; + } + if(inMat.get(x2, y1)[0] == white) { // 右上角 + count++; + } + if(inMat.get(x2, y2)[0] == white) { // 右下角 + count++; + } - // 根据中心点+limit,定位四个角生成一个矩形, - // 将四个角都是白色的矩形,内部的黑点标记为 要被替换的对象 - if(count >=4 ) { - for (int n = x1; n < x2; n++) { - for (int m = y1; m < y2; m++) { - if (inMat.get(n, m)[0] < 10 && label.get(n, m)[0] == uncheck) { - label.put(n, m, black); + // 根据中心点+limit,定位四个角生成一个矩形, + // 将四个角都是白色的矩形,内部的黑点标记为 要被替换的对象 + if(count >=4 ) { + for (int n = x1; n < x2; n++) { + for (int m = y1; m < y2; m++) { + if (inMat.get(n, m)[0] == black && label.get(n, m)[0] == uncheck) { + label.put(n, m, replace); + } } } } - } + + int ex = rowLimit; + rowLimit = colsLimit; + colsLimit = ex; + + condition++; + } while (condition == 1); } } } - // 黑色替换成白色 for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if(label.get(i, j)[0] == black) { - dst.put(i, j, 255); + if(label.get(i, j)[0] == replace) { + dst.put(i, j, white); // 黑色替换成白色 } } } if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("clearHole") + 100) + "_clearHole.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("clearHole") + "_clearHole.jpg", dst); + Instant end = Instant.now(); + System.out.println("clearHole执行耗时:" + Duration.between(start, end).toMillis()); } return dst; } @@ -631,7 +740,8 @@ public class ImageUtil { * @return */ public static Mat clearSmallConnArea(Mat inMat, int rowLimit, int colsLimit, Boolean debug, String tempPath) { - int uncheck = 0, black = 1, white = 2; + Instant start = Instant.now(); + int uncheck = 0, normal = 2, replace = 3, white = 255, black = 0; Mat dst = new Mat(inMat.size(), CvType.CV_8UC1); inMat.copyTo(dst); @@ -642,57 +752,67 @@ public class ImageUtil { // 标记所有的白色区域 for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if (inMat.get(i, j)[0] < 10) { // 对于二值图,0代表黑色,255代表白色 - label.put(i, j, black); // 中心点 - - int x1 = i - rowLimit < 0 ? 0 : i - rowLimit; - int x2 = i + rowLimit >= inMat.rows() ? inMat.rows()-1 : i + rowLimit; - int y1 = j - colsLimit < 0 ? 0 : j - colsLimit ; - int y2 = j + colsLimit >= inMat.cols() ? inMat.cols()-1 : j + colsLimit ; - - int count = 0; - if(inMat.get(x1, y1)[0] < 10) {// 左上角 - count++; - } - if(inMat.get(x1, y2)[0] < 10) { // 左下角 - count++; - } - if(inMat.get(x2, y1)[0] < 10) { // 右上角 - count++; - } - if(inMat.get(x2, y2)[0] < 10) { // 右下角 - count++; - } + if (inMat.get(i, j)[0] == black) { // 对于二值图,0代表黑色,255代表白色 + label.put(i, j, normal); // 中心点 + // 执行两次,交换row 跟col; + int condition = 0; + do { + int x1 = i; + int x2 = i + rowLimit >= inMat.rows() ? inMat.rows() - 1 : i + rowLimit; + int y1 = j; + int y2 = j + colsLimit >= inMat.cols() ? inMat.cols() - 1 : j + colsLimit ; + + int count = 0; + if(inMat.get(x1, y1)[0] == black) {// 左上角 + count++; + } + if(inMat.get(x1, y2)[0] == black) { // 左下角 + count++; + } + if(inMat.get(x2, y1)[0] == black) { // 右上角 + count++; + } + if(inMat.get(x2, y2)[0] == black) { // 右下角 + count++; + } - // 根据 中心点+limit,定位四个角生成一个矩形, - // 将四个角都是黑色的矩形,内部的白点标记为 要被替换的对象 - if(count >= 4) { - for (int n = x1; n < x2; n++) { - for (int m = y1; m < y2; m++) { - if (inMat.get(n, m)[0] > 10 && label.get(n, m)[0] == uncheck) { - label.put(n, m, white); + // 根据 中心点+limit,定位四个角生成一个矩形, + // 将四个角都是黑色的矩形,内部的白点标记为 要被替换的对象 + if(count >= 4) { + for (int n = x1; n < x2; n++) { + for (int m = y1; m < y2; m++) { + if (inMat.get(n, m)[0] == white && label.get(n, m)[0] == uncheck) { + label.put(n, m, replace); + } } } } - } + int ex = rowLimit; + rowLimit = colsLimit; + colsLimit = ex; + + condition++; + } while (condition == 1); } } } - // 白色替换成黑色 + for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if(label.get(i, j)[0] == white) { - dst.put(i, j, 0); + if(label.get(i, j)[0] == replace) { + dst.put(i, j, black); // 白色替换成黑色 } } } if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("clearSmallConnArea") + 100) + "_clearSmallConnArea.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("clearSmallConnArea") + "_clearSmallConnArea.jpg", dst); + Instant end = Instant.now(); + System.out.println("clearSmallConnArea执行耗时:" + Duration.between(start, end).toMillis()); } return dst; } - + /** * 清除二值图像的细小连接 * 按45度斜边清除 @@ -703,8 +823,9 @@ public class ImageUtil { * @param tempPath * @return */ - public static Mat clearSmallConnArea(Mat inMat, int limit, Boolean debug, String tempPath) { - int uncheck = 0, black = 1, white = 2; + public static Mat clearAngleConn(Mat inMat, int limit, Boolean debug, String tempPath) { + Instant start = Instant.now(); + int uncheck = 0, normal = 2, replace = 3, white = 255, black = 0; Mat dst = new Mat(inMat.size(), CvType.CV_8UC1); inMat.copyTo(dst); @@ -715,58 +836,48 @@ public class ImageUtil { // 标记所有的白色区域 for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if (inMat.get(i, j)[0] < 10) { // 对于二值图,0代表黑色,255代表白色 - label.put(i, j, black); // 中心点 + if (inMat.get(i, j)[0] == black) { // 对于二值图,0代表黑色,255代表白色 + label.put(i, j, normal); // 中心点 - int x1 = i - limit < 0 ? 0 : i - limit; - int x2 = i + limit >= inMat.rows() ? inMat.rows()-1 : i + limit; - int y1 = j - limit < 0 ? 0 : j - limit ; - int y2 = j + limit >= inMat.cols() ? inMat.cols()-1 : j + limit ; + int x1 = i; + int x2 = i + limit >= inMat.rows() ? inMat.rows() - 1 : i + limit; + int y1 = j; + int y2 = j + limit >= inMat.cols() ? inMat.cols() - 1 : j + limit ; - int count = 0; - if(inMat.get(x1, y1)[0] < 10) {// 左上角 - count++; - } - if(inMat.get(x1, y2)[0] < 10) { // 左下角 - count++; - } - if(inMat.get(x2, y1)[0] < 10) { // 右上角 - count++; - } - if(inMat.get(x2, y2)[0] < 10) { // 右下角 - count++; - } - // 根据 中心点+limit,定位四个角生成一个矩形, // 将2个角都是黑色的线,内部的白点标记为 要被替换的对象 - if(count == 2) { - // 【\】 斜对角线 - for (int n = x1, m = y1; n < x2; n++, m++) { - if (inMat.get(n, m)[0] > 10 && label.get(n, m)[0] == uncheck) { - label.put(n, m, white); + // 【\】 斜对角线 + if(inMat.get(x1, y1)[0] == black && inMat.get(x2, y2)[0] == black) { + for (int n = x1, m = y1; n < x2 && m < y2; n++, m++) { + if (inMat.get(n, m)[0] == white && label.get(n, m)[0] == uncheck) { + label.put(n, m, replace); } } + } + if(inMat.get(x1, y2)[0] == black && inMat.get(x2, y1)[0] == black) { // 【/】 斜对角线 - for (int n = x1, m = y2; n < x2; n++, m--) { - if (inMat.get(n, m)[0] > 10 && label.get(n, m)[0] == uncheck) { - label.put(n, m, white); + for (int n = x1, m = y2; n < x2 && m > y1; n++, m--) { + if (inMat.get(n, m)[0] == white && label.get(n, m)[0] == uncheck) { + label.put(n, m, replace); } } } } } } - // 白色替换成黑色 + // 白色替换成黑色 for (int i = 0; i < inMat.rows(); i++) { for (int j = 0; j < inMat.cols(); j++) { - if(label.get(i, j)[0] == white) { - dst.put(i, j, 0); + if(label.get(i, j)[0] == replace) { + dst.put(i, j, black); } } } - + if (debug) { - Imgcodecs.imwrite(tempPath + (debugMap.get("clearAngleConn") + 100) + "_clearAngleConn.jpg", dst); + Imgcodecs.imwrite(tempPath + debugMap.get("clearAngleConn") + "_clearAngleConn.jpg", dst); + Instant end = Instant.now(); + System.out.println("clearAngleConn执行耗时:" + Duration.between(start, end).toMillis()); } return dst; }