diff --git a/.classpath b/.classpath index 481b25f4057e2add50feaa9fb2664155a4d31594..136685672d01d4c8354c99513a8711750df586e3 100644 --- a/.classpath +++ b/.classpath @@ -1,19 +1,20 @@ + + + + - - - - + diff --git a/pom.xml b/pom.xml index 2f09fb010481cb29ba77ece314edfe25340e839a..ee04f5ebadc16d2746742e8c3d163be4368ee0c6 100644 --- a/pom.xml +++ b/pom.xml @@ -38,11 +38,5 @@ poi-ooxml 4.1.2 - - - org.openpnp - opencv - 4.3.0-2 - \ No newline at end of file diff --git a/src/test/java/com/hy/java/uct/umlrecog/OpenCVTest.java b/src/test/java/com/hy/java/uct/umlrecog/OpenCVTest.java index ea86df7832f1b06d78073283c84a726653db9b8e..fb1f370aa52230dccad6eddf7791f478e948508a 100644 --- a/src/test/java/com/hy/java/uct/umlrecog/OpenCVTest.java +++ b/src/test/java/com/hy/java/uct/umlrecog/OpenCVTest.java @@ -3,6 +3,7 @@ package com.hy.java.uct.umlrecog; import java.util.ArrayList; import java.util.List; +import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfPoint; import org.opencv.core.MatOfPoint2f; @@ -11,117 +12,136 @@ import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; -import nu.pattern.OpenCV; +import com.hy.java.utility.common.Pair; public class OpenCVTest { - static String image_path = "D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\eclipse.jetty-class diagram.png"; + static String class_diagram_path = "D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\eclipse.jetty-class diagram.png"; public static void main(String[] args) { // TODO Auto-generated method stub - OpenCV.loadShared(); - // System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取图片。并灰度处理 - Mat mat = Imgcodecs.imread(image_path, Imgcodecs.IMREAD_GRAYSCALE); + Mat mat = Imgcodecs.imread(class_diagram_path, Imgcodecs.IMREAD_GRAYSCALE); // 高斯锐化,提升类图图形清晰度 // Imgproc.Laplacian(mat, mat, 2); // 二值化,用于后续处理 Imgproc.threshold(mat, mat, 160, 255, Imgproc.THRESH_BINARY); // 矩形检测 - detectRec(mat); + Pair> rec_detected = detectRec(mat); + // 关系类型检测 + Mat temp = detectRelationType(rec_detected); // 直线检测 - // detectLines(mat); - // 看一眼 - // Imgcodecs.imwrite("D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\result.png",mat); + detectLines(temp); } - private static void detectRec(Mat src) { + /** + * 检测方框 + * + * @param src + * @return + */ + private static Pair> detectRec(Mat src) { // TODO Auto-generated method stub + System.out.println("识别所有类"); + List class_rects = new ArrayList<>(); + // 识别图中所有“轮廓”并保存 List contours = new ArrayList<>(); Imgproc.findContours(src, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); - for (MatOfPoint c : contours) { - if (Imgproc.contourArea(c) < 10) { + // 对每个轮廓,检测是否为矩形 + for (MatOfPoint contour : contours) { + // 如果轮廓面积太小或太大,则直接忽略。阈值可以根据图片像素动态计算 + if (Imgproc.contourArea(contour) < 10 || Imgproc.contourArea(contour) > 100000) { continue; } - - MatOfPoint2f curve = new MatOfPoint2f(c.toArray()); - MatOfPoint2f approxCurve = new MatOfPoint2f(); - // 轮廓逼近 + // 如果轮廓面积合适,则检测是否为矩形。采用多边形逼近法 + MatOfPoint2f curve = new MatOfPoint2f(contour.toArray()); + MatOfPoint2f approx_curve = new MatOfPoint2f(); + // 将轮廓向多边形做逼近 double epsilon = 0.01 * Imgproc.arcLength(curve, true); - Imgproc.approxPolyDP(curve, approxCurve, epsilon, true); -// System.out.print(approxCurve.dump()); - // Drawing lines on the image - if (approxCurve.toArray().length == 4) { - System.out.println(approxCurve.dump()); - double[] data1 = approxCurve.get(0, 0); - double[] data2 = approxCurve.get(1, 0); - double[] data3 = approxCurve.get(2, 0); - double[] data4 = approxCurve.get(3, 0); - Point pt1 = new Point(data1[0], data1[1]); - Point pt2 = new Point(data2[0], data2[1]); - Point pt3 = new Point(data3[0], data3[1]); - Point pt4 = new Point(data4[0], data4[1]); + Imgproc.approxPolyDP(curve, approx_curve, epsilon, true); + // 如果逼近的多边形一共有4个顶点,则可以认为是矩形(其实应该再检查4个顶点的坐标)。将检测结果绘制在原图中 + if (approx_curve.toArray().length == 4) { + // 将每个矩形存在别处用于识别文字。存完后将其从图中抹掉,防止其干扰直线识别 + class_rects.add(contour); + // 将矩形从图中抹掉(涂白)。后面还需对所有边框进行涂白 + Imgproc.fillConvexPoly(src, contour, new Scalar(255, 255, 255)); + // 已下几行其实无用,只是提示如何获取矩形顶点 + // 4个顶点 + Point pt1 = new Point(approx_curve.get(0, 0)[0], approx_curve.get(0, 0)[1]); + Point pt2 = new Point(approx_curve.get(1, 0)[0], approx_curve.get(1, 0)[1]); + Point pt3 = new Point(approx_curve.get(2, 0)[0], approx_curve.get(2, 0)[1]); + Point pt4 = new Point(approx_curve.get(3, 0)[0], approx_curve.get(3, 0)[1]); Imgproc.line(src, pt1, pt2, new Scalar(187, 255, 255), 2); Imgproc.line(src, pt2, pt3, new Scalar(187, 255, 255), 2); Imgproc.line(src, pt3, pt4, new Scalar(187, 255, 255), 2); Imgproc.line(src, pt4, pt1, new Scalar(187, 255, 255), 2); } - System.out.println("<<<<<<<<<<<<<<<<<"); -// double[] data; -// double rho, theta; -// Point pt1 = new Point(); -// Point pt2 = new Point(); -// double a, b; -// double x0, y0; -// -// for (int i = 0; i < approxCurve.rows(); i = i + 4) { -// -// data = approxCurve.get(i, 0); -// pt1.x = data[0]; -// pt1.y = data[1]; -// pt2.x = data[2]; -// pt2.y = data[3]; -// Imgproc.line(src, pt1, pt2, new Scalar(187, 255, 255), 20); -// } - // Writing the image - // Imgcodecs.imwrite("D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\result.png", - // src); - } - - // Imgproc.drawContours(src, contours, -1, new Scalar(0, 0, 255), 1); - // Writing the image + // 对所有边框进行涂白 + Imgproc.drawContours(src, class_rects, -1, new Scalar(255, 255, 255), 8); + // 将图片写入result文件 Imgcodecs.imwrite("D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\result.png", src); + System.out.println("识别类完毕,共" + class_rects.size() + "个"); + return Pair.createPair(src, class_rects); + } + + /** + * 识别关系符号 + * + * @param rec_detected + * @return + */ + private static Mat detectRelationType(Pair> rec_detected) { + // TODO Auto-generated method stub + System.out.println("识别所有关系符号"); + List class_rects = new ArrayList<>(); + // 识别图中所有“轮廓”并保存 + List contours = new ArrayList<>(); + Imgproc.findContours(rec_detected.getLeft(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); + // 对每个轮廓,检测是否为“特殊形状” + for (MatOfPoint contour : contours) { + // 如果轮廓面积太小或太大,则直接忽略。阈值可以根据图片像素动态计算 + if (Imgproc.contourArea(contour) < 35 || Imgproc.contourArea(contour) > 1000) { + continue; + } + // 如果轮廓面积合适,则检测是否为关系符号形状。采用多边形逼近法 + MatOfPoint2f curve = new MatOfPoint2f(contour.toArray()); + MatOfPoint2f approx_curve = new MatOfPoint2f(); + // 将轮廓向多边形做逼近 + double epsilon = 0.01 * Imgproc.arcLength(curve, true); + Imgproc.approxPolyDP(curve, approx_curve, epsilon, true); + System.out.print(approx_curve.dump()); + // 将每个关系符号存在别处。存完后将其从图中抹掉,防止其干扰直线识别 + class_rects.add(contour); + // 将关系符号从图中抹掉(涂白)。后面还需对所有边框进行涂白 + Imgproc.fillConvexPoly(rec_detected.getLeft(), contour, new Scalar(15, 225, 25)); + } + // 对所有边框进行涂白 + Imgproc.drawContours(rec_detected.getLeft(), class_rects, -1, new Scalar(255, 255, 255), 8); + // 将图片写入result文件 + Imgcodecs.imwrite("D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\result.png", rec_detected.getLeft()); + System.out.println("识别关系符号完毕,共" + class_rects.size() + "个"); + return rec_detected.getLeft(); } private static void detectLines(Mat src) { // TODO Auto-generated method stub - // Detecting edges of it + System.out.println("识别关系"); + // 先检测边缘。然后从边缘集中检测直线 Mat canny = new Mat(); - Imgproc.Canny(src, canny, 50, 200, 3, false); - - // Detecting the hough lines from (canny) + Imgproc.Canny(src, canny, 50, 150, 3, true); + // 从边缘集中检测直线 Mat lines = new Mat(); - - Imgproc.HoughLinesP(canny, lines, 1, Math.PI / 2, 80, 80, 80); - - // Drawing lines on the image - double[] data; - double rho, theta; - Point pt1 = new Point(); - Point pt2 = new Point(); - double a, b; - double x0, y0; - + Imgproc.HoughLinesP(canny, lines, 1, Math.PI / 4, 12, 17, 20); + // 将检测到的直线绘制到图中 for (int i = 0; i < lines.rows(); i++) { - data = lines.get(i, 0); - pt1.x = data[0]; - pt1.y = data[1]; - pt2.x = data[2]; - pt2.y = data[3]; + Point pt1 = new Point(lines.get(i, 0)[0], lines.get(i, 0)[1]); + Point pt2 = new Point(lines.get(i, 0)[2], lines.get(i, 0)[3]); Imgproc.line(src, pt1, pt2, new Scalar(187, 255, 255), 2); } // Writing the image Imgcodecs.imwrite("D:\\eclipse-committers\\uml-code-trace\\src\\test\\resources\\result.png", src); + System.out.println("识别关系完毕,共" + lines.rows() + "条"); } } diff --git a/src/test/resources/result.png b/src/test/resources/result.png index bd036f17f2d2dccb4198717adc5070adb98a5fbf..d49509128935a2a6340c1f393a42c1a3bfdd31a5 100644 Binary files a/src/test/resources/result.png and b/src/test/resources/result.png differ