From db1deb09a496a08ffcd6c59bbc0746df33bc9443 Mon Sep 17 00:00:00 2001 From: chief Date: Fri, 5 Feb 2021 18:06:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=85=B3=E7=B3=BB=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E3=80=82=E4=B8=8B=E4=B8=80=E6=AD=A5=E6=98=AF=E6=95=B4?= =?UTF-8?q?=E5=90=88=E7=B1=BB=E3=80=81=E5=85=B3=E7=B3=BB=EF=BC=8C=E5=B0=86?= =?UTF-8?q?=E5=85=B6=E5=86=99=E5=85=A5=E4=B8=80=E4=B8=AAtxt=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=AD=EF=BC=8C=E7=94=A8=E4=BA=8E=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E3=80=81=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/umlrecog/ClassDiagramRecognizer.java | 21 +++- .../cddetector/ClassRelationDetector.java | 110 ++++++++++-------- .../java/uct/umlrecog/util/PolygonalLine.java | 15 +++ src/main/resources/cd/temp result.png | Bin 101 -> 176 bytes 4 files changed, 93 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java index a58e47b..3b74a55 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/ClassDiagramRecognizer.java @@ -1,12 +1,14 @@ package com.hy.java.uct.umlrecog; import java.util.List; +import java.util.Set; import org.opencv.core.Core; import org.opencv.core.Mat; import com.hy.java.uct.umlrecog.cddetector.ClassDetector; import com.hy.java.uct.umlrecog.cddetector.ClassRelationDetector; +import com.hy.java.uct.umlrecog.util.Relation; import com.hy.java.uct.umlrecog.util.UMLClass; import com.hy.java.utility.common.Pair; import com.hy.java.utility.common.Traverser; @@ -20,15 +22,26 @@ public class ClassDiagramRecognizer { if (repo_cd_path != null) { // 导入OpenCV库,开始识别 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); - // 识别类图中的类 + /* + * 识别类图中的类 + */ ClassDetector cls_detector = new ClassDetector(repo_cd_path); cls_detector.recog(); Pair> classes = cls_detector.getResult(); - // 识别类图中的关系 + /* + * 识别类图中的关系 + */ ClassRelationDetector cls_relation_detector = new ClassRelationDetector(repo_cd_path, classes); cls_relation_detector.recog(); - // 整合文件吧,哈哈 - cls_relation_detector.getResult(); + Set relations = cls_relation_detector.getResult(); + /* + * 整合文件吧,哈哈 + * + * 该做这儿了 + * + * 整合出来一个txt,包含类、关系等信息即可。然后再把结果画出来,用于验证、展示 + */ + } else { System.err.println("不存在" + repo_name + "的类图"); } diff --git a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassRelationDetector.java b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassRelationDetector.java index 02df9b6..25f5943 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassRelationDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassRelationDetector.java @@ -6,8 +6,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.opencv.core.Core; -import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfPoint; import org.opencv.core.MatOfPoint2f; @@ -21,9 +19,7 @@ import org.opencv.imgproc.Imgproc; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Line; import com.hy.java.uct.umlrecog.util.PolygonalLine; -import com.hy.java.uct.umlrecog.util.Rectangle; import com.hy.java.uct.umlrecog.util.Relation; -import com.hy.java.uct.umlrecog.util.RelationType; import com.hy.java.uct.umlrecog.util.UMLClass; import com.hy.java.utility.common.Pair; @@ -31,7 +27,7 @@ public class ClassRelationDetector { private String cd_path = null; private String temp_res_path = null; private Pair> classes_in_cd = null; - private Object result = null; + private Set result = null; public ClassRelationDetector(String repo_cd_path, Pair> classes) { this.cd_path = repo_cd_path; @@ -45,8 +41,8 @@ public class ClassRelationDetector { // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 Set dash_lines = detectLines(classes_in_cd, 0.0504, false); // 再检测关系类型检测 - Set relation_types = detectRelationType(classes_in_cd, solid_lines, dash_lines, 0.0001); - + Set relation_with_types = detectRelationType(classes_in_cd, solid_lines, dash_lines, 0.0001); + result = relation_with_types; } private Set detectLines(Pair> classes_in_cd, double ratio, boolean detect_solid) { @@ -115,8 +111,7 @@ public class ClassRelationDetector { for (int j = i + 1; j < current_size; j++) { Line other_line = line_segments.get(j); if (Line.Knear(line, other_line)) { - if (Line.ptNearPt(line.pt1, other_line.pt1, false, true, other_line) || Line.ptNearPt(line.pt1, other_line.pt2, false, true, other_line) - || Line.ptNearPt(line.pt2, other_line.pt1, false, true, other_line) || Line.ptNearPt(line.pt2, other_line.pt2, false, true, other_line)) { + if (Line.ptNearPt(line.pt1, other_line.pt1, false, true, other_line) || Line.ptNearPt(line.pt1, other_line.pt2, false, true, other_line) || Line.ptNearPt(line.pt2, other_line.pt1, false, true, other_line) || Line.ptNearPt(line.pt2, other_line.pt2, false, true, other_line)) { other_line.should_be_del = true; } } @@ -168,7 +163,8 @@ public class ClassRelationDetector { if (detect_solid) { // 实线识别结果 for (Relation rela : result) { - System.out.println("(" + rela.poly_line.pt1.x + ", " + rela.poly_line.pt1.y + ")" + "(" + rela.poly_line.pt2.x + ", " + rela.poly_line.pt2.y + ")"); + // 两端坐标 + // System.out.println("(" + rela.poly_line.pt1.x + ", " + rela.poly_line.pt1.y + ")" + "(" + rela.poly_line.pt2.x + ", " + rela.poly_line.pt2.y + ")"); // 在图中抹掉已识别的线,防止干扰后续识别 for (Line segment : rela.poly_line.line_list) { Imgproc.line(cls_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); @@ -181,7 +177,8 @@ public class ClassRelationDetector { } else { // 虚线识别结果 for (Relation rela : result) { - System.out.println("(" + rela.poly_line.pt1.x + ", " + rela.poly_line.pt1.y + ")" + "(" + rela.poly_line.pt2.x + ", " + rela.poly_line.pt2.y + ")"); + // 两端坐标 + // System.out.println("(" + rela.poly_line.pt1.x + ", " + rela.poly_line.pt1.y + ")" + "(" + rela.poly_line.pt2.x + ", " + rela.poly_line.pt2.y + ")"); // 在图中抹掉已识别的线,防止干扰后续识别 for (Line segment : rela.poly_line.line_list) { Imgproc.line(cls_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); @@ -372,9 +369,9 @@ public class ClassRelationDetector { MatOfPoint2f approx_curve = new MatOfPoint2f(); Imgproc.approxPolyDP(curve, approx_curve, 0.01 * Imgproc.arcLength(curve, true), true); // 获取包络矩形 - Rect rect = Imgproc.boundingRect(new MatOfPoint(approx_curve.toArray())); + Rect rect_containing_rela_type = Imgproc.boundingRect(new MatOfPoint(approx_curve.toArray())); // 如果包络矩形包含某一条关系线的某一端,则检测该矩形内的符号 - // 对于虚线,由于只可能是实现或生命线,所以只需要知道是否包含即可,不用检测矩形内部图形 + // 对于虚线,由于只可能是实现或生命线,所以只需要知道是否包含即可,不用检测矩形内部图形。belong_to_dash_rela为true表示当前关系符号属于某条虚线关系线 boolean belong_to_dash_rela = false; for (Relation dash_rela : dash_lines) { // 如果dash_rela.source_pt_index != -1,则说明该dash_rela已经与某一包络矩形检测并对应上了,则跳过 @@ -382,11 +379,11 @@ public class ClassRelationDetector { continue; } // 对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。如果包含,则belong_to_dash_line = true; - if (rect.contains(dash_rela.poly_line.pt1) || rect.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 5, false)) - || rect.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 5, true))) { + if (rect_containing_rela_type.contains(dash_rela.poly_line.pt1) || rect_containing_rela_type.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 5, false)) + || rect_containing_rela_type.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 5, true))) { // 包络矩形确实包含关系线的端点pt1 belong_to_dash_rela = true; - // 重新检查source和target。目前的端点pt1必须对应target类 + // 重新设置虚线的source和target。由于目前虚线的端点pt1必须对应target类,所以如果虚线的原source类对应了pt1,则需对换source和target if (dash_rela.source.whole.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 35, false))) { UMLClass temp = dash_rela.source; dash_rela.source = dash_rela.target; @@ -394,11 +391,13 @@ public class ClassRelationDetector { } dash_rela.source_pt_index = 2; dash_rela.type = "实现"; + // 记录当前关系到result里 + result.add(dash_rela); break; - } else if (rect.contains(dash_rela.poly_line.pt2) || rect.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 5, false)) - || rect.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 5, true))) { + } else if (rect_containing_rela_type.contains(dash_rela.poly_line.pt2) || rect_containing_rela_type.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 5, false)) + || rect_containing_rela_type.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 5, true))) { belong_to_dash_rela = true; - // 重新检查source和target。目前的端点pt2必须对应target类 + // 重新设置虚线的source和target。由于目前虚线的端点pt2必须对应target类,所以如果虚线的原source类对应了pt2,则需对换source和target if (dash_rela.source.whole.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 35, false))) { UMLClass temp = dash_rela.source; dash_rela.source = dash_rela.target; @@ -406,9 +405,12 @@ public class ClassRelationDetector { } dash_rela.source_pt_index = 1; dash_rela.type = "实现"; + // 记录当前关系到result里 + result.add(dash_rela); break; } } + // 如果该关系符号不属于任何虚线关系,则检测其是否属于某实线关系 if (!belong_to_dash_rela) { // 对于实线,需检测矩形内部图形,识别继承、聚合 for (Relation solid_rela : solid_lines) { @@ -416,24 +418,24 @@ public class ClassRelationDetector { if (solid_rela.source_pt_index != -1) { continue; } - // 记录该包络矩形是否属于某关系线。如果是的话,再去检测矩形内图形 + // 记录该包络矩形是否属于当前实线关系线solid_rela。如果是的话,再去检测矩形内图形 boolean belong_to_this_solid_rela = false; // 方法同对dash_rela的检测。对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。 - if (rect.contains(solid_rela.poly_line.pt1) || rect.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 5, false)) - || rect.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 5, true))) { + if (rect_containing_rela_type.contains(solid_rela.poly_line.pt1) || rect_containing_rela_type.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 5, false)) + || rect_containing_rela_type.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 5, true))) { // 包络矩形确实包含关系线的端点pt1 belong_to_this_solid_rela = true; - // 重新检查source和target。目前的端点pt1必须对应target类 + // 重新设置虚线的source和target。由于目前虚线的端点pt1必须对应target类,所以如果虚线的原source类对应了pt1,则需对换source和target if (solid_rela.source.whole.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 35, false))) { UMLClass temp = solid_rela.source; solid_rela.source = solid_rela.target; solid_rela.target = temp; } solid_rela.source_pt_index = 2; - } else if (rect.contains(solid_rela.poly_line.pt2) || rect.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 5, false)) - || rect.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 5, true))) { + } else if (rect_containing_rela_type.contains(solid_rela.poly_line.pt2) || rect_containing_rela_type.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 5, false)) + || rect_containing_rela_type.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 5, true))) { belong_to_this_solid_rela = true; - // 重新检查source和target。目前的端点pt2必须对应target类 + // 重新设置虚线的source和target。由于目前虚线的端点pt2必须对应target类,所以如果虚线的原source类对应了pt2,则需对换source和target if (solid_rela.source.whole.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 35, false))) { UMLClass temp = solid_rela.source; solid_rela.source = solid_rela.target; @@ -441,43 +443,53 @@ public class ClassRelationDetector { } solid_rela.source_pt_index = 1; } + // 目前该关系符号确实属于当前实线关系solid_rela,所以需检查其是聚合还是继承 if (belong_to_this_solid_rela) { String type = "聚合"; - // 裁剪原图中矩形区域 - Mat cutted_origin_rela_type_area = ImgProcessor.cutImage(origin_cls_diagram, rect); + // 裁剪原图中包含关系符号的矩形区域 + Mat cutted_origin_rela_type_area = ImgProcessor.cutImage(origin_cls_diagram, rect_containing_rela_type); Imgproc.erode(cutted_origin_rela_type_area, cutted_origin_rela_type_area, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2, 2)), new Point(-1, -1), 2); Imgproc.dilate(cutted_origin_rela_type_area, cutted_origin_rela_type_area, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 1)), new Point(-1, -1), 2); - // 重新识别符号 + // 针对包含关系符号的区域,重新识别各种“轮廓”,从而发现真正的关系符号 List origin_contours = new ArrayList<>(); Imgproc.findContours(cutted_origin_rela_type_area, origin_contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); - // 针对识别出来的区域做筛选 + // 针对识别出来的各种“轮廓”做筛选 for (MatOfPoint origin_contour : origin_contours) { MatOfPoint2f origin_curve = new MatOfPoint2f(origin_contour.toArray()); MatOfPoint2f origin_approx_curve = new MatOfPoint2f(); + // 对“轮廓”做二次逼近,获取关系符号形状。第一次逼近可以误差大一点,得到大致形状;第二次逼近误差要小一点,得到精确形状 Imgproc.approxPolyDP(origin_curve, origin_approx_curve, 0.05 * Imgproc.arcLength(origin_curve, false), true); Imgproc.approxPolyDP(origin_approx_curve, origin_approx_curve, 0.01 * Imgproc.arcLength(origin_approx_curve, true), true); + // 如果逼近得到三角形,则基本就是继承了,再检查一下位置即可(其实检不检查作用不大) if (origin_approx_curve.toArray().length == 3) { - // 获取包络矩形 - Rect if_extend_rect = Imgproc.boundingRect(new MatOfPoint(origin_approx_curve.toArray())); - Imgproc.rectangle(cutted_origin_rela_type_area, if_extend_rect, new Scalar(5, 5, 5), 1); + // 获取三角形的包络矩形 + Rect rect_possible_containing_ext = Imgproc.boundingRect(new MatOfPoint(origin_approx_curve.toArray())); + // 检查包络矩形rect_possible_containing_ext是否真的包含当前关系线solid_rela的target端点的延长线。如果是的话,则确定是继承关系 + // 先找到关系线solid_rela的target端点和对应线段。然后检查target端点的延长与包络矩形的关系 + Point target_point = solid_rela.poly_line.pt1; + Line target_line = solid_rela.poly_line.l1; + if (solid_rela.source_pt_index == 1) { + // 如果source端点是1,则target端点是pt2 + target_point = solid_rela.poly_line.pt2; + target_line = solid_rela.poly_line.l2; + } + // 如果rect_possible_containing_ext包含当前关系线solid_rela的target端点或延长,则就是继承关系了 + if (rect_possible_containing_ext.contains(target_point) || rect_possible_containing_ext.contains(ImgProcessor.reachPt(target_point, target_line, 5, false)) || rect_possible_containing_ext.contains(ImgProcessor.reachPt(target_point, target_line, 5, true))) { + type = "继承"; + } + /* + * 我就看看,不乱动 + */ + Imgproc.rectangle(cutted_origin_rela_type_area, rect_possible_containing_ext, new Scalar(5, 5, 5), 3); Imgcodecs.imwrite(temp_res_path, cutted_origin_rela_type_area); - - type = "继承"; + /* + * 看完了,可删 + */ } - - /* - * 识别一下吧,估计不咋滴。下面的代码可以都删掉 - */ - /* - * List temp_list = new ArrayList<>(); MatOfPoint matOfPoint = new MatOfPoint(); origin_approx_curve.convertTo(matOfPoint, CvType.CV_32S); - * temp_list.add(matOfPoint); Imgproc.polylines(cutted_origin_rela_type_area, temp_list, true, new Scalar(5, 5, 5), 5); - * Imgcodecs.imwrite(temp_res_path, cutted_origin_rela_type_area); System.out.println("把" + type + "画完了"); System.out.println("把上面的字打印完了"); - */ - /* - * 识别完毕,差不多得了。上面的代码可以都删掉 - */ } solid_rela.type = type; + // 记录当前关系到result里 + result.add(solid_rela); // 检测完符号类别后,对当前区域就算检测完了,不用再检测其他实线了 break; } @@ -485,11 +497,11 @@ public class ClassRelationDetector { // 如果运行到这儿(检测完符号类别后break会直接到这儿),说明对当前区域的包络矩形与实线之间的检测完毕。相当于对当前区域检测完毕,开始检测下一个区域 } } - System.out.println("完成对" + cd_path + "中识别关系符号的识别,共" + result.size() + "个"); + System.out.println("完成对" + cd_path + "中识别关系符号的识别。最终获得带关系类型的关系共" + result.size() + "个"); return result; } - public Object getResult() { + public Set getResult() { return result; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/PolygonalLine.java b/src/main/java/com/hy/java/uct/umlrecog/util/PolygonalLine.java index faad1c0..fd67f6e 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/PolygonalLine.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/PolygonalLine.java @@ -11,10 +11,25 @@ import org.opencv.core.Point; * 最终作为Relation的一个属性 */ public class PolygonalLine { + /** + * 该折线的一端pt1 + */ public Point pt1; + /** + * 该折线的一端pt2 + */ public Point pt2; + /** + * 该折线的端点pt1所在的线段 + */ public Line l1; + /** + * 该折线的端点pt2所在的线段 + */ public Line l2; + /** + * 该折线的线段列表 + */ public List line_list = new ArrayList<>(); public PolygonalLine(Line line) { diff --git a/src/main/resources/cd/temp result.png b/src/main/resources/cd/temp result.png index 4e790beef5a46e348376e6323133972ccda356e7..1e6fa00d4e596adc01249a25e47d7a57e05bf888 100644 GIT binary patch delta 147 zcmYe@z&JsrzTDHrF+@T#_MoBA5d|KWgEtwTd;R$T+r!NKr01~*t6oowv^u`vgwEXL zfRt(H3^k0r)$fXD0@;4M^e-(qVY6uByKWQTNtG^-XQ-W=vY^n1=LCdY!XUMtQz9j3 xf>gh!(TODw`W>GMCz#FjZ@8Ia$C&n;aqj^&!I%?;yq6h(z|+;wWt~$(69Dh(KZyVU delta 71 zcmdnMm^wklQODE8F+@VL^q?Ul0|P^|g6*65N=~+8i85G_p;t6RbdpqPD^Mkar>mdK II;Vst04vfKx&QzG -- Gitee