From a8437e80ca61b5bfd0a4a84cc98b2ef6fb2b64f1 Mon Sep 17 00:00:00 2001 From: chief Date: Mon, 1 Mar 2021 21:26:18 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E4=BB=8EObjectDetector=E7=9A=84=E7=AC=AC?= =?UTF-8?q?50=E8=A1=8C=E5=BC=80=E5=A7=8B=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/SequenceDiagramRecognizer.java | 60 +++++------ .../umlrecog/sddetector/MessageDetector.java | 10 +- .../umlrecog/sddetector/ObjectDetector.java | 29 ++--- .../hy/java/uct/umlrecog/util/Message.java | 5 + .../hy/java/uct/umlrecog/util/UMLObject.java | 15 +++ src/main/resources/cd/Salaboy_smart-tasks.txt | 99 ++++++++++++++++++ src/main/resources/sd/temp result.png | Bin 0 -> 746 bytes 7 files changed, 169 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/hy/java/uct/umlrecog/util/Message.java create mode 100644 src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java create mode 100644 src/main/resources/sd/temp result.png diff --git a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java index d25d684..02f2006 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java @@ -5,10 +5,10 @@ import java.util.List; 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.uct.umlrecog.sddetector.MessageDetector; +import com.hy.java.uct.umlrecog.sddetector.ObjectDetector; +import com.hy.java.uct.umlrecog.util.Message; +import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.FileEditor; import com.hy.java.utility.common.Pair; import com.hy.java.utility.common.Traverser; @@ -18,33 +18,33 @@ public class SequenceDiagramRecognizer { private static String temp_res_path = null; - public static void recog(String cd_dir, String repo_name) { - // 遍历cd_dir下的文件,寻找repo_name对应的图片,存在repo_cd_path中 - String repo_cd_path = findCD(cd_dir, repo_name); - if (repo_cd_path != null) { + public static void recog(String sd_dir, String repo_name) { + // 遍历cd_dir下的文件,寻找repo_name对应的图片,存在repo_sd_path中 + String repo_sd_path = findSD(sd_dir, repo_name); + if (repo_sd_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(); + ObjectDetector obj_detector = new ObjectDetector(repo_sd_path); + obj_detector.recog(); + Pair> objects = obj_detector.getResult(); /* - * 识别类图中的关系 + * 识别顺序图中的消息 */ - ClassRelationDetector cls_relation_detector = new ClassRelationDetector(repo_cd_path, classes); - cls_relation_detector.recog(); - Pair> classes_with_relations = cls_relation_detector.getResult(); + MessageDetector obj_msg_detector = new MessageDetector(repo_sd_path, objects); + obj_msg_detector.recog(); + Pair> classes_with_relations = obj_msg_detector.getResult(); /* * 目前classes_with_relations中包含所有类。每个类包含这些信息:类名、属性、方法;关系(分为in和out) * * 将所有类整合为一个txt,以每个类为划分,包含每个类的信息 */ // 图包路径+项目名称+.txt - FileEditor fe = new FileEditor(cd_dir + repo_name.replaceAll("/", "_") + ".txt"); - List class_list = classes_with_relations.getRight(); - for (UMLClass UML_class : class_list) { + FileEditor fe = new FileEditor(sd_dir + repo_name.replaceAll("/", "_") + ".txt"); + List class_list = classes_with_relations.getRight(); + for (UMLObject UML_class : class_list) { // 想想写的格式!!!!!!!!! // 想想写的格式!!!!!!!!! // 想想写的格式!!!!!!!!! @@ -56,12 +56,10 @@ public class SequenceDiagramRecognizer { // 想想写的格式!!!!!!!!! // 比如@、#、¥、%等分隔符等级 fe.write(UML_class.getTitle() + "@", true); - fe.write(UML_class.getAttrisStr() + "@", true); - fe.write(UML_class.getMethodsStr() + "@", true); - for (Relation out_rel : UML_class.out_relas) { + for (Message out_rel : UML_class.out_relas) { } - for (Relation in_rel : UML_class.in_relas) { + for (Message in_rel : UML_class.in_relas) { } } @@ -74,25 +72,25 @@ public class SequenceDiagramRecognizer { */ } else { - System.err.println("不存在" + repo_name + "的类图"); + System.err.println("不存在" + repo_name + "的顺序图"); } } - private static String findCD(String cd_dir, String repo_name) { + private static String findSD(String sd_dir, String repo_name) { String result = null; // 用repo_name去查找图片时所使用的字符串 - String search_string = cd_dir + "cd-" + repo_name.replaceAll("/", "_"); + String search_string = sd_dir + "sd-" + repo_name.replaceAll("/", "_"); // 遍历cd_dir下的文件 - List cd_dir_files = Traverser.traverseDir(cd_dir).children; - for (FileNode cd_dir_file : cd_dir_files) { + List sd_dir_files = Traverser.traverseDir(sd_dir).children; + for (FileNode sd_dir_file : sd_dir_files) { // 过滤掉result.txt文件,只找图片 - if (cd_dir_file.path.equals(cd_dir + "result.txt")) { + if (sd_dir_file.path.equals(sd_dir + "result.txt")) { continue; } // 针对图片名,去掉后缀后,与search_string做匹配 - if (search_string.equals(cd_dir_file.path.substring(0, cd_dir_file.path.lastIndexOf(".")))) { + if (search_string.equals(sd_dir_file.path.substring(0, sd_dir_file.path.lastIndexOf(".")))) { // 如果匹配成功,则保存图片路径 - result = cd_dir_file.path; + result = sd_dir_file.path; // 找到指定图片后就可以结束查找了 break; } diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 5f1ab50..fb69ee8 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -22,6 +22,7 @@ import com.hy.java.uct.umlrecog.util.Line; import com.hy.java.uct.umlrecog.util.PolygonalLine; import com.hy.java.uct.umlrecog.util.Relation; import com.hy.java.uct.umlrecog.util.UMLClass; +import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.Pair; public class MessageDetector { @@ -30,10 +31,11 @@ public class MessageDetector { private Pair> classes_in_cd = null; private Pair> result = null; - public MessageDetector(String repo_cd_path, Pair> classes) { + public MessageDetector(String repo_cd_path, Pair> objects) { this.cd_path = repo_cd_path; this.temp_res_path = cd_path.replaceAll(cd_path.substring(cd_path.lastIndexOf("\\") + 1, cd_path.lastIndexOf(".")), "temp result"); - this.classes_in_cd = classes; + // 这句需要改成List + // this.classes_in_cd = objects; } public void recog() { @@ -500,7 +502,7 @@ public class MessageDetector { return classes_in_cd; } - public Pair> getResult() { - return result; + public Pair> getResult() { + return null; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java index 56274be..5b749ae 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java @@ -16,6 +16,7 @@ import com.hy.java.uct.umlrecog.UMLDiagramRecognizer; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Rectangle; import com.hy.java.uct.umlrecog.util.UMLClass; +import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.Pair; import net.sourceforge.tess4j.ITesseract; @@ -23,13 +24,13 @@ import net.sourceforge.tess4j.Tesseract; import net.sourceforge.tess4j.TesseractException; public class ObjectDetector { - private String cd_path = null; + private String sd_path = null; private String temp_res_path = null; - private Pair> result = null; + private Pair> result = null; - public ObjectDetector(String repo_cd_path) { - this.cd_path = repo_cd_path; - this.temp_res_path = cd_path.replaceAll(cd_path.substring(cd_path.lastIndexOf("\\") + 1, cd_path.lastIndexOf(".")), "temp result"); + public ObjectDetector(String repo_sd_path) { + this.sd_path = repo_sd_path; + this.temp_res_path = sd_path.replaceAll(sd_path.substring(sd_path.lastIndexOf("\\") + 1, sd_path.lastIndexOf(".")), "temp result"); } public void recog() { @@ -37,20 +38,20 @@ public class ObjectDetector { * 预处理 */ // 读取图片。并灰度处理 - Mat mat = Imgcodecs.imread(cd_path, Imgcodecs.IMREAD_GRAYSCALE); + Mat mat = Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE); // 高斯锐化,提升类图图形清晰度 // Imgproc.Laplacian(mat, mat, 2); // 二值化,用于后续处理 Imgproc.threshold(mat, mat, 160, 255, Imgproc.THRESH_BINARY); /* - * 识别类 + * 识别对象 */ // 矩形检测。识别所有矩形区域 Pair> all_rect_areas_in_cd = detectRectArea(mat, 0.000555); // 对矩形进行整合,形成类区域 List classes = mergeIntoClass(all_rect_areas_in_cd); // 对类区域进行文字检测 - result = Pair.createPair(all_rect_areas_in_cd.getLeft(), detectText(Imgcodecs.imread(cd_path, Imgcodecs.IMREAD_GRAYSCALE), classes)); + // result = Pair.createPair(all_rect_areas_in_cd.getLeft(), detectText(Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE), classes)); } /** @@ -61,7 +62,7 @@ public class ObjectDetector { * @return */ private Pair> detectRectArea(Mat cls_diagram, double ratio) { - System.out.println("开始识别" + cd_path + "中所有矩形"); + System.out.println("开始识别" + sd_path + "中所有矩形"); /* * 识别图中所有“轮廓”并存在contours中 */ @@ -222,12 +223,12 @@ public class ObjectDetector { // 针对当前矩形,与所有其他矩形对比完毕后,则完成了该类的识别 result.add(uml_class); } - System.out.println("完成将" + cd_path + "中所有矩形整合为类的业务,共" + result.size() + "个类"); + System.out.println("完成将" + sd_path + "中所有矩形整合为类的业务,共" + result.size() + "个类"); return result; } private List detectText(Mat cls_diagram, List classes) { - System.out.println("开始识别" + cd_path + "中每个类的文字"); + System.out.println("开始识别" + sd_path + "中每个类的文字"); for (UMLClass uc : classes) { ITesseract instance = new Tesseract(); instance.setDatapath(UMLDiagramRecognizer.tessdata_path); @@ -250,11 +251,11 @@ public class ObjectDetector { e.printStackTrace(); } } - System.out.println("完成对" + cd_path + "中每个类的文字识别"); + System.out.println("完成对" + sd_path + "中每个类的文字识别"); return classes; } - public Pair> getResult() { - return result; + public Pair> getResult() { + return null; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java new file mode 100644 index 0000000..1256f11 --- /dev/null +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java @@ -0,0 +1,5 @@ +package com.hy.java.uct.umlrecog.util; + +public class Message { + +} diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java new file mode 100644 index 0000000..1d0721a --- /dev/null +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -0,0 +1,15 @@ +package com.hy.java.uct.umlrecog.util; + +import java.util.List; + +public class UMLObject { + + public List out_relas; + public List in_relas; + + public String getTitle() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/resources/cd/Salaboy_smart-tasks.txt b/src/main/resources/cd/Salaboy_smart-tasks.txt index ee76cbe..db63982 100644 --- a/src/main/resources/cd/Salaboy_smart-tasks.txt +++ b/src/main/resources/cd/Salaboy_smart-tasks.txt @@ -92,6 +92,105 @@ claimfid : String) start(id : String) +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + complete(id : String,data : Object) @@= HumanTaskServiceOperations diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png new file mode 100644 index 0000000000000000000000000000000000000000..179515db827147318358c2040eab1f5a447bdc04 GIT binary patch literal 746 zcmeAS@N?(olHy`uVBq!ia0vp^T|lhP0VEi{=Jj_lFfeWOba4!c;5>V9VRwqT4Eu-o z{ZHBM6&NV>yxh4`BGBTaPmHV4ste76OO;xiI}Ys>{mESB68c51XGPSBo$k)QXHL#| zA-wcL<8m#lMUNJ+$o<)+?k&&Ee0t*fc8RqLZrU9exstXt;bVTR^xc-yXnADEidQ@d zHy(Q}wt9Hc>g$j7C#UHcv`dJG-aXptyYl$erjLC8jc-n3eI}56EhYFBW60g3Pao#p z@c+j6`bu($I?wM_#@Ajh^<61{RZZ^=^EDvN|GxhJr~WJ9caNqT++$o}l{~j9WbQ`4 zzbW2gGn{)OC;P5s4=5GS|6;j5=j5XgdiK|2_f-D&y0SDTNi&?N?pi zz<+GF(q3nvA))g>pIY{1s@?OczAu;RMkeqX>aDV3-n~QS>bnl5cJWKr3q0Nn^!)eB zU9{id>204z(F>q!R=)%CY=Q3AxMa=pc>lC}iW2qNU^jHHdiO{lX!ggGANnP~IT+kq z=uw}2`uF?YKO7%TUKqYxxnRftum8^PZ~;!~v>WW7FQ3nknRxHv#T8}l3r_rdZ_dYY4D6^gADpV%6WSnp4YN0C zeq{h!{;9ycX7Tw*28pX`_x9BNUe(PVy-DI~=G_=;jt#27 zAd0y$DI6SKGfZzzsbUB%FN}QBe|(kkhO Date: Tue, 2 Mar 2021 10:37:53 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E7=8E=B0=E5=B7=B2=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E5=AE=8C=E9=A1=BA=E5=BA=8F=E5=9B=BE=E4=B8=AD=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E6=A1=86=E3=80=82=E6=8E=A5=E4=B8=8B=E6=9D=A5=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E5=9B=BE=E5=AF=B9=E8=B1=A1=E3=80=82=E4=BB=8E?= =?UTF-8?q?ObjectDetector=E7=9A=84125=E8=A1=8C=E5=BC=80=E5=A7=8B=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/ObjectDetector.java | 76 +-- .../hy/java/uct/umlrecog/util/UMLObject.java | 6 + src/main/resources/cd/Salaboy_smart-tasks.txt | 495 ++++++++++++++++++ src/main/resources/sd/temp result.png | Bin 746 -> 8161 bytes 4 files changed, 539 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java index 5b749ae..158ddb3 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java @@ -47,27 +47,27 @@ public class ObjectDetector { * 识别对象 */ // 矩形检测。识别所有矩形区域 - Pair> all_rect_areas_in_cd = detectRectArea(mat, 0.000555); + Pair> all_rect_areas_in_sd = detectRectArea(mat, 0.000555); // 对矩形进行整合,形成类区域 - List classes = mergeIntoClass(all_rect_areas_in_cd); + List objects = mergeIntoObject(all_rect_areas_in_sd); // 对类区域进行文字检测 - // result = Pair.createPair(all_rect_areas_in_cd.getLeft(), detectText(Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE), classes)); + result = Pair.createPair(all_rect_areas_in_sd.getLeft(), detectText(Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE), objects)); } /** * 检测方框 * - * @param cls_diagram - * @param ratio 检测最小矩形占全图面积的比例(0~1之间的一个小数)。如果类图中类的面积很小,则该比例应设的很小。 + * @param s_diagram + * @param ratio 检测最小矩形占全图面积的比例(0~1之间的一个小数)。如果类图中类的面积很小,则该比例应设的很小。 * @return */ - private Pair> detectRectArea(Mat cls_diagram, double ratio) { + private Pair> detectRectArea(Mat s_diagram, double ratio) { System.out.println("开始识别" + sd_path + "中所有矩形"); /* * 识别图中所有“轮廓”并存在contours中 */ List contours = new ArrayList<>(); - Imgproc.findContours(cls_diagram, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); + Imgproc.findContours(s_diagram, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); /* * 对每个轮廓contour,检测是否为矩形,并将contour和检测结果存在Rectangle中。所有轮廓的检测结果最终存在all_rect_areas中 */ @@ -75,8 +75,8 @@ public class ObjectDetector { // 这个rect_contours里只存那些检测结果为矩形的contour,用于后面边框涂白,防止矩形干扰关系符号和关系线识别 List rect_contours = new ArrayList<>(); // 根据图片像素计算轮廓面积阈值。如果轮廓面积太小或太大,则直接忽略 - long cd_area = cls_diagram.width() * cls_diagram.height(); - double min_cls_area = 60; + long cd_area = s_diagram.width() * s_diagram.height(); + double min_cls_area = 70; double max_cls_area = cd_area * 0.5; for (MatOfPoint contour : contours) { // 如果轮廓面积太小或太大,则直接忽略 @@ -90,37 +90,45 @@ public class ObjectDetector { Imgproc.approxPolyDP(curve, approx_curve, 0.01 * Imgproc.arcLength(curve, true), true); // 针对逼近结果approx_curve,若其共有4个顶点,则可认为是矩形。将检测结果绘制在原图中,便于后续处理 if (approx_curve.toArray().length == 4) { - // 将矩形存在all_rect_areas中用于类的整合和文字识别。存完后将其从原图中抹掉,防止其干扰关系符号和关系线识别 - all_rect_areas.add(new Rectangle(cls_diagram.clone(), contour, approx_curve)); + // 将矩形存在all_rect_areas中用于对象的整合和文字识别。存完后将其从原图中抹掉,防止其干扰关系符号和关系线识别 + all_rect_areas.add(new Rectangle(s_diagram.clone(), contour, approx_curve)); rect_contours.add(contour); // 存完后将矩形从图中抹掉(涂白)。后面还需对所有边框进行涂白 - Imgproc.fillConvexPoly(cls_diagram, contour, new Scalar(255, 255, 255)); + Imgproc.fillConvexPoly(s_diagram, contour, new Scalar(255, 255, 255)); } } // 对所有矩形边框进行涂白,防止其干扰关系符号和关系线识别 - Imgproc.drawContours(cls_diagram, rect_contours, -1, new Scalar(255, 255, 255), 5); - // 此时的cls_diagram中矩形已涂白 - return Pair.createPair(cls_diagram, all_rect_areas); + Imgproc.drawContours(s_diagram, rect_contours, -1, new Scalar(255, 255, 255), 5); + // 可以先不涂白,看下识别结果。最后要注释掉 + // Imgproc.drawContours(s_diagram, rect_contours, -1, new Scalar(0, 0, 0), 5); + // Imgcodecs.imwrite(temp_res_path, s_diagram); + // 此时的s_diagram中矩形已涂白 + return Pair.createPair(s_diagram, all_rect_areas); } - private List mergeIntoClass(Pair> all_rect_areas_in_cd) { - List result = new ArrayList<>(); - // Mat cls_diagram = all_rect_areas_in_cd.getLeft(); + private List mergeIntoObject(Pair> all_rect_areas_in_sd) { + List result = new ArrayList<>(); + // Mat s_diagram = all_rect_areas_in_sd.getLeft(); // 获取所有矩形 - List rect_area_list = all_rect_areas_in_cd.getRight(); + List rect_area_list = all_rect_areas_in_sd.getRight(); /* * 拼接思路: * - * 首先针对当前矩形,将其赋给一个类。记录该类当前拥有的矩形列表。 + * 首先将矩形赋给一个对象。 * - * 然后针对该矩形的左上角,看是否与其他矩形的左上角横坐标相差不超过3~5个像素 + * 然后检测所有矩形横坐标。如果两个矩形横坐标一样,则舍去纵坐标靠下的矩形。 * - * 如果是,则再看两个左上角的纵坐标距离是否大致等于“上面矩形”的高度 - * - * 如果是,则纳入同一个类中 + * 留下的矩形包括:真正的对象(纵坐标可能不同)、生命线上的矩形。后者需在文字识别时剔除 */ for (int all_rect_index = 0; all_rect_index < rect_area_list.size(); all_rect_index++) { Rectangle current_rect = rect_area_list.get(all_rect_index); + /* + * 从这儿开始改。 + * + * 从这儿开始改。 + * + * 从这儿开始改。 + */ // 如果当前rect已经属于某个类,则跳过它 if (current_rect.within_class) { continue; @@ -221,41 +229,33 @@ public class ObjectDetector { } uml_class.whole = new Rectangle(null, null, uml_class.top.x, uml_class.top.y, uml_class.top.width, whole_height); // 针对当前矩形,与所有其他矩形对比完毕后,则完成了该类的识别 - result.add(uml_class); + // result.add(uml_class); } System.out.println("完成将" + sd_path + "中所有矩形整合为类的业务,共" + result.size() + "个类"); return result; } - private List detectText(Mat cls_diagram, List classes) { + private List detectText(Mat s_diagram, List objects) { System.out.println("开始识别" + sd_path + "中每个类的文字"); - for (UMLClass uc : classes) { + for (UMLObject uc : objects) { ITesseract instance = new Tesseract(); instance.setDatapath(UMLDiagramRecognizer.tessdata_path); try { // 将uc中的每个区域写入临时文件,然后识别临时文件中的文字 if (uc.top != null) { - Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(cls_diagram, uc.top)); + Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(s_diagram, uc.top)); uc.setTitle(instance.doOCR(new File(temp_res_path))); } - if (uc.mid != null) { - Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(cls_diagram, uc.mid)); - uc.setAttrisStr(instance.doOCR(new File(temp_res_path))); - } - if (uc.bottom != null) { - Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(cls_diagram, uc.bottom)); - uc.setMethodsStr(instance.doOCR(new File(temp_res_path))); - } } catch (TesseractException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("完成对" + sd_path + "中每个类的文字识别"); - return classes; + return objects; } public Pair> getResult() { - return null; + return result; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java index 1d0721a..735e6d4 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -6,10 +6,16 @@ public class UMLObject { public List out_relas; public List in_relas; + public Rectangle top; public String getTitle() { // TODO Auto-generated method stub return null; } + public void setTitle(String doOCR) { + // TODO Auto-generated method stub + + } + } diff --git a/src/main/resources/cd/Salaboy_smart-tasks.txt b/src/main/resources/cd/Salaboy_smart-tasks.txt index db63982..8460154 100644 --- a/src/main/resources/cd/Salaboy_smart-tasks.txt +++ b/src/main/resources/cd/Salaboy_smart-tasks.txt @@ -191,6 +191,501 @@ claimfid : String) start(id : String) +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + complete(id : String,data : Object) @@= HumanTaskServiceOperations diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index 179515db827147318358c2040eab1f5a447bdc04..8168d374da3b1a99c80b558021c2bb9dd2dc9a29 100644 GIT binary patch literal 8161 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 XZ&=L9r~TyL?(+{89=Mu&V9VRwqT4Eu-o z{ZHBM6&NV>yxh4`BGBTaPmHV4ste76OO;xiI}Ys>{mESB68c51XGPSBo$k)QXHL#| zA-wcL<8m#lMUNJ+$o<)+?k&&Ee0t*fc8RqLZrU9exstXt;bVTR^xc-yXnADEidQ@d zHy(Q}wt9Hc>g$j7C#UHcv`dJG-aXptyYl$erjLC8jc-n3eI}56EhYFBW60g3Pao#p z@c+j6`bu($I?wM_#@Ajh^<61{RZZ^=^EDvN|GxhJr~WJ9caNqT++$o}l{~j9WbQ`4 zzbW2gGn{)OC;P5s4=5GS|6;j5=j5XgdiK|2_f-D&y0SDTNi&?N?pi zz<+GF(q3nvA))g>pIY{1s@?OczAu;RMkeqX>aDV3-n~QS>bnl5cJWKr3q0Nn^!)eB zU9{id>204z(F>q!R=)%CY=Q3AxMa=pc>lC}iW2qNU^jHHdiO{lX!ggGANnP~IT+kq z=uw}2`uF?YKO7%TUKqYxxnRftum8^PZ~;!~v>WW7FQ3nknRxHv#T8}l3r_rdZ_dYY4D6^gADpV%6WSnp4YN0C zeq{h!{;9ycX7Tw*28pX`_x9BNUe(PVy-DI~=G_=;jt#27 zAd0y$DI6SKGfZzzsbUB%FN}QBe|(kkhO Date: Tue, 2 Mar 2021 17:06:11 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E4=BB=8EObjectDetector=E7=9A=84140?= =?UTF-8?q?=E8=A1=8C=E7=BB=A7=E7=BB=AD=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/cddetector/ClassDetector.java | 8 +- .../umlrecog/sddetector/ObjectDetector.java | 130 +++--------------- .../hy/java/uct/umlrecog/util/Rectangle.java | 2 +- .../hy/java/uct/umlrecog/util/UMLObject.java | 13 +- 4 files changed, 31 insertions(+), 122 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java index 103d825..c64de98 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java @@ -121,13 +121,13 @@ public class ClassDetector { for (int all_rect_index = 0; all_rect_index < rect_area_list.size(); all_rect_index++) { Rectangle current_rect = rect_area_list.get(all_rect_index); // 如果当前rect已经属于某个类,则跳过它 - if (current_rect.within_class) { + if (current_rect.within_cls_obj) { continue; } // 如果当前rect不属于任何类,则将其赋给一个新的类 UMLClass uml_class = new UMLClass(); uml_class.list.add(current_rect); - current_rect.within_class = true; + current_rect.within_cls_obj = true; // 这个temp_rect用于每次拼接之后更新类的总大小。实际每次都是用temp_rect与其他未拼接的类作比较 uml_class.temp_rect = current_rect.clone(); // 对当前类的temp_rect,与all_rect_areas中其他所有矩形做比较 @@ -141,7 +141,7 @@ public class ClassDetector { if (uml_class.temp_rect.tl().y < other_rect.tl().y) { if (other_rect.tl().y - uml_class.temp_rect.tl().y - uml_class.temp_rect.height <= 5) { uml_class.list.add(other_rect); - other_rect.within_class = true; + other_rect.within_cls_obj = true; // 更新类的temp_rect uml_class.temp_rect.height += other_rect.height; } @@ -150,7 +150,7 @@ public class ClassDetector { else { if (uml_class.temp_rect.tl().y - other_rect.tl().y - other_rect.height <= 5) { uml_class.list.add(other_rect); - other_rect.within_class = true; + other_rect.within_cls_obj = true; // 更新类的temp_rect uml_class.temp_rect.x = other_rect.x; uml_class.temp_rect.y = other_rect.y; diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java index 158ddb3..d8e896c 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java @@ -108,6 +108,8 @@ public class ObjectDetector { private List mergeIntoObject(Pair> all_rect_areas_in_sd) { List result = new ArrayList<>(); + // 临时保存所有矩形形成的新对象。后面要对比这些对象的横纵坐标、舍去纵坐标靠下的矩形 + List temp_result = new ArrayList<>(); // Mat s_diagram = all_rect_areas_in_sd.getLeft(); // 获取所有矩形 List rect_area_list = all_rect_areas_in_sd.getRight(); @@ -122,116 +124,26 @@ public class ObjectDetector { */ for (int all_rect_index = 0; all_rect_index < rect_area_list.size(); all_rect_index++) { Rectangle current_rect = rect_area_list.get(all_rect_index); - /* - * 从这儿开始改。 - * - * 从这儿开始改。 - * - * 从这儿开始改。 - */ - // 如果当前rect已经属于某个类,则跳过它 - if (current_rect.within_class) { + // 如果当前rect已经属于某个对象,则跳过它 + if (current_rect.within_cls_obj) { continue; } - // 如果当前rect不属于任何类,则将其赋给一个新的类 - UMLClass uml_class = new UMLClass(); - uml_class.list.add(current_rect); - current_rect.within_class = true; - // 这个temp_rect用于每次拼接之后更新类的总大小。实际每次都是用temp_rect与其他未拼接的类作比较 - uml_class.temp_rect = current_rect.clone(); - // 对当前类的temp_rect,与all_rect_areas中其他所有矩形做比较 - for (int j = all_rect_index + 1; j < rect_area_list.size(); j++) { - // 获取all_rect_areas列表中位于current_rect后面的矩形 - Rectangle other_rect = rect_area_list.get(j); - // 针对该矩形的左上角,看是否与其他矩形的左上角横坐标相差不超过3~5个像素 - if (Math.abs(other_rect.tl().x - uml_class.temp_rect.tl().x) <= 5) { - // 如果是,则再看两个左上角的纵坐标距离是否大致等于“上面矩形”的高度 - // “上面矩形”是temp_rect - if (uml_class.temp_rect.tl().y < other_rect.tl().y) { - if (other_rect.tl().y - uml_class.temp_rect.tl().y - uml_class.temp_rect.height <= 5) { - uml_class.list.add(other_rect); - other_rect.within_class = true; - // 更新类的temp_rect - uml_class.temp_rect.height += other_rect.height; - } - } - // “上面矩形”是other_rect - else { - if (uml_class.temp_rect.tl().y - other_rect.tl().y - other_rect.height <= 5) { - uml_class.list.add(other_rect); - other_rect.within_class = true; - // 更新类的temp_rect - uml_class.temp_rect.x = other_rect.x; - uml_class.temp_rect.y = other_rect.y; - uml_class.temp_rect.height += other_rect.height; - } - } - } - } - // 将列表里的矩形按上、中、下排序 - uml_class.list.sort(new Comparator() { - @Override - public int compare(Rectangle r1, Rectangle r2) { - return Integer.valueOf(r1.y).compareTo(r2.y); - } - }); - for (int j = 0; j < uml_class.list.size(); j++) { - Rectangle r_in_l = uml_class.list.get(j); - if (r_in_l != null) { - switch (j) { - case 0: { - uml_class.top = r_in_l; - break; - } - case 1: { - uml_class.mid = r_in_l; - break; - } - case 2: { - uml_class.bottom = r_in_l; - break; - } - default: - break; - } - } - } - /* - * 此时会出现top其实是整个矩形的情况。需将top、mid、bottom重新分割 - */ - if (uml_class.mid != null) { - if (uml_class.bottom != null) { - if (uml_class.top.y + uml_class.top.height >= uml_class.bottom.y + uml_class.bottom.height) { - int top_old_height = uml_class.top.height; - uml_class.top = uml_class.mid.clone(); - uml_class.mid = uml_class.bottom.clone(); - uml_class.bottom.y = uml_class.top.y + uml_class.top.height + uml_class.mid.height; - uml_class.bottom.height = top_old_height - uml_class.top.height - uml_class.mid.height; - } - } else { - if (uml_class.top.y + uml_class.top.height >= uml_class.mid.y + uml_class.mid.height) { - int top_old_height = uml_class.top.height; - uml_class.top = uml_class.mid.clone(); - uml_class.mid.y = uml_class.top.y + uml_class.top.height; - uml_class.mid.height = top_old_height - uml_class.top.height; - } - } - } - // 计算类框整体大小 - int whole_height = 0; - // 先将whole的高度设置为top的高度 - whole_height += uml_class.top.height; - if (uml_class.mid != null) { - whole_height += uml_class.mid.height; - } - if (uml_class.bottom != null) { - whole_height += uml_class.bottom.height; + // 如果当前rect不属于任何对象,则将其赋给一个新的对象 + UMLObject uml_obj = new UMLObject(); + current_rect.within_cls_obj = true; + uml_obj.whole = current_rect; + temp_result.add(uml_obj); + } + // 检测temp_result中所有矩形横坐标。如果两个矩形横坐标一样,则舍去纵坐标靠下的矩形。 + for (UMLObject uml_obj : temp_result) { + // 针对当前矩形,查找是否有与其横坐标大致一样的其他矩形 + // other_rects + if (true) { + } - uml_class.whole = new Rectangle(null, null, uml_class.top.x, uml_class.top.y, uml_class.top.width, whole_height); - // 针对当前矩形,与所有其他矩形对比完毕后,则完成了该类的识别 - // result.add(uml_class); + // 针对当前矩形,与所有其他矩形对比完毕后,则完成了该对象的识别 + // result.add(uml_obj); } - System.out.println("完成将" + sd_path + "中所有矩形整合为类的业务,共" + result.size() + "个类"); return result; } @@ -242,8 +154,8 @@ public class ObjectDetector { instance.setDatapath(UMLDiagramRecognizer.tessdata_path); try { // 将uc中的每个区域写入临时文件,然后识别临时文件中的文字 - if (uc.top != null) { - Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(s_diagram, uc.top)); + if (uc.whole != null) { + Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(s_diagram, uc.whole)); uc.setTitle(instance.doOCR(new File(temp_res_path))); } } catch (TesseractException e) { @@ -251,7 +163,7 @@ public class ObjectDetector { e.printStackTrace(); } } - System.out.println("完成对" + sd_path + "中每个类的文字识别"); + System.out.println("完成对" + sd_path + "中对象的识别业务,共" + objects.size() + "个对象"); return objects; } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Rectangle.java b/src/main/java/com/hy/java/uct/umlrecog/util/Rectangle.java index f374ad6..ee787b3 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Rectangle.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Rectangle.java @@ -12,7 +12,7 @@ import org.opencv.core.Rect; public class Rectangle extends Rect { private Mat mat; private MatOfPoint contour; - public boolean within_class = false; + public boolean within_cls_obj = false; public Rectangle(Mat cls_diagram, MatOfPoint contour, MatOfPoint2f approx_rect) { super(new Point(approx_rect.get(0, 0)[0], approx_rect.get(0, 0)[1]), new Point(approx_rect.get(2, 0)[0], approx_rect.get(2, 0)[1])); diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java index 735e6d4..f12542b 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -3,19 +3,16 @@ package com.hy.java.uct.umlrecog.util; import java.util.List; public class UMLObject { - + public Rectangle whole; + private String title; public List out_relas; public List in_relas; - public Rectangle top; public String getTitle() { - // TODO Auto-generated method stub - return null; + return title; } - public void setTitle(String doOCR) { - // TODO Auto-generated method stub - + public void setTitle(String title) { + this.title = title; } - } -- Gitee From 1aee922775eb446bf196eff343e6ce9b54264297 Mon Sep 17 00:00:00 2001 From: origin Date: Thu, 4 Mar 2021 12:13:39 +0800 Subject: [PATCH 04/14] =?UTF-8?q?ObjectDetector=E7=9A=84139~177=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E8=BF=98=E9=9C=80=E4=BF=AE=E6=94=B9=E3=80=82=E7=9B=AE?= =?UTF-8?q?=E5=89=8D=E4=BC=9A=E9=87=8D=E5=A4=8D=E8=AE=B0=E5=BD=95=E6=A8=AA?= =?UTF-8?q?=E5=9D=90=E6=A0=87=E7=9B=B8=E5=90=8C=E7=9A=84=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/umlrecog/UMLDiagramRecognizer.java | 4 +- .../umlrecog/sddetector/ObjectDetector.java | 70 ++- .../hy/java/uct/umlrecog/util/UMLObject.java | 7 + src/main/resources/cd/Salaboy_smart-tasks.txt | 495 ++++++++++++++++++ src/main/resources/sd/temp result.png | Bin 8161 -> 665 bytes 5 files changed, 558 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java index dfdbf4b..533850a 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java @@ -33,7 +33,7 @@ public class UMLDiagramRecognizer { * 测试一下识别特定的类图和顺序图 */ public static void main(String[] args) { - UMLDiagramRecognizer.recogCD(cd_dir, "Salaboy/smart-tasks"); - UMLDiagramRecognizer.recogSD(sd_dir, "albanoj2/grp"); + // UMLDiagramRecognizer.recogCD(cd_dir, "Salaboy/smart-tasks"); + UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent"); } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java index d8e896c..e16b9ae 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java @@ -3,6 +3,7 @@ package com.hy.java.uct.umlrecog.sddetector; import java.io.File; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import org.opencv.core.Mat; @@ -15,7 +16,6 @@ import org.opencv.imgproc.Imgproc; import com.hy.java.uct.umlrecog.UMLDiagramRecognizer; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Rectangle; -import com.hy.java.uct.umlrecog.util.UMLClass; import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.Pair; @@ -134,37 +134,75 @@ public class ObjectDetector { uml_obj.whole = current_rect; temp_result.add(uml_obj); } - // 检测temp_result中所有矩形横坐标。如果两个矩形横坐标一样,则舍去纵坐标靠下的矩形。 - for (UMLObject uml_obj : temp_result) { + int temp_size = temp_result.size(); + // 检测temp_result中所有矩形横坐标。如果存在多个矩形横坐标一样,则只保留纵坐标最靠上的矩形、舍去其他所有矩形。 + for (int i = 0; i < temp_size; i++) { + UMLObject uml_obj = temp_result.get(i); + // 如果should_be_del,则说明uml_obj在一列横坐标相近的矩形中纵坐标靠下,且已被舍去,所以直接跳过 + if (uml_obj.should_be_del) { + continue; + } + // 临时保存所有横坐标相近的矩形在temp_result中的索引,用于后面比对纵坐标 + List similar_ys = new ArrayList<>(); + similar_ys.add(i); // 针对当前矩形,查找是否有与其横坐标大致一样的其他矩形 - // other_rects - if (true) { - + for (int j = 0; j < temp_size; j++) { + if (j != i) { + UMLObject other_uml_obj = temp_result.get(j); + if (Math.abs(uml_obj.whole.x - other_uml_obj.whole.x) <= 3) { + // 记录与当前矩形横坐标大致一样的其他矩形在temp_result中的索引 + similar_ys.add(j); + } + } + } + // 对所有横坐标相近的矩形按纵坐标从小到大排序 + similar_ys.sort(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return Integer.valueOf(temp_result.get(o1).whole.y).compareTo(temp_result.get(o2).whole.y); + } + }); + // 对所有横坐标相近的矩形,只保留纵坐标最靠上的矩形、舍去其他所有矩形。 + // 现在similar_ys的第一个元素,记录的是与当前矩形横坐标相近的矩形中,纵坐标最靠上的矩形在temp_result中的索引 + for (int j = 0; j < similar_ys.size(); j++) { + if (j == 0) { + // 只保留纵坐标最靠上的矩形 + result.add(temp_result.get(similar_ys.get(j))); + } else { + // 舍去其他所有矩形 + temp_result.get(similar_ys.get(j)).should_be_del = true; + } } - // 针对当前矩形,与所有其他矩形对比完毕后,则完成了该对象的识别 - // result.add(uml_obj); + } return result; } private List detectText(Mat s_diagram, List objects) { - System.out.println("开始识别" + sd_path + "中每个类的文字"); - for (UMLObject uc : objects) { + List result = new ArrayList<>(); + System.out.println("开始识别" + sd_path + "中每个对象的文字"); + for (UMLObject uo : objects) { ITesseract instance = new Tesseract(); instance.setDatapath(UMLDiagramRecognizer.tessdata_path); try { - // 将uc中的每个区域写入临时文件,然后识别临时文件中的文字 - if (uc.whole != null) { - Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(s_diagram, uc.whole)); - uc.setTitle(instance.doOCR(new File(temp_res_path))); + // 将uo中的每个区域写入临时文件,然后识别临时文件中的文字 + if (uo.whole != null) { + Imgcodecs.imwrite(temp_res_path, ImgProcessor.cutImage(s_diagram, uo.whole)); + uo.setTitle(instance.doOCR(new File(temp_res_path))); } } catch (TesseractException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - System.out.println("完成对" + sd_path + "中对象的识别业务,共" + objects.size() + "个对象"); - return objects; + // 清除无文字的矩形,则剩下的就是对象 + for (UMLObject uo : objects) { + if (!uo.getTitle().isBlank()) { + result.add(uo); + } + } + System.out.println("完成对" + sd_path + "中对象的识别业务,共" + result.size() + "个对象"); + return result; } public Pair> getResult() { diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java index f12542b..ac33f30 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -3,6 +3,13 @@ package com.hy.java.uct.umlrecog.util; import java.util.List; public class UMLObject { + /** + * 只在mergeIntoObject时使用 + */ + public boolean should_be_del = false; + /** + * 此UMLObject的信息 + */ public Rectangle whole; private String title; public List out_relas; diff --git a/src/main/resources/cd/Salaboy_smart-tasks.txt b/src/main/resources/cd/Salaboy_smart-tasks.txt index 8460154..d5ce72e 100644 --- a/src/main/resources/cd/Salaboy_smart-tasks.txt +++ b/src/main/resources/cd/Salaboy_smart-tasks.txt @@ -686,6 +686,501 @@ claimfid : String) start(id : String) +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + +complete(id : String,data : Object) +@@= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥#JBPMSMinaHumanTaskClientConfiguration +@@getServiceOperationsimplementation() : HumanTaskServiceOperations +@JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#JBPMSHUmanTaskServiceOperations +@taskClient : TaskClient +configuration : JEPMSHumanTaskClientConfiguration +@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) +@JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskServiceOperations +%实现¥#HumanTaskServicelmpl +@taskOperations : Map +@@HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥#JBPMSHUmanTaskClientConfiguration +@port : String +host : String +@JBPMSHumanTaskClientConfiguration(port : String,host : String) +@JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥JBPMSMinaHumanTaskClientConfiguration +%JBPMSHUmanTaskClientConfiguration +%聚合¥#==interface=: +HumanTaskservice +@getTaskOperations() : Map +@null@==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥HumanTaskServicelmpl +%==interface=: +HumanTaskservice +%实现¥#< +HumanTaskclientConfiguration +@getServiceOperationsimplementation() : HumanTaskServiceOperations +@null@< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥JBPMSHUmanTaskClientConfiguration +%< +HumanTaskclientConfiguration +%实现¥#= +HumanTaskServiceOperations +@getTaskOriginatorType(Taskid : String) : String +@null@= +HumanTaskServiceOperations +%HumanTaskServicelmpl +%聚合¥= +HumanTaskServiceOperations +%= +TaskOperations +%聚合¥JBPMSHUmanTaskServiceOperations +%= +HumanTaskServiceOperations +%实现¥< +HumanTaskclientConfiguration +%= +HumanTaskServiceOperations +%实现¥==interface=: +HumanTaskservice +%= +HumanTaskServiceOperations +%聚合¥#HumanTaskServiceConfiguration +@clientConfs : Map +@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) +getHumarTaskClientConfigurations() : Map +@< +HumanTaskclientConfiguration +%HumanTaskServiceConfiguration +%聚合¥#= +TaskOperations +@getMyTaskabstracts(taskType : String) : TTaskAbstract +geyMyTasks(taskType : String) : TTask + +getTaskinfoid : String) : TTask + +claimfid : String) + +start(id : String) + complete(id : String,data : Object) @@= HumanTaskServiceOperations diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index 8168d374da3b1a99c80b558021c2bb9dd2dc9a29..3cc0e396490415388d4d76ec0844f5f4f47cad8d 100644 GIT binary patch literal 665 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 XZ&=L9r~TyL?(+{89=Mu& Date: Thu, 4 Mar 2021 21:58:49 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E5=B7=B2=E8=AF=86=E5=88=AB=E5=AE=8C?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E5=9B=BE=E5=AF=B9=E8=B1=A1=E3=80=82=E6=8E=A5?= =?UTF-8?q?=E4=B8=8B=E6=9D=A5=E6=94=B9MessageDetector?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/MessageDetector.java | 48 +++++++++--------- .../umlrecog/sddetector/ObjectDetector.java | 6 +-- .../hy/java/uct/umlrecog/util/Message.java | 9 ++++ src/main/resources/sd/temp result.png | Bin 665 -> 90 bytes 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index fb69ee8..63513c4 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -19,6 +19,7 @@ import org.opencv.imgproc.Imgproc; import com.hy.java.uct.umlrecog.cddetector.ClassRelationDetector; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Line; +import com.hy.java.uct.umlrecog.util.Message; import com.hy.java.uct.umlrecog.util.PolygonalLine; import com.hy.java.uct.umlrecog.util.Relation; import com.hy.java.uct.umlrecog.util.UMLClass; @@ -28,34 +29,33 @@ import com.hy.java.utility.common.Pair; public class MessageDetector { private String cd_path = null; private String temp_res_path = null; - private Pair> classes_in_cd = null; - private Pair> result = null; + private Pair> classes_in_cd = null; + private Pair> result = null; public MessageDetector(String repo_cd_path, Pair> objects) { this.cd_path = repo_cd_path; this.temp_res_path = cd_path.replaceAll(cd_path.substring(cd_path.lastIndexOf("\\") + 1, cd_path.lastIndexOf(".")), "temp result"); - // 这句需要改成List - // this.classes_in_cd = objects; + this.classes_in_cd = objects; } public void recog() { // 先检测实线。检测结果需借助类的位置关系、去除“单纯的线” - Set solid_lines = detectLines(classes_in_cd, 0.0504, true); + Set solid_lines = detectLines(classes_in_cd, 0.0504, true); // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 - Set dash_lines = detectLines(classes_in_cd, 0.0504, false); + Set dash_lines = detectLines(classes_in_cd, 0.0504, false); // 再检测关系类型检测。由于会遍历所有关系,所以顺便将关系存在classes_in_cd中每个UMLClass的关系列表中 result = detectRelationType(classes_in_cd, solid_lines, dash_lines, 0.0001); } - private Set detectLines(Pair> classes_in_cd, double ratio, boolean detect_solid) { - Set result = new HashSet<>(); + private Set detectLines(Pair> classes_in_cd2, double ratio, boolean detect_solid) { + Set result = new HashSet<>(); if (detect_solid) { System.out.println("开始识别" + cd_path + "中的实线"); } else { System.out.println("开始识别" + cd_path + "中的虚线"); } - Mat cls_diagram = classes_in_cd.getLeft(); - List UML_classes = classes_in_cd.getRight(); + Mat cls_diagram = classes_in_cd2.getLeft(); + List UML_classes = classes_in_cd2.getRight(); /* * 先检测边缘,然后从边缘集中初步检测“原始直线” */ @@ -142,9 +142,9 @@ public class MessageDetector { * 针对每条候选关系线,计算每个类方框的4根边框线,看哪个边框线与当前候选关系线相交(允许一定像素的误差),则认为这条线确实是关系线,且属于相交的类 */ for (PolygonalLine pl : poly_lines) { - Relation rela = new Relation(pl); + Message rela = new Message(pl); // 对pl.pt1和pl.pt2,需要将其延直线方向延长一点,检查延长后的端点。 - for (UMLClass uml_class : UML_classes) { + for (UMLObject uml_class : UML_classes) { // 检查延长后的端点 if (uml_class.whole.contains(ImgProcessor.reachPt(pl.pt1, pl.l1, 35, false))) { // 暂时将与pt1相近的类记为source、与pt2相近的类为target,后面识别出符号来后再调 @@ -164,7 +164,7 @@ public class MessageDetector { */ if (detect_solid) { // 实线识别结果 - for (Relation rela : result) { + for (Message 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 + ")"); // 在图中抹掉已识别的线,防止干扰后续识别 @@ -178,7 +178,7 @@ public class MessageDetector { System.out.println("完成对" + cd_path + "中的实线识别,共" + result.size() + "条"); } else { // 虚线识别结果 - for (Relation rela : result) { + for (Message 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 + ")"); // 在图中抹掉已识别的线,防止干扰后续识别 @@ -332,15 +332,15 @@ public class MessageDetector { /** * 识别关系符号,并根据关系符号与关系线端点的位置关系更新关系线的source和target * - * @param classes_in_cd + * @param classes_in_cd2 * @param dash_lines * @param solid_lines * @param dash_lines * @return */ - private Pair> detectRelationType(Pair> classes_in_cd, Set solid_lines, Set dash_lines, double ratio) { + private Pair> detectRelationType(Pair> classes_in_cd2, Set solid_lines, Set dash_lines, double ratio) { System.out.println("开始识别" + cd_path + "中所有关系符号"); - Mat cls_diagram = classes_in_cd.getLeft(); + Mat cls_diagram = classes_in_cd2.getLeft(); Mat origin_cls_diagram = Imgcodecs.imread(cd_path, Imgcodecs.IMREAD_GRAYSCALE); /* * 识别图中所有“轮廓”并存在contours中 @@ -374,7 +374,7 @@ public class MessageDetector { // 如果包络矩形包含某一条关系线的某一端,则检测该矩形内的符号 // 对于虚线,由于只可能是实现或生命线,所以只需要知道是否包含即可,不用检测矩形内部图形。belong_to_dash_rela为true表示当前关系符号属于某条虚线关系线 boolean belong_to_dash_rela = false; - for (Relation dash_rela : dash_lines) { + for (Message dash_rela : dash_lines) { // 如果dash_rela.source_pt_index != -1,则说明该dash_rela已经与某一包络矩形检测并对应上了,则跳过 if (dash_rela.source_pt_index != -1) { continue; @@ -386,7 +386,7 @@ public class MessageDetector { belong_to_dash_rela = true; // 重新设置虚线的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; + UMLObject temp = dash_rela.source; dash_rela.source = dash_rela.target; dash_rela.target = temp; } @@ -401,7 +401,7 @@ public class MessageDetector { belong_to_dash_rela = true; // 重新设置虚线的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; + UMLObject temp = dash_rela.source; dash_rela.source = dash_rela.target; dash_rela.target = temp; } @@ -416,7 +416,7 @@ public class MessageDetector { // 如果该关系符号不属于任何虚线关系,则检测其是否属于某实线关系 if (!belong_to_dash_rela) { // 对于实线,需检测矩形内部图形,识别继承、聚合 - for (Relation solid_rela : solid_lines) { + for (Message solid_rela : solid_lines) { // 如果solid_line.source_pt_index != -1,则说明该solid_line已经与某一包络矩形检测并对应上了,则跳过 if (solid_rela.source_pt_index != -1) { continue; @@ -430,7 +430,7 @@ public class MessageDetector { belong_to_this_solid_rela = true; // 重新设置虚线的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; + UMLObject temp = solid_rela.source; solid_rela.source = solid_rela.target; solid_rela.target = temp; } @@ -440,7 +440,7 @@ public class MessageDetector { belong_to_this_solid_rela = true; // 重新设置虚线的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; + UMLObject temp = solid_rela.source; solid_rela.source = solid_rela.target; solid_rela.target = temp; } @@ -499,7 +499,7 @@ public class MessageDetector { } } System.out.println("完成对" + cd_path + "中识别关系符号的识别。"); - return classes_in_cd; + return classes_in_cd2; } public Pair> getResult() { diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java index e16b9ae..2bb03b7 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/ObjectDetector.java @@ -3,7 +3,6 @@ package com.hy.java.uct.umlrecog.sddetector; import java.io.File; import java.util.ArrayList; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import org.opencv.core.Mat; @@ -168,10 +167,9 @@ public class ObjectDetector { if (j == 0) { // 只保留纵坐标最靠上的矩形 result.add(temp_result.get(similar_ys.get(j))); - } else { - // 舍去其他所有矩形 - temp_result.get(similar_ys.get(j)).should_be_del = true; } + // 舍去其他所有矩形。注意此时也应将本次添加的矩形舍去,防止重复记录 + temp_result.get(similar_ys.get(j)).should_be_del = true; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java index 1256f11..11839b3 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java @@ -2,4 +2,13 @@ package com.hy.java.uct.umlrecog.util; public class Message { + public UMLObject source; + public UMLObject target; + public PolygonalLine poly_line; + public int source_pt_index; + public String type; + + public Message(PolygonalLine pl) { + // TODO Auto-generated constructor stub + } } diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index 3cc0e396490415388d4d76ec0844f5f4f47cad8d..1ef080a10df209c77528f0b59c0138ee0be7f8d2 100644 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^kwDDO0VEjQp6vSqq!c|}978ljw;p6<1oD~`{@ULP iV>#AYm^4R19Zd0DVPR+7`pW4$NRy|lpUXO@geCx<+8CVx literal 665 zcmeAS@N?(olHy`uVBq!ia0vp^en4!<0VEg#w;s64z`&H?>EamT!MpaLug5h83HA^F zm9s=rqgS-vV)qc#^;Y@w;w+DTre2&?*B3`Nxs-rQiEL9nw&?{vnDF7TLPtVmhY64J ziU~YQN|LHGJhlT!H1z@{A zlu*q53Uu&x-F%+uyMmHLL)jbqfBs&zG3&$O+e&w5o^@kMYWXr}@6DD2Z_eG|2)niG zSi|ABt?T^~&IYu;tKd=+P<|4bnyb#Fy!0dEnpxHN-Y=>DTeD;tdv?k3V36tdmp7}K zC51kod%JhC?9xz%N6qiQYu^+;$q@DbO8!+@e@CGCFVD?npZUODyrSlNjo-f)Y->dN z&Zb}c5|_;wH~o3vWQa96%WAAr?=M?<^vSu;4u|*NS@k4w`$Ii3uVvjy+ Date: Fri, 5 Mar 2021 16:40:24 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E4=BB=8EMessageDetector=E7=9A=84133?= =?UTF-8?q?=E8=A1=8C=E5=BC=80=E5=A7=8B=EF=BC=8C=E6=A3=80=E6=B5=8B=E7=BA=BF?= =?UTF-8?q?=E4=B8=8E=E5=AF=B9=E8=B1=A1=E7=9A=84=E4=BD=8D=E7=BD=AE=E5=85=B3?= =?UTF-8?q?=E7=B3=BB=EF=BC=8C=E8=AE=BE=E7=BD=AE=E5=A5=BDsource=E3=80=81tar?= =?UTF-8?q?get=E5=8D=B3=E5=8F=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/SequenceDiagramRecognizer.java | 4 +- .../cddetector/ClassRelationDetector.java | 2 +- .../umlrecog/sddetector/MessageDetector.java | 116 ++++++++++-------- .../hy/java/uct/umlrecog/util/Message.java | 2 +- .../hy/java/uct/umlrecog/util/UMLObject.java | 4 +- 5 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java index 02f2006..4093a0f 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/SequenceDiagramRecognizer.java @@ -56,10 +56,10 @@ public class SequenceDiagramRecognizer { // 想想写的格式!!!!!!!!! // 比如@、#、¥、%等分隔符等级 fe.write(UML_class.getTitle() + "@", true); - for (Message out_rel : UML_class.out_relas) { + for (Message out_rel : UML_class.out_msgs) { } - for (Message in_rel : UML_class.in_relas) { + for (Message in_rel : UML_class.in_msgs) { } } 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 bb0b412..7d91d77 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 @@ -40,7 +40,7 @@ public class ClassRelationDetector { Set solid_lines = detectLines(classes_in_cd, 0.0504, true); // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 Set dash_lines = detectLines(classes_in_cd, 0.0504, false); - // 再检测关系类型检测。由于会遍历所有关系,所以顺便将关系存在classes_in_cd中每个UMLClass的关系列表中 + // 再检测关系类型。由于会遍历所有关系,所以顺便将关系存在classes_in_cd中每个UMLClass的关系列表中 result = detectRelationType(classes_in_cd, solid_lines, dash_lines, 0.0001); } diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 63513c4..7e9d0df 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -16,56 +16,53 @@ import org.opencv.core.Size; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; -import com.hy.java.uct.umlrecog.cddetector.ClassRelationDetector; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Line; import com.hy.java.uct.umlrecog.util.Message; import com.hy.java.uct.umlrecog.util.PolygonalLine; -import com.hy.java.uct.umlrecog.util.Relation; -import com.hy.java.uct.umlrecog.util.UMLClass; import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.Pair; public class MessageDetector { - private String cd_path = null; + private String sd_path = null; private String temp_res_path = null; - private Pair> classes_in_cd = null; + private Pair> objects_in_sd = null; private Pair> result = null; - public MessageDetector(String repo_cd_path, Pair> objects) { - this.cd_path = repo_cd_path; - this.temp_res_path = cd_path.replaceAll(cd_path.substring(cd_path.lastIndexOf("\\") + 1, cd_path.lastIndexOf(".")), "temp result"); - this.classes_in_cd = objects; + public MessageDetector(String repo_sd_path, Pair> objects) { + this.sd_path = repo_sd_path; + this.temp_res_path = sd_path.replaceAll(sd_path.substring(sd_path.lastIndexOf("\\") + 1, sd_path.lastIndexOf(".")), "temp result"); + this.objects_in_sd = objects; } public void recog() { - // 先检测实线。检测结果需借助类的位置关系、去除“单纯的线” - Set solid_lines = detectLines(classes_in_cd, 0.0504, true); + // 先检测实线。检测结果需借助对象的位置关系、去除“单纯的线” + Set solid_lines = detectLines(objects_in_sd, 0.0504, true); // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 - Set dash_lines = detectLines(classes_in_cd, 0.0504, false); - // 再检测关系类型检测。由于会遍历所有关系,所以顺便将关系存在classes_in_cd中每个UMLClass的关系列表中 - result = detectRelationType(classes_in_cd, solid_lines, dash_lines, 0.0001); + Set dash_lines = detectLines(objects_in_sd, 0.0504, false); + // 再检测消息内容。由于会遍历所有关系,所以顺便将关系存在objects_in_sd中每个UMLObject的关系列表中 + result = detectRelationType(objects_in_sd, solid_lines, dash_lines, 0.0001); } - private Set detectLines(Pair> classes_in_cd2, double ratio, boolean detect_solid) { + private Set detectLines(Pair> objects_in_sd, double ratio, boolean detect_solid) { Set result = new HashSet<>(); if (detect_solid) { - System.out.println("开始识别" + cd_path + "中的实线"); + System.out.println("开始识别" + sd_path + "中的实线"); } else { - System.out.println("开始识别" + cd_path + "中的虚线"); + System.out.println("开始识别" + sd_path + "中的虚线"); } - Mat cls_diagram = classes_in_cd2.getLeft(); - List UML_classes = classes_in_cd2.getRight(); + Mat sd_diagram = objects_in_sd.getLeft(); + List UML_objects = objects_in_sd.getRight(); /* * 先检测边缘,然后从边缘集中初步检测“原始直线” */ List line_segments = new ArrayList<>(); // 先检测边缘。然后从边缘集中检测直线 Mat edges = new Mat(); - Imgproc.Canny(cls_diagram, edges, 50, 50 * 3, 3, true); + Imgproc.Canny(sd_diagram, edges, 50, 50 * 3, 3, true); // 从边缘集中检测直线。膨胀(将线外面的空白区域膨胀)、腐蚀(让线侵蚀周围的空白区域),可以提高识别准确率 - Imgproc.dilate(cls_diagram, cls_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1.7, 1.7)), new Point(-1, -1), 2); - Imgproc.erode(cls_diagram, cls_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 1)), new Point(-1, -1), 1); + Imgproc.dilate(sd_diagram, sd_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1.7, 1.7)), new Point(-1, -1), 2); + Imgproc.erode(sd_diagram, sd_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 1)), new Point(-1, -1), 1); Mat lines = new Mat(); if (detect_solid) { // 实线检测时,“最小直线长度”与图像像素有关;“最大像素间隔”越小越接近实线 @@ -113,7 +110,8 @@ public class MessageDetector { 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; } } @@ -132,6 +130,20 @@ public class MessageDetector { } } } + /* + * 从这里开始。现在所有线已识别出来(需看一下效果) + * + * 之后检测线与对象的位置关系,设置好source、target即可 + * + * + * 可能不需要PolygonalLine这么麻烦的东西 + * + * !!!!!!!!!!!!!!!!!!!!!! + * + * !!!!!!!!!!!!!!!!!!!!!! + * + * !!!!!!!!!!!!!!!!!!!!!! + */ /* * 对所有实线,将可能的“折线”识别并合并。合并为折线的直线,其belonged_polygonal_line会标识其所属折线 */ @@ -144,7 +156,7 @@ public class MessageDetector { for (PolygonalLine pl : poly_lines) { Message rela = new Message(pl); // 对pl.pt1和pl.pt2,需要将其延直线方向延长一点,检查延长后的端点。 - for (UMLObject uml_class : UML_classes) { + for (UMLObject uml_class : UML_objects) { // 检查延长后的端点 if (uml_class.whole.contains(ImgProcessor.reachPt(pl.pt1, pl.l1, 35, false))) { // 暂时将与pt1相近的类记为source、与pt2相近的类为target,后面识别出符号来后再调 @@ -166,30 +178,32 @@ public class MessageDetector { // 实线识别结果 for (Message 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); + Imgproc.line(sd_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); } // 看一眼。看结果相当于把抹掉的线再画出来,会影响后续识别,所以看完就注释掉 // Imgproc.line(cls_diagram, rela.poly_line.pt1, rela.poly_line.pt2, new Scalar(55, 55, 55), 5); } - Imgcodecs.imwrite(temp_res_path, cls_diagram); - System.out.println("完成对" + cd_path + "中的实线识别,共" + result.size() + "条"); + Imgcodecs.imwrite(temp_res_path, sd_diagram); + System.out.println("完成对" + sd_path + "中的实线识别,共" + result.size() + "条"); } else { // 虚线识别结果 for (Message 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); + Imgproc.line(sd_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); } // 看一眼。看结果相当于把抹掉的线再画出来,会影响后续识别,所以看完就注释掉 // Imgproc.line(cls_diagram, rela.poly_line.pt1, rela.poly_line.pt2, new Scalar(55, 55, 55), 5); } - Imgcodecs.imwrite(temp_res_path, cls_diagram); - System.out.println("完成对" + cd_path + "中的虚线识别,共" + result.size() + "条"); + Imgcodecs.imwrite(temp_res_path, sd_diagram); + System.out.println("完成对" + sd_path + "中的虚线识别,共" + result.size() + "条"); } return result; } @@ -339,9 +353,9 @@ public class MessageDetector { * @return */ private Pair> detectRelationType(Pair> classes_in_cd2, Set solid_lines, Set dash_lines, double ratio) { - System.out.println("开始识别" + cd_path + "中所有关系符号"); + System.out.println("开始识别" + sd_path + "中所有关系符号"); Mat cls_diagram = classes_in_cd2.getLeft(); - Mat origin_cls_diagram = Imgcodecs.imread(cd_path, Imgcodecs.IMREAD_GRAYSCALE); + Mat origin_cls_diagram = Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE); /* * 识别图中所有“轮廓”并存在contours中 */ @@ -391,12 +405,13 @@ public class MessageDetector { dash_rela.target = temp; } dash_rela.source_pt_index = 2; - dash_rela.type = "实现"; + dash_rela.msg = "实现"; // 记录当前关系到UMLClass里 - dash_rela.source.out_relas.add(dash_rela); - dash_rela.target.in_relas.add(dash_rela); + dash_rela.source.out_msgs.add(dash_rela); + dash_rela.target.in_msgs.add(dash_rela); break; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -406,10 +421,10 @@ public class MessageDetector { dash_rela.target = temp; } dash_rela.source_pt_index = 1; - dash_rela.type = "实现"; + dash_rela.msg = "实现"; // 记录当前关系到UMLClass里 - dash_rela.source.out_relas.add(dash_rela); - dash_rela.target.in_relas.add(dash_rela); + dash_rela.source.out_msgs.add(dash_rela); + dash_rela.target.in_msgs.add(dash_rela); break; } } @@ -424,7 +439,8 @@ public class MessageDetector { // 记录该包络矩形是否属于当前实线关系线solid_rela。如果是的话,再去检测矩形内图形 boolean belong_to_this_solid_rela = false; // 方法同对dash_rela的检测。对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。 - 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)) + 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; @@ -435,7 +451,8 @@ public class MessageDetector { solid_rela.target = temp; } solid_rela.source_pt_index = 2; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -477,7 +494,8 @@ public class MessageDetector { 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))) { + 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 = "继承"; } /* @@ -487,10 +505,10 @@ public class MessageDetector { // Imgcodecs.imwrite(temp_res_path, cutted_origin_rela_type_area); } } - solid_rela.type = type; + solid_rela.msg = type; // 记录当前关系到result里 - solid_rela.source.out_relas.add(solid_rela); - solid_rela.target.in_relas.add(solid_rela); + solid_rela.source.out_msgs.add(solid_rela); + solid_rela.target.in_msgs.add(solid_rela); // 检测完符号类别后,对当前区域就算检测完了,不用再检测其他实线了 break; } @@ -498,11 +516,11 @@ public class MessageDetector { // 如果运行到这儿(检测完符号类别后break会直接到这儿),说明对当前区域的包络矩形与实线之间的检测完毕。相当于对当前区域检测完毕,开始检测下一个区域 } } - System.out.println("完成对" + cd_path + "中识别关系符号的识别。"); + System.out.println("完成对" + sd_path + "中识别关系符号的识别。"); return classes_in_cd2; } public Pair> getResult() { - return null; + return result; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java index 11839b3..694dcfd 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java @@ -6,7 +6,7 @@ public class Message { public UMLObject target; public PolygonalLine poly_line; public int source_pt_index; - public String type; + public String msg; public Message(PolygonalLine pl) { // TODO Auto-generated constructor stub diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java index ac33f30..8b8ff11 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -12,8 +12,8 @@ public class UMLObject { */ public Rectangle whole; private String title; - public List out_relas; - public List in_relas; + public List out_msgs; + public List in_msgs; public String getTitle() { return title; -- Gitee From 9f67c25c920147c283dcd765d5fdec2b1423686a Mon Sep 17 00:00:00 2001 From: origin Date: Mon, 8 Mar 2021 11:38:20 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E7=B1=BB=E5=9B=BE=E5=B0=8F=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cddetector/ClassRelationDetector.java | 2 +- src/main/resources/cd/Salaboy_smart-tasks.txt | 1109 +---------------- 2 files changed, 11 insertions(+), 1100 deletions(-) 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 7d91d77..0e440a4 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 @@ -445,7 +445,7 @@ public class ClassRelationDetector { } // 目前该关系符号确实属于当前实线关系solid_rela,所以需检查其是聚合还是继承 if (belong_to_this_solid_rela) { - String type = "聚合"; + String type = "依赖"; // 裁剪原图中包含关系符号的矩形区域 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); diff --git a/src/main/resources/cd/Salaboy_smart-tasks.txt b/src/main/resources/cd/Salaboy_smart-tasks.txt index d5ce72e..abc6e87 100644 --- a/src/main/resources/cd/Salaboy_smart-tasks.txt +++ b/src/main/resources/cd/Salaboy_smart-tasks.txt @@ -4,7 +4,7 @@ JBPMSMinaHumanTaskClientConfiguration %JBPMSHUmanTaskServiceOperations %实现¥JBPMSMinaHumanTaskClientConfiguration %JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations +%依赖¥#JBPMSHUmanTaskServiceOperations @taskClient : TaskClient configuration : JEPMSHumanTaskClientConfiguration @JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) @@ -21,7 +21,7 @@ HumanTaskservice %实现¥= HumanTaskServiceOperations %HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration +%依赖¥#JBPMSHUmanTaskClientConfiguration @port : String host : String @JBPMSHumanTaskClientConfiguration(port : String,host : String) @@ -30,14 +30,14 @@ host : String HumanTaskclientConfiguration %实现¥JBPMSMinaHumanTaskClientConfiguration %JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: +%依赖¥#==interface=: HumanTaskservice @getTaskOperations() : Map @null@==interface=: HumanTaskservice %= HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl +%依赖¥HumanTaskServicelmpl %==interface=: HumanTaskservice %实现¥#< @@ -50,7 +50,7 @@ HumanTaskServiceOperations %实现¥< HumanTaskclientConfiguration %HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration +%依赖¥JBPMSHUmanTaskClientConfiguration %< HumanTaskclientConfiguration %实现¥#= @@ -59,11 +59,11 @@ HumanTaskServiceOperations @null@= HumanTaskServiceOperations %HumanTaskServicelmpl -%聚合¥= +%依赖¥= HumanTaskServiceOperations %= TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations +%依赖¥JBPMSHUmanTaskServiceOperations %= HumanTaskServiceOperations %实现¥< @@ -74,14 +74,14 @@ HumanTaskServiceOperations HumanTaskservice %= HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration +%依赖¥#HumanTaskServiceConfiguration @clientConfs : Map @addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) getHumarTaskClientConfigurations() : Map @< HumanTaskclientConfiguration %HumanTaskServiceConfiguration -%聚合¥#= +%依赖¥#= TaskOperations @getMyTaskabstracts(taskType : String) : TTaskAbstract geyMyTasks(taskType : String) : TTask @@ -97,1093 +97,4 @@ complete(id : String,data : Object) HumanTaskServiceOperations %= TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥#JBPMSMinaHumanTaskClientConfiguration -@@getServiceOperationsimplementation() : HumanTaskServiceOperations -@JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#JBPMSHUmanTaskServiceOperations -@taskClient : TaskClient -configuration : JEPMSHumanTaskClientConfiguration -@JBPMSHumanTaskServiceOperations(configuration : JBPMSHumanTaskClientConfiguration) -@JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskServiceOperations -%实现¥#HumanTaskServicelmpl -@taskOperations : Map -@@HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥#JBPMSHUmanTaskClientConfiguration -@port : String -host : String -@JBPMSHumanTaskClientConfiguration(port : String,host : String) -@JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥JBPMSMinaHumanTaskClientConfiguration -%JBPMSHUmanTaskClientConfiguration -%聚合¥#==interface=: -HumanTaskservice -@getTaskOperations() : Map -@null@==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥HumanTaskServicelmpl -%==interface=: -HumanTaskservice -%实现¥#< -HumanTaskclientConfiguration -@getServiceOperationsimplementation() : HumanTaskServiceOperations -@null@< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥JBPMSHUmanTaskClientConfiguration -%< -HumanTaskclientConfiguration -%实现¥#= -HumanTaskServiceOperations -@getTaskOriginatorType(Taskid : String) : String -@null@= -HumanTaskServiceOperations -%HumanTaskServicelmpl -%聚合¥= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥JBPMSHUmanTaskServiceOperations -%= -HumanTaskServiceOperations -%实现¥< -HumanTaskclientConfiguration -%= -HumanTaskServiceOperations -%实现¥==interface=: -HumanTaskservice -%= -HumanTaskServiceOperations -%聚合¥#HumanTaskServiceConfiguration -@clientConfs : Map -@addHumanTaskClientConfiguration(name : String,client : HumanTaskclientConfiguration) -getHumarTaskClientConfigurations() : Map -@< -HumanTaskclientConfiguration -%HumanTaskServiceConfiguration -%聚合¥#= -TaskOperations -@getMyTaskabstracts(taskType : String) : TTaskAbstract -geyMyTasks(taskType : String) : TTask - -getTaskinfoid : String) : TTask - -claimfid : String) - -start(id : String) - -complete(id : String,data : Object) -@@= -HumanTaskServiceOperations -%= -TaskOperations -%聚合¥# \ No newline at end of file +%依赖¥# \ No newline at end of file -- Gitee From b08de598ab3a99b7a7bd622bff8f343e1328472c Mon Sep 17 00:00:00 2001 From: origin Date: Mon, 8 Mar 2021 11:48:30 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E5=AE=9E=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/umlrecog/UMLDiagramRecognizer.java | 2 +- src/main/resources/cd/fltt_jss7.txt | 97 ++++++++++++++++++ .../cd/marcellodesales_my-cs-research.txt | 87 ++++++++++++++++ src/main/resources/cd/temp result.jpg | Bin 0 -> 1041 bytes src/main/resources/cd/temp result.png | Bin 4354 -> 23159 bytes src/main/resources/sd/coinvent_coinvent.txt | 3 + src/main/resources/sd/temp result.png | Bin 90 -> 13472 bytes 7 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/cd/fltt_jss7.txt create mode 100644 src/main/resources/cd/marcellodesales_my-cs-research.txt create mode 100644 src/main/resources/cd/temp result.jpg create mode 100644 src/main/resources/sd/coinvent_coinvent.txt diff --git a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java index 533850a..b85d5ce 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java @@ -33,7 +33,7 @@ public class UMLDiagramRecognizer { * 测试一下识别特定的类图和顺序图 */ public static void main(String[] args) { - // UMLDiagramRecognizer.recogCD(cd_dir, "Salaboy/smart-tasks"); + UMLDiagramRecognizer.recogCD(cd_dir, "abrden/StarCraft"); UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent"); } } diff --git a/src/main/resources/cd/fltt_jss7.txt b/src/main/resources/cd/fltt_jss7.txt new file mode 100644 index 0000000..5412dcc --- /dev/null +++ b/src/main/resources/cd/fltt_jss7.txt @@ -0,0 +1,97 @@ +< +MapServiceF actory +@createProcessUinstructuredS SRequest{ussdDataCodingS cheme : byte,ussdString : USSDString) : ProcessUnstructuradSSRequest +createProcessUnstructuredssR equestResponselinvokelD : rt, ussdDataCodingScharma : byke,ussdString :USSDString) - ProcesslnstructuredsSResponse +createlnstructuredsSRequest(ussdDataCodingSchama | byte,ussdString USSDString) - UnstructuredSSRaquest +createlnstructuradSsRequestResponselinokelD - nt,ussdDataCodingScherne - byte,ussdstring : USSDString) : UnstructuredssResponse +cretelISSDStringlussdString - String] : USSDString + +cretelISSDStringlusadstring : USSDString charSe : Charset] : USSDString + +cretelISSDStringlussdstring: ytell : LSSDString + +createl)SSDStringlussdstring: bytell charSat Charset) : USSDString + +crataddrassStringladdature : it urPlan : NurnberingPlan, adress : String) : Addressstring + +createMAP UserabortChaicel) MAPUsarabortChoice +@null@< +MAPProvider +%< +MapServiceF actory +%依赖¥#< +MAPServicelistener +@onProcessUnstructuredSSindication{procUnstrind : ProcessUnstructuredsSindication) : void +onlnstructuradssindication(unstrind : UnstructuredsSindicatio) void +@null@#< +MAPDislogListener +@onMAF OpeninfolmapOpeninfo : MAFOpeninfa) : void +onMAPAccaptinfolmapAccptinfo: MAPACcaptinfo) void +onMAPCloselnfolmapCloselnfo : MAP Clossinfo) : void + +OnMAPRefuseinfol mapRefuselnfo : MAPRefuselnfo) : void +nMAPUserabortinfolmapUserAbortinfo MAPUserAbortinfol : void +nMAPProvidarAbortinfolmapP roviderabortinfo : MAPP roviderabortinfo) : void +@null@< +MAPProvider +%< +MAPDislogListener +%实现¥#< +MAPProvider +@createNewDialoglappCritx : MAP ApplicationContext,orighddress : Sccpaddress,origReference : AddressString, destAddress : Sccpaddress, destReference : AddressString) : MAPDialog +dMAP Dialoglistener{mapDialogl istenr : MAPDiaioglistener) void + +removeAP DidlogListenrmapDislogLtener : MAP DidlogListenr) : void + +ddMAPServical istenarmapServicelstener MAPServiceL istener) : void + +removeMAP S arviceL tener{mapSariceL istenar : MAPSaruiceL tener] : void + +gethapServiceFactoryl) : MapSaruiceF actory + +GethAPDislogldialogld: Long] : MAPDislog +@null@< +MAPProvider +%< +MapServiceF actory +%依赖¥< +MAPProvider +%< +MAPDislogListener +%实现¥< +MAPDilog +%< +MAPProvider +%依赖¥< +MAPStack +%< +MAPProvider +%依赖¥#< +MAPDilog +@getDialogldl) : Long + +send() - void + +closelprearrangadEnd - boolsan) : void + +Short{rmaplserabortChoice : MAP UssrAbertChoice veid + +dProcessinstructuredSSFaquestlussdDataCodingScharne : byte,ussdString : USSDString msisdn: AddressString) veid +dProcassinstructurads SR esponsalinvakeld lang.lastResul : boslean ussdDstaCodingScheme : byte.ussdstring : UISSDString) : void +acdUnstructuredsSRequest{ussdDataCodingscheme - byte.ussdString : USSDString) : void + +Unstructurads s Rasponselinvokeld : longlastRasul : boolean,ussdD ataCodingScherns : byt ussdString : USSDStringl : void +@null@< +MAPDilog +%< +MAPProvider +%依赖¥#< +MAPStack +@stopl) : void +start() - void +GetMAPProvider() : MAPProvider +@null@< +MAPStack +%< +MAPProvider +%依赖¥# \ No newline at end of file diff --git a/src/main/resources/cd/marcellodesales_my-cs-research.txt b/src/main/resources/cd/marcellodesales_my-cs-research.txt new file mode 100644 index 0000000..0b1ac1f --- /dev/null +++ b/src/main/resources/cd/marcellodesales_my-cs-research.txt @@ -0,0 +1,87 @@ +GreatsrMancpsrator +@@@#LesscrEqualscpentor +@@@LesscrEqualscpentor +%Reazanaiopaacer +%实现¥#NotEquaICpsrator +@@null@NotEquaICpsrator +%Reazanaiopaacer +%实现¥#GreatirorBqualsCperator +@@null@Reazanaiopaacer +%GreatirorBqualsCperator +%实现¥#LessTancpsrator +@@@#Equacpsator +@@@Equacpsator +%Reazanaiopaacer +%依赖¥#@@null@#@@@#@@@#@@null@#@@null@#ToknEception +@@@#@@null@%%实现¥#“rCpsrator +@@@“rCpsrator +%Adcveopaer +%实现¥#Tidecperator +@@null@Tidecperator +%Idepieacveopaer +%依赖¥#andcperator +@@null@Idepieacveopaer +%andcperator +%实现¥#Timascpsrator +@@null@Idepieacveopaer +%Timascpsrator +%实现¥#Reazanaiopaacer +@@null@Reazanaiopaacer +%GreatirorBqualsCperator +%实现¥LesscrEqualscpentor +%Reazanaiopaacer +%实现¥NotEquaICpsrator +%Reazanaiopaacer +%实现¥Equacpsator +%Reazanaiopaacer +%依赖¥#@@null@#Minuscpsrator +@@null@#ntwrprotr +@@null@#@@null@#T~ +@null@null@Adcveopaer +%T~ +%实现¥#Adcveopaer +@@null@Adcveopaer +%T~ +%实现¥Adcveopaer +%Exprasson +%实现¥“rCpsrator +%Adcveopaer +%实现¥Puscpentor +%Adcveopaer +%实现¥#@@null@%Exprasson +%实现¥%%实现¥#Idepieacveopaer +@@null@Idepieacveopaer +%andcperator +%实现¥Idepieacveopaer +%Timascpsrator +%实现¥Tidecperator +%Idepieacveopaer +%依赖¥#@@null@%Exprasson +%实现¥#Puscpentor +@@null@Puscpentor +%Adcveopaer +%实现¥#@@null@%Exprasson +%实现¥#Concluslonsequencs. +@@null@Concluslonsequencs. +%Statamentssquence +%实现¥#@@null@#Asignmentstitament +@@null@#RoatTyps. +@@@#BokanType. +@@null@%BokanType. +%依赖¥#Statamentssquence +@@null@Concluslonsequencs. +%Statamentssquence +%实现¥#Exprasson +@@null@%Exprasson +%实现¥%Exprasson +%实现¥%Exprasson +%实现¥Adcveopaer +%Exprasson +%实现¥#@@null@%%实现¥#@@null@%%实现¥#@@null@%%实现¥#e +@@null@ntagerTyps. +%e +%实现¥#ntagerTyps. +@@null@ntagerTyps. +%e +%实现¥#@@null@%BokanType. +%依赖¥%%实现¥# \ No newline at end of file diff --git a/src/main/resources/cd/temp result.jpg b/src/main/resources/cd/temp result.jpg new file mode 100644 index 0000000000000000000000000000000000000000..918a3a1a49924bf376c78eeab1c72aea6ee9fa02 GIT binary patch literal 1041 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 -- Gitee From b63a4bd919581ea603d1393374fcf516e71e0a89 Mon Sep 17 00:00:00 2001 From: origin Date: Tue, 9 Mar 2021 11:25:07 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=B1=BB=E8=AF=86?= =?UTF-8?q?=E5=88=AB=EF=BC=8C=E5=81=9A=E5=AE=9E=E9=AA=8C=E3=80=82=E5=9B=BE?= =?UTF-8?q?=E7=9A=84=E9=80=89=E5=8F=96=E4=BC=9A=E5=BD=B1=E5=93=8D=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=EF=BC=8C=E7=89=B9=E5=88=AB=E6=98=AF=E5=9B=BE=E7=9A=84?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E9=97=AE=E9=A2=98=E5=BD=B1=E5=93=8D=E6=9E=81?= =?UTF-8?q?=E5=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/umlrecog/UMLDiagramRecognizer.java | 26 +- .../umlrecog/cddetector/ClassDetector.java | 34 ++- .../cddetector/ClassRelationDetector.java | 56 +++- .../cd/C204-242-DJSMT_Assignment-1.txt | 83 +++++ src/main/resources/cd/abrden_StarCraft.txt | 25 ++ .../resources/cd/badqiu_rapid-framework.txt | 28 ++ src/main/resources/cd/cscfa_bartleby.txt | 41 +++ ...rigoazevedomartins_TrabalhoFinalLTPIII.txt | 286 ++++++++++++++++++ src/main/resources/cd/temp result.jpeg | Bin 0 -> 169332 bytes src/main/resources/cd/temp result.jpg | Bin 1041 -> 8599 bytes src/main/resources/cd/temp result.png | Bin 23159 -> 5214 bytes src/main/resources/sd/coinvent_coinvent.txt | 1 + 12 files changed, 562 insertions(+), 18 deletions(-) create mode 100644 src/main/resources/cd/C204-242-DJSMT_Assignment-1.txt create mode 100644 src/main/resources/cd/abrden_StarCraft.txt create mode 100644 src/main/resources/cd/badqiu_rapid-framework.txt create mode 100644 src/main/resources/cd/cscfa_bartleby.txt create mode 100644 src/main/resources/cd/rodrigoazevedomartins_TrabalhoFinalLTPIII.txt create mode 100644 src/main/resources/cd/temp result.jpeg diff --git a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java index b85d5ce..7f800e4 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java @@ -17,23 +17,37 @@ public class UMLDiagramRecognizer { /** * 识别目录下指定的类图并将结果存为文件 + * + * @param check */ - public static void recogCD(String cd_dir, String repo_name) { - ClassDiagramRecognizer.recog(cd_dir, repo_name); + public static void recogCD(String cd_dir, String repo_name, boolean todo) { + if (todo) { + ClassDiagramRecognizer.recog(cd_dir, repo_name); + } } /** * 识别目录下指定的顺序图并将结果存为文件 + * + * @param todo */ - public static void recogSD(String sd_dir, String repo_name) { - SequenceDiagramRecognizer.recog(sd_dir, repo_name); + public static void recogSD(String sd_dir, String repo_name, boolean todo) { + if (todo) { + SequenceDiagramRecognizer.recog(sd_dir, repo_name); + } } /* * 测试一下识别特定的类图和顺序图 */ public static void main(String[] args) { - UMLDiagramRecognizer.recogCD(cd_dir, "abrden/StarCraft"); - UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent"); + // 类图实验 + UMLDiagramRecognizer.recogCD(cd_dir, "rodrigoazevedomartins/TrabalhoFinalLTPIII", false); + UMLDiagramRecognizer.recogCD(cd_dir, "ultragdb/org.eclipse.cdt", false); + UMLDiagramRecognizer.recogCD(cd_dir, "badqiu/rapid-framework", false); + UMLDiagramRecognizer.recogCD(cd_dir, "C204-242-DJSMT/Assignment-1", false); + UMLDiagramRecognizer.recogCD(cd_dir, "cscfa/bartleby", true); + // 顺序图实验 + UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent", false); } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java index c64de98..7756c41 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/cddetector/ClassDetector.java @@ -41,7 +41,7 @@ public class ClassDetector { // 高斯锐化,提升类图图形清晰度 // Imgproc.Laplacian(mat, mat, 2); // 二值化,用于后续处理 - Imgproc.threshold(mat, mat, 160, 255, Imgproc.THRESH_BINARY); + Imgproc.threshold(mat, mat, 150, 255, Imgproc.THRESH_BINARY); /* * 识别类 */ @@ -98,6 +98,38 @@ public class ClassDetector { } // 对所有矩形边框进行涂白,防止其干扰关系符号和关系线识别 Imgproc.drawContours(cls_diagram, rect_contours, -1, new Scalar(255, 255, 255), 5); + // 由于灰度问题,此时可能会有遗留矩形,所以重新检测一遍 + contours.clear(); + rect_contours.clear(); + Imgproc.findContours(cls_diagram, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); + for (MatOfPoint contour : contours) { + // 如果轮廓面积太小或太大,则直接忽略 + double contour_area = Imgproc.contourArea(contour); + if (contour_area < min_cls_area || contour_area > max_cls_area) { + continue; + } + // 如果轮廓面积合适,则检测是否为矩形。采用多边形逼近法,将轮廓转化为curve向多边形做逼近,并将逼近结果存在approx_curve中 + MatOfPoint2f curve = new MatOfPoint2f(contour.toArray()); + MatOfPoint2f approx_curve = new MatOfPoint2f(); + Imgproc.approxPolyDP(curve, approx_curve, 0.05 * Imgproc.arcLength(curve, false), true); + Imgproc.approxPolyDP(approx_curve, approx_curve, 0.01 * Imgproc.arcLength(approx_curve, true), true); + // 针对逼近结果approx_curve,若其共有4个顶点,则可认为是矩形。将检测结果绘制在原图中,便于后续处理 + if (approx_curve.toArray().length == 4) { + // 将矩形存在all_rect_areas中用于类的整合和文字识别。存完后将其从原图中抹掉,防止其干扰关系符号和关系线识别 + all_rect_areas.add(new Rectangle(cls_diagram.clone(), contour, approx_curve)); + rect_contours.add(contour); + // 存完后将矩形从图中抹掉(涂白)。后面还需对所有边框进行涂白 + Imgproc.fillConvexPoly(cls_diagram, contour, new Scalar(255, 255, 255)); + // 可以不涂白,看一下识别结果。最后注释掉 + // Imgproc.fillConvexPoly(cls_diagram, contour, new Scalar(55, 55, 55)); + // Imgcodecs.imwrite(temp_res_path, cls_diagram); + // System.out.println(approx_curve.dump()); + } + } + // 对所有矩形边框进行涂白,防止其干扰关系符号和关系线识别 + Imgproc.drawContours(cls_diagram, rect_contours, -1, new Scalar(255, 255, 255), 5); + // 看一眼,最后注释掉 + // Imgcodecs.imwrite(temp_res_path, cls_diagram); // 此时的cls_diagram中矩形已涂白 return Pair.createPair(cls_diagram, all_rect_areas); } 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 0e440a4..9e8787b 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 @@ -110,7 +110,8 @@ 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; } } @@ -132,7 +133,7 @@ public class ClassRelationDetector { /* * 对所有实线,将可能的“折线”识别并合并。合并为折线的直线,其belonged_polygonal_line会标识其所属折线 */ - Set poly_lines = mergePolygonalLines(line_segments); + Set poly_lines = mergePolygonalLines(line_segments, cls_diagram); /* * 利用UML_classes的位置,进一步筛选关系线,存在result中 * @@ -163,7 +164,8 @@ public class ClassRelationDetector { // 实线识别结果 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); @@ -177,7 +179,8 @@ public class ClassRelationDetector { // 虚线识别结果 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); @@ -227,9 +230,13 @@ public class ClassRelationDetector { /** * 将可能的“折线”识别并合并 + * + * @param cls_diagram */ - private Set mergePolygonalLines(List lines) { + private Set mergePolygonalLines(List lines, Mat cls_diagram) { Set result = new HashSet<>(); + Set init_result = new HashSet<>(); + Set temp_result = new HashSet<>(); // 从第一条线开始,检查当前线与每条后面的线是否能合并 for (int i = 0; i < lines.size(); i++) { Line line = lines.get(i); @@ -239,7 +246,7 @@ public class ClassRelationDetector { if (line.belonged_poly == null) { // 将当前直线作为一条新折线的一段 line.belonged_poly = new PolygonalLine(line); - result.add(line.belonged_poly); + init_result.add(line.belonged_poly); } // 检查当前线与每条后面的线是否能合并 for (int j = i + 1; j < lines.size(); j++) { @@ -298,8 +305,25 @@ public class ClassRelationDetector { } } } + // 清理过长的线(比如边框线) + for (PolygonalLine pl : init_result) { + boolean should_be_del = false; + for (Line l : pl.line_list) { + if (l.length >= 0.6 * cls_diagram.width() || l.length >= 0.6 * cls_diagram.height()) { + should_be_del = true; + break; + } + } + if (!should_be_del) { + temp_result.add(pl); + } + } // 设置每条折线的两端。同时记录两端的点所在的线段 - for (PolygonalLine pl : result) { + for (PolygonalLine pl : temp_result) { + // 看一下每条折线,最后注释掉 + /* + * for (Line l : pl.line_list) { Imgproc.line(cls_diagram, l.pt1, l.pt2, new Scalar(55, 55, 55), 5); } Imgcodecs.imwrite(temp_res_path, cls_diagram); + */ for (Line l : pl.line_list) { Point pt = l.notInPolyPt(); if (pt != null) { @@ -323,6 +347,12 @@ public class ClassRelationDetector { } } } + // 此时仍有折线两端都是null,剔除掉 + for (PolygonalLine pl : temp_result) { + if (pl.pt1 != null || pl.pt2 != null) { + result.add(pl); + } + } return result; } @@ -393,7 +423,8 @@ public class ClassRelationDetector { dash_rela.source.out_relas.add(dash_rela); dash_rela.target.in_relas.add(dash_rela); break; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -421,7 +452,8 @@ public class ClassRelationDetector { // 记录该包络矩形是否属于当前实线关系线solid_rela。如果是的话,再去检测矩形内图形 boolean belong_to_this_solid_rela = false; // 方法同对dash_rela的检测。对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。 - 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)) + 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; @@ -432,7 +464,8 @@ public class ClassRelationDetector { solid_rela.target = temp; } solid_rela.source_pt_index = 2; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -474,7 +507,8 @@ public class ClassRelationDetector { 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))) { + 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 = "继承"; } /* diff --git a/src/main/resources/cd/C204-242-DJSMT_Assignment-1.txt b/src/main/resources/cd/C204-242-DJSMT_Assignment-1.txt new file mode 100644 index 0000000..7340daf --- /dev/null +++ b/src/main/resources/cd/C204-242-DJSMT_Assignment-1.txt @@ -0,0 +1,83 @@ +<> +ScanEvents +@+takeFromVehicle ++addToVehicle +@@Scan +%<> +ScanEvents +%依赖¥#<> +Employee Roles +@+sorter +@R +@Employeee +%<> +Employee Roles +%依赖¥#Employeee +@+role +@@Employeee +%<> +Employee Roles +%依赖¥SorterSession +%Employeee +%实现¥Scan +%Employeee +%依赖¥DataAdapter +%Employeee +%依赖¥#PackageBin +@+destinationCities ++scantistory ++scan +@+addPackage() ++ostring() ++lastScan() +@PackageBin +%Scan +%实现¥#Scan +@+event +@@Scan +%Employeee +%依赖¥Scan +%<> +ScanEvents +%依赖¥PackageBin +%Scan +%实现¥Package +%Scan +%实现¥#DataAdapter +@— =2 +@+getAllPackage() ++getallBin() + ++addBin() ++getundeliveredPackages() +@DataAdapter +%Employeee +%依赖¥DataAdapter +%SorterSession +%实现¥LoginForm +%DataAdapter +%实现¥Package +%DataAdapter +%实现¥#SorterSession +@w— +@@SorterSession +%Employeee +%实现¥DataAdapter +%SorterSession +%实现¥LoginForm +%SorterSession +%实现¥#Package +@“+destinationCity +“+scanHistory +@+tostring() +@Package +%Scan +%实现¥Package +%DataAdapter +%实现¥#LoginForm +@——— =~ +@@LoginForm +%SorterSession +%实现¥LoginForm +%DataAdapter +%实现¥#@null@null@# \ No newline at end of file diff --git a/src/main/resources/cd/abrden_StarCraft.txt b/src/main/resources/cd/abrden_StarCraft.txt new file mode 100644 index 0000000..2fefe0f --- /dev/null +++ b/src/main/resources/cd/abrden_StarCraft.txt @@ -0,0 +1,25 @@ +TerranBuilder +@@+TerranBuilder() ++getRace(): String +@#ProtossBuilder +@@+ProtossBuilder() ++getRace(): String +@#StructureTemplate +@@+create(position : Point) : Structure +@#Builder +@# dependsOn : Map = new HashMap() +@+ create(name : String, position : Point, resources : Resources, bl : terable, map : Map) : Construction +- getTemplateWithName(name : String) : StructureTemplate + +- structureRequiredExists(name : String, built - terable) : boolean + +#addTemplate(template : StructureTemplate) : void + +#addDependency(key : String, value : String) : void + +# dependensOn(key : String) : String + ++ getTemplateNames() : Stringl] + ++getRace() : String +@# \ No newline at end of file diff --git a/src/main/resources/cd/badqiu_rapid-framework.txt b/src/main/resources/cd/badqiu_rapid-framework.txt new file mode 100644 index 0000000..f5acf04 --- /dev/null +++ b/src/main/resources/cd/badqiu_rapid-framework.txt @@ -0,0 +1,28 @@ +SqlFactory +@+ parsesal() : Sal +@null@GeneratorFacade +%SqlFactory +%实现¥#JavaClass +@@null@GeneratorFacade +%JavaClass +%实现¥#TableFactory +@+ getTable() : Table +@null@GeneratorFacade +%TableFactory +%实现¥#GeneratorFacade +@+ deleteByClass() : void ++ deleteBySql) : void + ++ deleteByTable() : void ++ generateByClass() : void ++ generateBySqll) : void ++ generateByTable() : void +@@GeneratorFacade +%JavaClass +%实现¥GeneratorFacade +%TableFactory +%实现¥GeneratorFacade +%SqlFactory +%实现¥#GeneratorProperties +@@null@#@null@null@#@null@null@#@null@null@#@null@null@#GeneratorControl +@null@null@# \ No newline at end of file diff --git a/src/main/resources/cd/cscfa_bartleby.txt b/src/main/resources/cd/cscfa_bartleby.txt new file mode 100644 index 0000000..3e4536f --- /dev/null +++ b/src/main/resources/cd/cscfa_bartleby.txt @@ -0,0 +1,41 @@ +RollingFileAppender +@#setRolingPoiicy RollngPolicy): void ++setTriggeringPolcy (TriggeringPolicy ) +@null@#FileAppender +@+setFile(String): void. ++setPrudentlooolean): void ++setAppend(boolean): void +@@FileAppender +%‘OutputStreamAppender +%实现¥#‘ConsoleAppender +@+setTarget(String): void +@@‘ConsoleAppender +%‘OutputStreamAppender +%实现¥#Filter +@+decide(E event): FilterReply +@null@Filter +%‘OutputStreamAppender +%实现¥#<> +Encoder +@#init{OutputStream): void ++doEncode(E event): void ++cose(): void +@null@#‘OutputStreamAppender +@+setOutputStream(OutputStream): void +4setEncoder Encoder ): void +@null@FileAppender +%‘OutputStreamAppender +%实现¥‘ConsoleAppender +%‘OutputStreamAppender +%实现¥Filter +%‘OutputStreamAppender +%实现¥#UnsynchronizedAppenderBase +@+doAppend(E event): void + +#append(E event): void ++addFiter Fiter <> fiter): void ++getFierChainDeciion(E event): FiterReply +@@#<> +Appender +@“+doAppend(E event): void +@@# \ No newline at end of file diff --git a/src/main/resources/cd/rodrigoazevedomartins_TrabalhoFinalLTPIII.txt b/src/main/resources/cd/rodrigoazevedomartins_TrabalhoFinalLTPIII.txt new file mode 100644 index 0000000..2bedc5a --- /dev/null +++ b/src/main/resources/cd/rodrigoazevedomartins_TrabalhoFinalLTPIII.txt @@ -0,0 +1,286 @@ +ProfessorDisciplina +@-professor: Professor +—diacipiings Hasioinn +@setProfessor (professoriprofesser) : void ++getProfessor () : professor + ++setbisciplina (disciplina:disciplina) : void ++getDisciplina(): disciplina +@#Usuario +@-codusuario: int +-login: varchar +-senna: varchar +S Poenad g INCASDREAS +@+setCodfuncionario (codfuncionario:int) : void ++getCodfuncionario() : int ++setLogin(loginivarchar) : void + ++getlogin() : varchar + ++setSenna(senharvarchar) : void + ++gecSenha() : varchar + ++setFuncionario (funcicnario: funcionario) : void ++getFuncionario() : funcionario +@#Professor +@-codprofessor: int +—titulacao: varchar + +-nivel: int + +-pessoa: Pessoa + +S aetnlingd: TAiNCESEIHEIS +@+setCodprofessor (codprofessor:int) : void ++getCodprofessor() : int + ++setTitulacao (vitulacao:varchar): void ++getTitulacac(): varchar + ++setNivel (nivel:int) : void + ++gecNivel(): int + ++setPessoa (pessoa:pessoa) : void + ++gecPessca(): pessca + ++setbisciplinas (disciplinas:list) : void ++getDisciplinas(): lisc +@#Funcionario +@-codfuncionario: int +-siape: varchar +-cargo: varchar +s Diwak +@+setCodfuncionario (codfuncionario:int) : void ++getCodfuncionariol) : int + ++setSiape (siapervarchar) : void + ++gecSiape() : varchar ++setCargo(cargovarchar) : void + ++gecCargo() : varchar + ++setPessoa (pessoa:pessoa) : void ++getPessoa(): pessoa +@#Secao +@-codsecao: int +inicio: date +—final: date +RaREis DaaReis +@+setCodsecac (codsecaniint): void ++gecCodsecan() : int + ++setInicio (inicio:date) : void ++getInicio(): date + ++setFinal (finalidate) : void ++getFinal(): date + ++setUsuario (usuariorusuario) : void ++getUsuario () : usuario +@#Reserva +@-codreserva: int +-datainicio: date +—datafinal: date +-situacao: Situacao +—secao: Secao + +-pessoa: Pessoa +~recursoa: 1igt): void ++getRecursos() : list ++setPessoa (pessoa:pessoa) : void ++getPessoa(): pessoa +@#Disciplina +@-coddisciplina: int +-ementa: varchar +L e Bk +@+setCoddisciplina (coddisciplina:int): void ++getCoddisciplina(): int + ++setiome (nome:varchar) : void + ++getiome () : varchar + ++setEnenta (ementa:varchar): void ++getEnenta(): varchar ++setCurso(cursoscurso) : void + +FostCursol): Pares +@#Situacao +@-codsituacac: int +AEETORY: GREChAR +@+setCodsituacac (codsituacao:int) : void ++gecCodsituacac () : int + ++setbescricac (descricac:varchar): void ++getDescrican () : varchar +@#Tiporecurso +@-codtiporecurso: int +SRR h +@setCodtiporecurso (codtiporecursorint) ¢ void ++getCoduiporecurso () : int + ++setbescricac (descricao:varchar): void ++getDescricao () : varchar +@#Recurso +@-codrecurso: int +-nome: varchar +slemecapn: e +@+setCodrecurso (codrecursorint) : void ++getCodrecurso(): int + ++setiome (nome:varchar) : void + ++getiome () : varchar + ++setTiporecurso (ciporecurso: tiporecurso) : void ++getTiporecurso() : tiporecurso +@#Telefone +@-codtelefone: int +-pessoa: Pessoa +-area: int +vt e +@+setcodtelefone (codvelefone:int) ; void ++getcodtelefone () int + ++setarea (area:int) : void + ++getarea(): int + ++setnumero (numero:int) : void +sgetnmero(): inc + ++setpessoa (pessoa:pessoa) : void ++getpessoa(): pessoa +@#Curso +@-codcurso: int +-nome: varchar +—uracac: int +_disciplinas: list +@+setCodcurso (codeurso:int) : void + ++gecCodenrsa() : int + ++setiome (nome:varchar) : void + ++getome () : varchar + ++setburacao (duracao: int) : void + ++getDuracan(): int + ++setbisciplinas (disciplinas:list) : void ++getDisciplinas(): lisc +@#Endereco +@-codendereco: int +-pessoa: Pessoa +—rua: string +——— +-complemento: string +bairro: string +—cidade: string +-cep: int + +—estado: string +A e +@+setcodendereco (codendereco:int) ; void ++getcodendereca () : int + ++setrua (ruastring): void + ++getrua(): string + ++setnumero (numero:int) : void +tgetnmero(): inc + ++setcomplemento (complemento: string) : void ++getcamplementa () : string + ++setbairro (bairro:string) : void ++getbairro(): string + ++setcidade (cidade:string) : void ++getcidade (): string + ++setcep (cepiint): void + ++getcep(): int + ++setestads (estado:string) : void ++getestado(): string + ++setpais (pais:string) : void ++getpais () : string + ++setpessoa (pessoa:pessoa) : void ++getpessoa(): pessca +@#Pessoa +@~codpessoa: int + +-nome: string + +-rg: string + +~cpf:int + +~datanasc: date +-enderecos list +-emails: list +Aaloforves: e ): void ++getenderecos(): list ++setemails(emailsiist): void ++getemails): list ++setelefones(telefonesilist): void ++gettelefones(): list +@#ReservaRecurso +@-reserva: Reserva +Crerurass. Recarac +@+setReserva (reservaireserva) : void ++getResexrva(): reserva ++setRecurso (recurso: recurso) : void ++getRecurso () : recurso +@#Email +@~codemail: int +-endereco: string +i s +@+setcodemail(codemail:int): void ++getcodemail): int ++setendereco(endereco:string): void ++getendereco): string ++setpessoa(pessoa:pessoa): void +oo b pesce +@# \ No newline at end of file diff --git a/src/main/resources/cd/temp result.jpeg b/src/main/resources/cd/temp result.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9a3ff1c6df94ff927d00f12edc792bd29c24b0a8 GIT binary patch literal 169332 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 z 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�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 PqZTYIDDXe70NnpiH!+O! literal 1041 zcmex=iF;N$`UAd82aiwDH{e}I9T18B}BMn*w~|3?_)frhh!%>>#20gOz{EUawo zK)u{R1zQDxb}};qZDIvl15{lLlxJWOWEE00bYv3_Ok`Io6ftU?xR68HY2!iBpoX!XqN1l2cOC(lau%ic3n% z$}1|Xnp;}i+B-VCCQY6)b=ve9GiNPYykzOJeA&aSFc^aar4&0M~|O8efIpt%U2&ieg5+G+xH(ofBnD3zyS(2dxpQI9d8fF`yc+( z7<|ZIX8yS~ZvHY?r>GY^TjS(sHE-V5G@+`LFJD(aQkOXS@^zR1&zHAhNg?WTQU4k4 zE3I)^W#3ZzWwjvVyymsu8|`=5YniEkcYo@3Oyk- z-}RsB?fiT3XCOkU*NWZkr>uU3OuTzXNsIjf16zpHCzn_D_x>|T&C|P@WY_#UEciXw zMt=W8YYt!k#~gh0uhyy3KU!yE>!mh|e_btD`X?(&V^J3nX@;-(bxGgx%X$sJ#ed&_ zT>0p2nDPs|t*Le&RttOq>aeYUU}_V8Y0dKZLu-y+|F~MPK5CAs<%# zDqHy|pm1VXQsB#5%l!m4ykay>Gca%L|Cy{@r})9%YdZ7S{|q;0)I0j!*f%97-pfpX oskHc|-tL!fN53pi`W3jbRs$%ps(a$`s@9X?TKo(jjdGT92bOeWu`1UF>2U26%M?3v>F z>OHS@X57D)@vg3}rF@F{#kiCFA@Sj+=I^yfvh-(>b5Y zH6p#+sNN#aMg}deY*WBw0zZhnp-PvcMXuYE?e1>HB)J+j!2za$K)@o;^pbYbQKM3i zW+PQfGywZ^1_oqfvS`2P^Vk_#cCy$aM@=p)$CQ&3Ef`CTn=F)BvX`SXL$d6F0JskT zytbTVdka^D@Qj$G3yQi)G8?tXfw62X0FYn^wGnN7ItLVR$QghTfC(7Fw{V$yF{dSb z`G7?ZLQ!O8sk6XWqtP@UkIi)hA6uai7f?l=E~85ALq?T_Sy_|D47oejXW@23h<+$b zNh}XVBEz~M!x**zVQ-@;H`mCmfDjD=M9@6QtH}&#aaIsg36l7QAb2fB(@g|avaAY_ z-UbynsO$uLvk+E>2LY0Yq2wDOT%Ku7w8&pf5UG4d_;l|>QJ1Am%d4oKvR!u1fv1xFFC~lKH4*FqEVT=DjgR0z~wf6UwK_+J|8ryaWV)OlIc_2)x@`GsxQcB;eLgjS97jDX{@Ff|eWv@hv^q?4N!_M>V~ zkTDCObGjgx*|XQq`r%HJtw8Ll)4@hNs}&-c%BPZs2Vu|@diy}rro`eE0?>B~d#WSE zva{R7kr3xl2D##et`kW7O%cMsPsa|6p;ywt zsE(qih3sBZQ^Qtv9hH;`K^3_Zz20^vq4Lh(SgRj-v2|ouYh?iP_g7QKDW5UygWEJa z<3K1QBQ;0;7U$uRvn%8jq)y#YMEY=c3THEgVwf#PY!@-`(Kf?uk_P=qrUcDzlgD;z z;y)F}GXxp7tEkzp(y-sNIJIfmxr#^yCSecdQ?ujJXj=o-K9Sa}*Nx~USLE~V#5r&B z!F-I|>x#&QEfUr(glbO<(zb`1O$*X*2+k4Akb_w%6kL;>^Dan$raCi2mHA~%{-n8baSe_!XL&8cGs7b5tg*M689D20s z%5{lZd;NNOY?G9P(c&1d41SrGhWCR!LJbv466E%bs;JAqxxp79!)cOEpe|KprAf-2 z2Sq6DHOZ@XP!aK@^;>5~gZ(WFEGug%za@2mJJOwaUt%($0S}zn$psXr7b7Rr2QWq{ zauz&O#PW=T877ujGOZjqFem2)BV1C|;G}n(33V zlZD{2QMF3J_Y8l z*#|DeOL}B;{ujwx6x$;O6Ux#@55u)EhJ`piI7X_W+!IQSucjWIrAHzy_3`$vuwOEt zi}hJt2fv#g|0=sDepRp>*%sk=f8Q8*oANPuYvKR;asK?wXMWPKzpI9v`Vqc3tgqQu K{b^P6iC+PE<+?He literal 23159 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 Date: Tue, 9 Mar 2021 21:58:36 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E4=BB=8EMessageDetector=E7=9A=84143?= =?UTF-8?q?=E8=A1=8C=E5=BC=80=E5=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uct/umlrecog/UMLDiagramRecognizer.java | 4 +- .../umlrecog/sddetector/MessageDetector.java | 89 +++++++++--------- .../hy/java/uct/umlrecog/util/Message.java | 4 +- src/main/resources/cd/cscfa_bartleby.txt | 40 ++++++++ src/main/resources/sd/temp result.png | Bin 13472 -> 21925 bytes 5 files changed, 88 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java index 7f800e4..c2b4740 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java +++ b/src/main/java/com/hy/java/uct/umlrecog/UMLDiagramRecognizer.java @@ -46,8 +46,8 @@ public class UMLDiagramRecognizer { UMLDiagramRecognizer.recogCD(cd_dir, "ultragdb/org.eclipse.cdt", false); UMLDiagramRecognizer.recogCD(cd_dir, "badqiu/rapid-framework", false); UMLDiagramRecognizer.recogCD(cd_dir, "C204-242-DJSMT/Assignment-1", false); - UMLDiagramRecognizer.recogCD(cd_dir, "cscfa/bartleby", true); + UMLDiagramRecognizer.recogCD(cd_dir, "cscfa/bartleby", false); // 顺序图实验 - UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent", false); + UMLDiagramRecognizer.recogSD(sd_dir, "coinvent/coinvent", true); } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 7e9d0df..4f7f10c 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -66,9 +66,9 @@ public class MessageDetector { Mat lines = new Mat(); if (detect_solid) { // 实线检测时,“最小直线长度”与图像像素有关;“最大像素间隔”越小越接近实线 - Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 180, 8, 29, 2); + Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 2, 8, 29, 1); } else { - Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 180, 8, 29, 10); + Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 2, 8, 29, 8); } // 保存所有刚检测出来的“原始直线” for (int i = 0; i < lines.rows(); i++) { @@ -110,8 +110,7 @@ public class MessageDetector { 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; } } @@ -131,44 +130,46 @@ public class MessageDetector { } } /* - * 从这里开始。现在所有线已识别出来(需看一下效果) + * 现在所有线已识别出来 * - * 之后检测线与对象的位置关系,设置好source、target即可 - * - * - * 可能不需要PolygonalLine这么麻烦的东西 - * - * !!!!!!!!!!!!!!!!!!!!!! - * - * !!!!!!!!!!!!!!!!!!!!!! - * - * !!!!!!!!!!!!!!!!!!!!!! - */ - /* - * 对所有实线,将可能的“折线”识别并合并。合并为折线的直线,其belonged_polygonal_line会标识其所属折线 - */ - Set poly_lines = mergePolygonalLines(line_segments); - /* - * 利用UML_classes的位置,进一步筛选关系线,存在result中 - * - * 针对每条候选关系线,计算每个类方框的4根边框线,看哪个边框线与当前候选关系线相交(允许一定像素的误差),则认为这条线确实是关系线,且属于相交的类 + * 首先找出斜率为0的直线,然后在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target */ - for (PolygonalLine pl : poly_lines) { - Message rela = new Message(pl); - // 对pl.pt1和pl.pt2,需要将其延直线方向延长一点,检查延长后的端点。 - for (UMLObject uml_class : UML_objects) { - // 检查延长后的端点 - if (uml_class.whole.contains(ImgProcessor.reachPt(pl.pt1, pl.l1, 35, false))) { - // 暂时将与pt1相近的类记为source、与pt2相近的类为target,后面识别出符号来后再调 - rela.source = uml_class; + for (Line l : line_segments) { + // 看一下效果,最后注释掉 + // Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); + // Imgcodecs.imwrite(temp_res_path, sd_diagram); + if (Double.parseDouble(Line.getK(l)) <= 0.1) { + // 获取l的包络矩形 + Rect rect = null; + /* + * 怎么获取l的包络矩形? + * + * 怎么获取l的包络矩形? + * + * 怎么获取l的包络矩形? + */ + + Mat cutted_img = ImgProcessor.cutImage(sd_diagram, rect); + Mat edges_in_cutted = new Mat(); + Imgproc.Canny(cutted_img, edges_in_cutted, 50, 50 * 3, 3, true); + // 从边缘集中检测直线。膨胀(将线外面的空白区域膨胀)、腐蚀(让线侵蚀周围的空白区域),可以提高识别准确率 + Mat lines_in_cutted = new Mat(); + if (detect_solid) { + // 实线检测时,“最小直线长度”与图像像素有关;“最大像素间隔”越小越接近实线 + Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 1); + } else { + Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 8); } - if (uml_class.whole.contains(ImgProcessor.reachPt(pl.pt2, pl.l2, 35, false))) { - // 暂时将与pt1相近的类记为source、与pt2相近的类为target,后面识别出符号来后再调 - rela.target = uml_class; + List line_segments_in_cutted = new ArrayList<>(); + // 保存所有刚检测出来的“原始直线” + for (int i = 0; i < lines_in_cutted.rows(); i++) { + line_segments_in_cutted.add(new Line(new Point(lines_in_cutted.get(i, 0)[0], lines_in_cutted.get(i, 0)[1]), new Point(lines_in_cutted.get(i, 0)[2], lines_in_cutted.get(i, 0)[3]))); + } + // 然后看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target + for (Line l_in_cutted : line_segments_in_cutted) { + result.add(null); + break; } - } - if (rela.source != null && rela.target != null) { - result.add(rela); } } /* @@ -410,8 +411,7 @@ public class MessageDetector { dash_rela.source.out_msgs.add(dash_rela); dash_rela.target.in_msgs.add(dash_rela); break; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -439,8 +439,7 @@ public class MessageDetector { // 记录该包络矩形是否属于当前实线关系线solid_rela。如果是的话,再去检测矩形内图形 boolean belong_to_this_solid_rela = false; // 方法同对dash_rela的检测。对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。 - 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)) + 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; @@ -451,8 +450,7 @@ public class MessageDetector { solid_rela.target = temp; } solid_rela.source_pt_index = 2; - } 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)) + } 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类对应了pt2,则需对换source和target @@ -494,8 +492,7 @@ public class MessageDetector { 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))) { + 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 = "继承"; } /* diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java index 694dcfd..b40a325 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java @@ -4,10 +4,12 @@ public class Message { public UMLObject source; public UMLObject target; - public PolygonalLine poly_line; + public Line line; public int source_pt_index; public String msg; + public PolygonalLine poly_line; + public Message(PolygonalLine pl) { // TODO Auto-generated constructor stub } diff --git a/src/main/resources/cd/cscfa_bartleby.txt b/src/main/resources/cd/cscfa_bartleby.txt index 3e4536f..ba694bd 100644 --- a/src/main/resources/cd/cscfa_bartleby.txt +++ b/src/main/resources/cd/cscfa_bartleby.txt @@ -32,6 +32,46 @@ Encoder %实现¥#UnsynchronizedAppenderBase @+doAppend(E event): void +#append(E event): void ++addFiter Fiter <> fiter): void ++getFierChainDeciion(E event): FiterReply +@@#<> +Appender +@“+doAppend(E event): void +@@#RollingFileAppender +@#setRolingPoiicy RollngPolicy): void ++setTriggeringPolcy (TriggeringPolicy ) +@null@#FileAppender +@+setFile(String): void. ++setPrudentlooolean): void ++setAppend(boolean): void +@@FileAppender +%‘OutputStreamAppender +%实现¥#‘ConsoleAppender +@+setTarget(String): void +@@‘ConsoleAppender +%‘OutputStreamAppender +%实现¥#Filter +@+decide(E event): FilterReply +@null@Filter +%‘OutputStreamAppender +%实现¥#<> +Encoder +@#init{OutputStream): void ++doEncode(E event): void ++cose(): void +@null@#‘OutputStreamAppender +@+setOutputStream(OutputStream): void +4setEncoder Encoder ): void +@null@FileAppender +%‘OutputStreamAppender +%实现¥‘ConsoleAppender +%‘OutputStreamAppender +%实现¥Filter +%‘OutputStreamAppender +%实现¥#UnsynchronizedAppenderBase +@+doAppend(E event): void + #append(E event): void +addFiter Fiter <> fiter): void +getFierChainDeciion(E event): FiterReply diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index dfb8bb785cc5f10d32989f2aac6bb52c494b51a2..bbd181b2a3594437f73193f102c9a2d6fca87373 100644 GIT binary patch literal 21925 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 K$f@PYx&H$a@a5?M literal 13472 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 PD9^WL$Kz++{+Is?BqZ Date: Wed, 10 Mar 2021 20:39:44 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=85=B3=E7=B3=BB?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=AF=86=E5=88=AB=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/MessageDetector.java | 175 +----------------- 1 file changed, 1 insertion(+), 174 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 4f7f10c..9d85271 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -41,7 +41,7 @@ public class MessageDetector { // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 Set dash_lines = detectLines(objects_in_sd, 0.0504, false); // 再检测消息内容。由于会遍历所有关系,所以顺便将关系存在objects_in_sd中每个UMLObject的关系列表中 - result = detectRelationType(objects_in_sd, solid_lines, dash_lines, 0.0001); + // result = detectRelationType(objects_in_sd, solid_lines, dash_lines, 0.0001); } private Set detectLines(Pair> objects_in_sd, double ratio, boolean detect_solid) { @@ -344,179 +344,6 @@ public class MessageDetector { return result; } - /** - * 识别关系符号,并根据关系符号与关系线端点的位置关系更新关系线的source和target - * - * @param classes_in_cd2 - * @param dash_lines - * @param solid_lines - * @param dash_lines - * @return - */ - private Pair> detectRelationType(Pair> classes_in_cd2, Set solid_lines, Set dash_lines, double ratio) { - System.out.println("开始识别" + sd_path + "中所有关系符号"); - Mat cls_diagram = classes_in_cd2.getLeft(); - Mat origin_cls_diagram = Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE); - /* - * 识别图中所有“轮廓”并存在contours中 - */ - // 先腐蚀(让符号像素侵蚀周围空间,得以连接起来)、后膨胀(让点周围的空白区域膨胀,从而去掉孤立的噪点),提高识别准确率 - Imgproc.erode(cls_diagram, cls_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3.5, 3.5)), new Point(-1, -1), 4); - Imgproc.dilate(cls_diagram, cls_diagram, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1.7, 1.7)), new Point(-1, -1), 5); - List contours = new ArrayList<>(); - Imgproc.findContours(cls_diagram, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); - /* - * 对每个轮廓contour,检测是否为某种关系符号 - */ - // 根据图片像素计算轮廓面积阈值。如果轮廓面积太小或太大,则直接忽略 - long cd_area = cls_diagram.width() * cls_diagram.height(); - double min_area = cd_area * ratio; - double max_area = cd_area * 0.5; - for (MatOfPoint contour : contours) { - // 如果轮廓面积太小或太大,则直接忽略 - double contour_area = Imgproc.contourArea(contour); - if (contour_area < min_area || contour_area > max_area) { - // 将噪点直接涂白 - Imgproc.fillConvexPoly(cls_diagram, contour, new Scalar(255, 255, 255)); - continue; - } - // 如果轮廓面积合适,则用矩形将其包裹,并裁剪原图中的矩形区域、重新识别符号 - MatOfPoint2f curve = new MatOfPoint2f(contour.toArray()); - MatOfPoint2f approx_curve = new MatOfPoint2f(); - Imgproc.approxPolyDP(curve, approx_curve, 0.01 * Imgproc.arcLength(curve, true), true); - // 获取包络矩形 - Rect rect_containing_rela_type = Imgproc.boundingRect(new MatOfPoint(approx_curve.toArray())); - // 如果包络矩形包含某一条关系线的某一端,则检测该矩形内的符号 - // 对于虚线,由于只可能是实现或生命线,所以只需要知道是否包含即可,不用检测矩形内部图形。belong_to_dash_rela为true表示当前关系符号属于某条虚线关系线 - boolean belong_to_dash_rela = false; - for (Message dash_rela : dash_lines) { - // 如果dash_rela.source_pt_index != -1,则说明该dash_rela已经与某一包络矩形检测并对应上了,则跳过 - if (dash_rela.source_pt_index != -1) { - continue; - } - // 对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。如果包含,则belong_to_dash_line = 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类对应了pt1,则需对换source和target - if (dash_rela.source.whole.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt1, dash_rela.poly_line.l1, 35, false))) { - UMLObject temp = dash_rela.source; - dash_rela.source = dash_rela.target; - dash_rela.target = temp; - } - dash_rela.source_pt_index = 2; - dash_rela.msg = "实现"; - // 记录当前关系到UMLClass里 - dash_rela.source.out_msgs.add(dash_rela); - dash_rela.target.in_msgs.add(dash_rela); - break; - } 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类对应了pt2,则需对换source和target - if (dash_rela.source.whole.contains(ImgProcessor.reachPt(dash_rela.poly_line.pt2, dash_rela.poly_line.l2, 35, false))) { - UMLObject temp = dash_rela.source; - dash_rela.source = dash_rela.target; - dash_rela.target = temp; - } - dash_rela.source_pt_index = 1; - dash_rela.msg = "实现"; - // 记录当前关系到UMLClass里 - dash_rela.source.out_msgs.add(dash_rela); - dash_rela.target.in_msgs.add(dash_rela); - break; - } - } - // 如果该关系符号不属于任何虚线关系,则检测其是否属于某实线关系 - if (!belong_to_dash_rela) { - // 对于实线,需检测矩形内部图形,识别继承、聚合 - for (Message solid_rela : solid_lines) { - // 如果solid_line.source_pt_index != -1,则说明该solid_line已经与某一包络矩形检测并对应上了,则跳过 - if (solid_rela.source_pt_index != -1) { - continue; - } - // 记录该包络矩形是否属于当前实线关系线solid_rela。如果是的话,再去检测矩形内图形 - boolean belong_to_this_solid_rela = false; - // 方法同对dash_rela的检测。对线的每个端点,检查其本身、延伸、反向延伸这三个点是否被包含于包络矩形中。 - 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类对应了pt1,则需对换source和target - if (solid_rela.source.whole.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt1, solid_rela.poly_line.l1, 35, false))) { - UMLObject temp = solid_rela.source; - solid_rela.source = solid_rela.target; - solid_rela.target = temp; - } - solid_rela.source_pt_index = 2; - } 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类对应了pt2,则需对换source和target - if (solid_rela.source.whole.contains(ImgProcessor.reachPt(solid_rela.poly_line.pt2, solid_rela.poly_line.l2, 35, false))) { - UMLObject temp = solid_rela.source; - solid_rela.source = solid_rela.target; - solid_rela.target = temp; - } - 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_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 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); - } - } - solid_rela.msg = type; - // 记录当前关系到result里 - solid_rela.source.out_msgs.add(solid_rela); - solid_rela.target.in_msgs.add(solid_rela); - // 检测完符号类别后,对当前区域就算检测完了,不用再检测其他实线了 - break; - } - } - // 如果运行到这儿(检测完符号类别后break会直接到这儿),说明对当前区域的包络矩形与实线之间的检测完毕。相当于对当前区域检测完毕,开始检测下一个区域 - } - } - System.out.println("完成对" + sd_path + "中识别关系符号的识别。"); - return classes_in_cd2; - } - public Pair> getResult() { return result; } -- Gitee From 45b5085b34d75cbcd9f8ac349857d0912c323804 Mon Sep 17 00:00:00 2001 From: chief Date: Thu, 11 Mar 2021 23:10:59 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E4=BB=8EMessageDetector=E7=9A=84113?= =?UTF-8?q?=E8=A1=8C=E5=BC=80=E5=A7=8B=E3=80=82=E7=9B=AE=E5=89=8D=E8=83=BD?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E5=87=BA=E5=9B=BE=E4=B8=AD=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E7=BA=BF=EF=BC=88=E5=87=86=E7=A1=AE=E7=8E=87?= =?UTF-8?q?100%=EF=BC=89=EF=BC=8C=E4=BD=86=E4=B8=8E=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E8=BF=98=E6=9C=AA=E6=90=9E=E6=B8=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/MessageDetector.java | 200 +++--------------- src/main/resources/sd/temp result.png | Bin 21925 -> 13030 bytes 2 files changed, 30 insertions(+), 170 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 9d85271..dd737db 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -52,6 +52,7 @@ public class MessageDetector { System.out.println("开始识别" + sd_path + "中的虚线"); } Mat sd_diagram = objects_in_sd.getLeft(); + Mat origin_sd_diagram = Imgcodecs.imread(sd_path, Imgcodecs.IMREAD_GRAYSCALE); List UML_objects = objects_in_sd.getRight(); /* * 先检测边缘,然后从边缘集中初步检测“原始直线” @@ -74,82 +75,26 @@ public class MessageDetector { for (int i = 0; i < lines.rows(); i++) { line_segments.add(new Line(new Point(lines.get(i, 0)[0], lines.get(i, 0)[1]), new Point(lines.get(i, 0)[2], lines.get(i, 0)[3]))); } + // 看一下效果,最后注释掉 /* - * 检查“原始直线”集中是否有重合直线,去除冗余或合并 + * for (Line l : line_segments) { Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); Imgcodecs.imwrite(temp_res_path, sd_diagram); } */ - int current_size = line_segments.size(); - for (int i = 0; i < current_size; i++) { - Line line = line_segments.get(i); - // 将line与other_line做比较,标记出所有与当前直线重合、或需合并的直线 - for (int j = i + 1; j < current_size; j++) { - Line other_line = line_segments.get(j); - // 下列情况算为一条线:“两端都接近”;或其中一端接近、且两直线斜率接近;或有一部分重合 - if (line.isCoincideWith(other_line)) { - other_line.should_be_del = true; - } - } - // 去除冗余;合并同斜率 - for (int j = i + 1; j < current_size;) { - Line other_line = line_segments.get(j); - if (other_line.should_be_del) { - // 将两条直线合并为一条长直线,存在line中 - line_segments.set(i, mergeCoincideLines(line, other_line)); - // 去除冗余 - line_segments.remove(other_line); - current_size = line_segments.size(); - } else { - j++; - } - } - } - // 此时可以还有“斜率接近,但端点不接近”的线段,如果这种线段间距很小,则也合并 - current_size = line_segments.size(); - for (int i = 0; i < current_size; i++) { - Line line = line_segments.get(i); - // 将line与other_line做比较 - 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)) { - other_line.should_be_del = true; - } - } - } - // 去除冗余;合并同斜率 - for (int j = i + 1; j < current_size;) { - Line other_line = line_segments.get(j); - if (other_line.should_be_del) { - // 将两条直线合并为一条长直线,存在line中 - line_segments.set(i, mergeCoincideLines(line, other_line)); - // 去除冗余 - line_segments.remove(other_line); - current_size = line_segments.size(); - } else { - j++; - } - } - } /* * 现在所有线已识别出来 * - * 首先找出斜率为0的直线,然后在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target + * 首先找出斜率为0的每条直线,然后在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target */ for (Line l : line_segments) { - // 看一下效果,最后注释掉 - // Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); - // Imgcodecs.imwrite(temp_res_path, sd_diagram); + if (Line.getK(l) == "无穷大") { + continue; + } if (Double.parseDouble(Line.getK(l)) <= 0.1) { // 获取l的包络矩形 - Rect rect = null; - /* - * 怎么获取l的包络矩形? - * - * 怎么获取l的包络矩形? - * - * 怎么获取l的包络矩形? - */ - - Mat cutted_img = ImgProcessor.cutImage(sd_diagram, rect); + Point left_pt = l.pt1.x < l.pt2.x ? l.pt1 : l.pt2; + Rect rect = new Rect(0, (int) left_pt.y - 17, sd_diagram.width(), 22); + Mat cutted_img = ImgProcessor.cutImage(origin_sd_diagram, rect); + // 可看到截取原图中包含关系线,最后注释掉 + Imgcodecs.imwrite(temp_res_path, cutted_img); Mat edges_in_cutted = new Mat(); Imgproc.Canny(cutted_img, edges_in_cutted, 50, 50 * 3, 3, true); // 从边缘集中检测直线。膨胀(将线外面的空白区域膨胀)、腐蚀(让线侵蚀周围的空白区域),可以提高识别准确率 @@ -165,15 +110,31 @@ public class MessageDetector { for (int i = 0; i < lines_in_cutted.rows(); i++) { line_segments_in_cutted.add(new Line(new Point(lines_in_cutted.get(i, 0)[0], lines_in_cutted.get(i, 0)[1]), new Point(lines_in_cutted.get(i, 0)[2], lines_in_cutted.get(i, 0)[3]))); } - // 然后看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target + // 目前line_segments_in_cutted里的“原始直线”都画完后,一定包含原关系线。现在需找出真正的那条线、舍去其他的 + // 方法:看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target for (Line l_in_cutted : line_segments_in_cutted) { + // 看一下效果,最后注释掉 + // Imgproc.line(sd_diagram, new Point(l_in_cutted.pt1.x, l_in_cutted.pt1.y + left_pt.y - 17), new Point(l_in_cutted.pt2.x, l_in_cutted.pt2.y + left_pt.y - 17), new Scalar(25, 25, 25), 5); + // Imgcodecs.imwrite(temp_res_path, sd_diagram); + /* + * 先看看针对每条关系线,切出来的原画里识别的“原始直线集”里的线段多不多,如果不多的话,可能真就只有一条关系线 + * + * 如果真就只有一条关系线的话,那就直接根据关系线两端和对象中心的位置关系,即可确定source、target了 + * + * 顺便还能识别一下消息文字 + */ + + // 识别完文字、添加进结果,就完事了。现在关系识别正确率100% result.add(null); - break; + // break; } + } } /* * 在图中抹掉关系线,防止其影响后续识别 + * + * 有可能不需要 */ if (detect_solid) { // 实线识别结果 @@ -243,107 +204,6 @@ public class MessageDetector { return lines.get(lines.size() - 1); } - /** - * 将可能的“折线”识别并合并 - */ - private Set mergePolygonalLines(List lines) { - Set result = new HashSet<>(); - // 从第一条线开始,检查当前线与每条后面的线是否能合并 - for (int i = 0; i < lines.size(); i++) { - Line line = lines.get(i); - if (line.pt1_in_polyline && line.pt2_in_polyline) { - continue; - } - if (line.belonged_poly == null) { - // 将当前直线作为一条新折线的一段 - line.belonged_poly = new PolygonalLine(line); - result.add(line.belonged_poly); - } - // 检查当前线与每条后面的线是否能合并 - for (int j = i + 1; j < lines.size(); j++) { - Line other_line = lines.get(j); - Pair pt1_other_line = Line.ptNearLine(line.pt1, other_line); - Pair pt2_other_line = Line.ptNearLine(line.pt2, other_line); - if (pt1_other_line.getLeft() == true) { - if (pt1_other_line.getRight() == other_line.pt1) { - if (Line.ptNearPt(line.pt1, other_line.pt1, false, false, other_line)) { - // 在折线的线段list中添加other_line - line.belonged_poly.line_list.add(other_line); - // 更新line和other_line的端点状态 - line.pt1_in_polyline = true; - other_line.pt1_in_polyline = true; - // 顺便给other_line也存上折线 - other_line.belonged_poly = line.belonged_poly; - } - - } else { - if (Line.ptNearPt(line.pt1, other_line.pt2, false, false, other_line)) { - // 在折线的线段list中添加other_line - line.belonged_poly.line_list.add(other_line); - // 更新line和other_line的端点状态 - line.pt1_in_polyline = true; - other_line.pt2_in_polyline = true; - // 顺便给other_line也存上折线 - other_line.belonged_poly = line.belonged_poly; - } - } - - } - // 同上,只是换一个端点 - else if (pt2_other_line.getLeft() == true) { - if (pt2_other_line.getRight() == other_line.pt1) { - if (Line.ptNearPt(line.pt2, other_line.pt1, false, false, other_line)) { - // 在折线的线段list中添加other_line - line.belonged_poly.line_list.add(other_line); - // 更新line和other_line的端点状态 - line.pt2_in_polyline = true; - other_line.pt1_in_polyline = true; - // 顺便给other_line也存上折线 - other_line.belonged_poly = line.belonged_poly; - } - - } else { - if (Line.ptNearPt(line.pt2, other_line.pt2, false, false, other_line)) { - // 在折线的线段list中添加other_line - line.belonged_poly.line_list.add(other_line); - // 更新line和other_line的端点状态 - line.pt2_in_polyline = true; - other_line.pt2_in_polyline = true; - // 顺便给other_line也存上折线 - other_line.belonged_poly = line.belonged_poly; - } - } - } - } - } - // 设置每条折线的两端。同时记录两端的点所在的线段 - for (PolygonalLine pl : result) { - for (Line l : pl.line_list) { - Point pt = l.notInPolyPt(); - if (pt != null) { - // 如果该直线两端都“暂时不在折线中”,说明这是根单独的线。将其两端设置为折线两端即可 - if (pt.x == 23579 && pt.y == 59873572) { - pl.pt1 = l.pt1; - pl.pt2 = l.pt2; - pl.l1 = l; - pl.l2 = l; - // 无需再检查(也没得可检查,因为pl.line_list中只有这一根线) - break; - } else { - if (pl.pt1 == null) { - pl.pt1 = pt; - pl.l1 = l; - } else if (pl.pt2 == null) { - pl.pt2 = pt; - pl.l2 = l; - } - } - } - } - } - return result; - } - public Pair> getResult() { return result; } diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index bbd181b2a3594437f73193f102c9a2d6fca87373..0696c2a70b4c88e5494e2aa71293bd59c2ba88e6 100644 GIT binary patch literal 13030 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 literal 21925 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 K$f@PYx&H$a@a5?M -- Gitee From 1af7ea3d453d58e4702fd733149377797e667e55 Mon Sep 17 00:00:00 2001 From: origin Date: Fri, 12 Mar 2021 17:24:04 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E4=B8=8B=E6=AC=A1=E4=BB=8EMessageDetecto?= =?UTF-8?q?r=E7=9A=84102=E8=A1=8C=E5=BC=80=E5=A7=8B=E3=80=82=E9=92=88?= =?UTF-8?q?=E5=AF=B9=E6=96=9C=E7=8E=87=E4=B8=BA0=E7=9A=84=E7=9B=B4?= =?UTF-8?q?=E7=BA=BF=EF=BC=8C=E5=A6=82=E6=9E=9C=E4=B8=A4=E6=9D=A1=E7=9B=B4?= =?UTF-8?q?=E7=BA=BFy=E5=9D=90=E6=A0=87=E7=9B=B8=E5=B7=AE=E5=83=8F?= =?UTF-8?q?=E7=B4=A0=E8=BE=83=E5=B0=91=EF=BC=8C=E5=88=99=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E6=9D=A1=E7=BA=BF=EF=BC=88=E9=A1=BA=E5=BA=8F?= =?UTF-8?q?=E5=9B=BE=E7=89=B9=E7=82=B9=EF=BC=9A=E5=90=8C=E4=B8=80=E8=A1=8C?= =?UTF-8?q?=E4=B8=8A=E5=8F=AA=E8=83=BD=E6=9C=89=E4=B8=80=E6=9D=A1=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=BA=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/MessageDetector.java | 89 ++++++++++-------- src/main/resources/sd/temp result.png | Bin 13030 -> 13612 bytes 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index dd737db..19df660 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -82,53 +82,60 @@ public class MessageDetector { /* * 现在所有线已识别出来 * - * 首先找出斜率为0的每条直线,然后在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target + * 首先找出斜率为0的每条直线 */ + List lines_k0 = new ArrayList<>(); for (Line l : line_segments) { if (Line.getK(l) == "无穷大") { continue; } if (Double.parseDouble(Line.getK(l)) <= 0.1) { - // 获取l的包络矩形 - Point left_pt = l.pt1.x < l.pt2.x ? l.pt1 : l.pt2; - Rect rect = new Rect(0, (int) left_pt.y - 17, sd_diagram.width(), 22); - Mat cutted_img = ImgProcessor.cutImage(origin_sd_diagram, rect); - // 可看到截取原图中包含关系线,最后注释掉 - Imgcodecs.imwrite(temp_res_path, cutted_img); - Mat edges_in_cutted = new Mat(); - Imgproc.Canny(cutted_img, edges_in_cutted, 50, 50 * 3, 3, true); - // 从边缘集中检测直线。膨胀(将线外面的空白区域膨胀)、腐蚀(让线侵蚀周围的空白区域),可以提高识别准确率 - Mat lines_in_cutted = new Mat(); - if (detect_solid) { - // 实线检测时,“最小直线长度”与图像像素有关;“最大像素间隔”越小越接近实线 - Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 1); - } else { - Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 8); - } - List line_segments_in_cutted = new ArrayList<>(); - // 保存所有刚检测出来的“原始直线” - for (int i = 0; i < lines_in_cutted.rows(); i++) { - line_segments_in_cutted.add(new Line(new Point(lines_in_cutted.get(i, 0)[0], lines_in_cutted.get(i, 0)[1]), new Point(lines_in_cutted.get(i, 0)[2], lines_in_cutted.get(i, 0)[3]))); - } - // 目前line_segments_in_cutted里的“原始直线”都画完后,一定包含原关系线。现在需找出真正的那条线、舍去其他的 - // 方法:看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target - for (Line l_in_cutted : line_segments_in_cutted) { - // 看一下效果,最后注释掉 - // Imgproc.line(sd_diagram, new Point(l_in_cutted.pt1.x, l_in_cutted.pt1.y + left_pt.y - 17), new Point(l_in_cutted.pt2.x, l_in_cutted.pt2.y + left_pt.y - 17), new Scalar(25, 25, 25), 5); - // Imgcodecs.imwrite(temp_res_path, sd_diagram); - /* - * 先看看针对每条关系线,切出来的原画里识别的“原始直线集”里的线段多不多,如果不多的话,可能真就只有一条关系线 - * - * 如果真就只有一条关系线的话,那就直接根据关系线两端和对象中心的位置关系,即可确定source、target了 - * - * 顺便还能识别一下消息文字 - */ - - // 识别完文字、添加进结果,就完事了。现在关系识别正确率100% - result.add(null); - // break; - } - + lines_k0.add(l); + } + } + // 针对斜率为0的直线,如果两条直线y坐标相差像素较少,则合并为一条线(顺序图特点:同一行上只能有一条消息线) + List possible_message_lines = new ArrayList<>(); + for (Line l : lines_k0) { + // 看一下效果,最后注释掉 + // Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); + // Imgcodecs.imwrite(temp_res_path, sd_diagram); + + possible_message_lines.add(l); + } + // 然后对possible_message_lines中的每条线,在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target + for (Line l : possible_message_lines) { + // 获取l的包络矩形 + Point left_pt = l.pt1.x < l.pt2.x ? l.pt1 : l.pt2; + // 注意y坐标的变换、矩形高度设置,将影响后续识别。切的太多太少都不行 + Rect rect = new Rect(0, (int) left_pt.y - 17, sd_diagram.width(), 22); + Mat cutted_img = ImgProcessor.cutImage(origin_sd_diagram, rect); + // 可看到截取原图中包含关系线,最后注释掉 + Imgcodecs.imwrite(temp_res_path, cutted_img); + Mat edges_in_cutted = new Mat(); + Imgproc.Canny(cutted_img, edges_in_cutted, 50, 50 * 3, 3, true); + // 从边缘集中检测直线。膨胀(将线外面的空白区域膨胀)、腐蚀(让线侵蚀周围的空白区域),可以提高识别准确率 + Mat lines_in_cutted = new Mat(); + if (detect_solid) { + // 实线检测时,“最小直线长度”与图像像素有关;“最大像素间隔”越小越接近实线 + Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 1); + } else { + Imgproc.HoughLinesP(edges_in_cutted, lines_in_cutted, 1, Math.PI / 2, 8, 29, 8); + } + List line_segments_in_cutted = new ArrayList<>(); + // 保存所有刚检测出来的“原始直线” + for (int i = 0; i < lines_in_cutted.rows(); i++) { + line_segments_in_cutted.add(new Line(new Point(lines_in_cutted.get(i, 0)[0], lines_in_cutted.get(i, 0)[1]), new Point(lines_in_cutted.get(i, 0)[2], lines_in_cutted.get(i, 0)[3]))); + } + // 目前line_segments_in_cutted里的“原始直线”都画完后,一定包含原关系线。现在需找出真正的那条线、舍去其他的 + // 方法:看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target + for (Line l_in_cutted : line_segments_in_cutted) { + // 看一下效果,最后注释掉 + // Imgproc.line(sd_diagram, new Point(l_in_cutted.pt1.x, l_in_cutted.pt1.y + left_pt.y - 17), new Point(l_in_cutted.pt2.x, l_in_cutted.pt2.y + + // left_pt.y - 17), new Scalar(25, 25, 25), 5); + // Imgcodecs.imwrite(temp_res_path, sd_diagram); + // 识别完文字、添加进结果,就完事了。现在关系识别正确率100% + result.add(null); + // break; } } /* diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index 0696c2a70b4c88e5494e2aa71293bd59c2ba88e6..797a7b64740103e9c0d5d818348b101ecc80bcb0 100644 GIT binary patch literal 13612 zcmeHudsI_*zHdk(B$~o*P}wPnd)F--M@RA)1uqmr=p$)W?i$Z1omvQl$6BqU4NfK4 z3=p%0pqpt7ZM7n>&b_ybd&jnvcC~dX@{D`H2b?**R_2a~vgt5wJ;jZ4YMhe;_xsy< zfHlsXv+g~2-9HYvaOd~@{=SdT_wn0l{LkB;d1UEhOGP5lBPQdMKNg9k6(W&%S_TcG zsB5q86p09t>B-!`wME_PcNAZH`Yq9Kf2H>NEo%n<`=DZ7=a=u~f0)p;`R06^hQ*&# zS(vUj{!brzHf-^(mhrvK^R7`jpGy0hvd*VrCD$4?J%4i#%fTi)J-%c9XYAWuIi$C0 zmaN(CvZk`WlT+!uq_NlN%5hJ4+ugo+gB>15O-!bSy-Im=UGr~Z?bzhZqmxc7hGctR z*Yr@144KuPSBJ^uQbQ80kBu^j9a&O?|Cboy%{3Ycy~~+2nG4N!Y?6=;k+HK_OtlOX zn#3^QVmBH54c*IVeYVsM4gPhF6Xz)Xb~wDlWamMlV);F$fCq@ z2L{_3h}8xeW^m=pc!H7|>huP}TRQ}EpQx7I!)BKg`B6ZcjFQSUJ%n)Nr(I4rCWBT= zI!nT;w2#K(U>#tZjP?;T23HPd$Oe88`3_8G#gt+iFLDPMPNJ27@Sz<95D27YlU`vp zM9mDGgv^E+2G_(;UeXi^v|~mYR$|Wu3DY76CZ;hl%o3yqOOf7G+UCit(-Xk2C?J8x zR?``XBgQ&R8EAxdCT$2WYWAm0oej;_i_z?WuuQR0l}6xgHd@;ob8nlBLcB&?oP9Ag z`wcsiCfX#4wz)fiF0n%pb*sM44y>(C09N?6XG`H=s|~OeF$07OqPpnG>uyGBCd>tD zf$Jcx-Zj90Sc4c^r$Da~K$Wt*g2M4cgNRI?f?)#7nIaPOS2MTN!W0o+CuZ@lVDX%_ z4K}QV=^eni4(X&R(5-n(%i@-G7Un-59>#sHX+}y<^^aXHxLnXzaB1wqnYONz z)*o^|VBcnR_*vLy8Gcmtg6b-)_I}y!^BK+7XiK_flO@Wcv8?9~!fGEgr|}By|1F|x zns~EaUDFitM9{g0yNX9537X^T^)hd#I^v-_HOY#+0pF&GXSZqRYFQ^~eb~0i6zX?i zcrP1~Niihqx4IuTUr(U^Vzbe&jL0{lVc)xVF5HVCS@L$%$Aw#3A_#Yj-SXb9k@5$1 zWa?((>2sCZ2gQ?;KT+__n;)qj6lb-MeW~-*r3c0Tc2ZB*7wao@4{A|;U-}mZzuXf+ zk@T?>1=DZdiLi}CTCyVI`IG2^^AQ;vr#u~5*uxK*@c&$0Bih)^5ZR-vDeaDTRf+lM znEA-oJnz;|IzgXJhRIyR$b`w zi!4QKeMpBPE7B>WE%A-15m~mUr2GGKXTk4hr>U9?5kVrS!oGd7Bcfx3Y0Y3cL*zrJ zW*Lpq^$u@-L^sC``}VWB;zp;Q;CDp!9ByI6*6T}@Ib{(&wiBxz$uJTsne-te6qqZg zBFiX~dgzCcA=%<>Z*IV3)v_%Q8IhO#5M-TQ9vMKZk94vR!u{|L`=$pGeOvP6Ma_dA zAO$P>Wdy%O`zj;&F^BiKbe+TW~UHCZM?tgka-}GML^V5g<^mCP(=hINs;+rsa>w22^+bySeeNkQP z-`2T%`xi%e9ox*eo|;T-Irrg(W!y}4ndJHP>?oekRvG-GQ;9E}`;eKyYk#wzo4D-T z?wWraO@E6|w#k1Q{m_TzJr58Kgab$zq-GI3Q5kMZ~?hpsWMH>lB93|#E!06!U zdk1_DKG)!Jt10lV`T?6d+h|lmAV8C(36Gn_a2%fR8@*jT+}9_#dP$=b{4)BaR)ceH zbVe!TJl=l&6bgw18r>OqOkT1<1`6!4 zLE-_zIwR*|l!S>;;dr#iQ3@_R$|LnS9K~j{(g?u}XU2_n6u*v)1=s;yPcQZx4PrTv zfDRy+H^#{2a1hBLG(a#C8*PMX^|W`jTnbr<Dz>9LN${B7V|Qlz!3@9?zUB! z%~?kDjDtt>t`72_<_Ufz1E0kVLpzd~Dy2DEY;|`i)ST0sDUswQYx@-HK|SHdCZ7pu z0@N@nk`xlTo9by6nZ(0-Es7n7eXvkaUx(G0jM7iWgl5#~yLEaGjH7@w3Mq^{&)`v0 zb3=W76bgX{1vTfw6Cm&MOU_*&9lm2BiHRqC4F{i^j1R3@>0@*L=X$mxC?i915C8f< zt!&o@)w}x7Y|fR$+Q&m5Vf5AY;oj!K^tu00c<IXtJB3MiqqX9qyslCw5j0*NaYqBc>DB?R6n9S`D zSlR{(%c=0UWl7oE<}-%^ecu?3{x|s7qK)|cw#lWzaciQKGTJWNLOZf(eHKm>6Ii8e z3frX?4BVpPoHRv(@_^8R&Nv4=0G9}N!H_LTmlm=OHJCU6 zh@$$4)2iOurUkjK^w_k)4L}7Tb3ya8RF5vU-joHprCcWG&4H8sCnaPF(SQqpaYkd3 zLI6LLp@ei~-~o)_;;v^%h3EcdT>L)0Ffk^L$%o(?;aZ}t*#31>9y)N0Hd($)_ASoCT$x$0fbLn6Ra=rwJY-j8a7yx6p;U+1q7F1j85UrgeqhVb@~mKI*_0W+*O<)P{{JYXL&+OKXfyZd%aL) zS;M6$9Q&BjZY{f+-F70WN0WW$0{(kEos65n+g~eVUSwL_9pM2(gX!!vOiSQWw#LGM z>N4hM;K!ulX~kfMOwPeFrU{z$#7+&W9|e3D;ay~BS;luuP=p`Qx#q?87)U7>1RXTf ze@kOAA}P>Q0w=oSjc#aC~#9k-4HERs5IgPe^usP6b({odloWjq~Xic_S}h< zE`Usjt+*vUws--6>Jv5}kUMyUrDI06y9L>$affz;;i z56&kxh!z?;w-Jj1;Gz~RZeg{e7H{*y-dD>*Ic)$%0u@VGvt=PRKO+a{{ag@c{@T;7 zp&kAq-!c9)6UP<>wcsVT)9s_7hSRB=(*^>how}OCJmqlc0RzQy08BY5)nGCO6z0L+ z2)7iRiQxDPF8fx18y)Neo0AMetR}=fgJ6Pk398np70hS|J^1xg>lBSK!)kYi0HYiM zKG&3_00%5M-+FHavx?EQ38$+$>}@V3;#AR|tkR(!b>3X@CA~qWp!>k%N+)x**=4r~ z4b&@OZM4CDVJw$mMZvN84(U){bfqy_X}FR2>7Q7V?L+LgI1=`L^N33m5QFXJ zC)YE)zN&zC9l;^u3}_l3ykw^(8tHOa6oJ00Q_JPCrp z+XMD)Vffd<*J@bbGZ0AQ7XKOuNEyxCF_<-Xo&mg`d;WWmO;W>+`TymV+}iBfpg#2W zZ-{SeH~$g;D*8v?+&%Ebtn1{j_G11=Nw+@Qqi3v}xNZ2vF(_S`aokw%#S?VbX};8+ z3URPWt9DcDnKnL!iD}&TluR*2N+fcUJ#!LToY(|IgOJQbl+v>Mk}W=3=B+9*LoBRR zdK?<|Jd+L}7PtA=9}PFPehURN#u^1%iC6FWd4)6a?6`{iG25cvV*lW`t&i-zb)bTI zPPNaFoIUpS$V=(lU#Vc$!^gJlu|JMf-v1GLtrg5N)xLqLubkVyWy9SA?uN1R1>dsr zZyD=a*lCD7pxJz;>vyf1_shEFQ07grNG#0V@@_dtK&BSW;xm_R@vL*vb92|xE+G9i zU;*4;M0f%zWWmyB;lg%Q81z6xSDkmCdalGDCxLs{XkqL!qx}ebz z8Iw0@21f*? z6;c^Zj|@m8ut4wkjK^YM1q-_eV_L2?EujMFg7m(@gTjmse-wH_cp%J+I0*B0|I<~Q&sYy-T6X`&7GK{NlQ{mn8-g%b zAz|JGS?{T|d<5OYg0A`YvG^|Sb=r!R_|q+DL%=F1SL58XKuR0KPcWMIOS|P3{}X{; zymmCu$Kq+Q1dDTPVGeHTreJ*wa~#HUXFYlT27X>!5)f5wxm-JY3jYzb78odjE zQW#2pAC_vek=Q?7iz$uuWHCf3PWi1>(^WFjE_ynVBB3`pzq|~ z?sJ*bXS+t@Vl_1_FemLRHvN_9J?RJj9Od=>jBRm`mmE#pH#2f?@2xw|JZ1t};B%kx zk6ha_-t>!_S6uw>!|SfUHpa!|2bSsliv9iBJKLv7b_PMxPsVL8S6x4vR3fmLzsq#} zQqPR4uhW{jHq950mVk|=FhaA}mjn{!W>l6{7P}|V`aM-xEOY=^4-mj;3enho+lg4E zu@1DScP-X?9_Mx-;`S*aXT?Cfe3_8e4u)D$>Y$?_ksW~h52;wFhy=7kX(U+R6QGFo z-hQ`2E(d=qr@&WoX~I1L*tN$&YS?{96s7hTprk>naAOih_UR!vZ->-^;`%{$2sK`W zWs<3$^^NV9AQ^c!St+i*VAIxkL^`nctg<>4IKy5f`drt(XD8F(2Hxv*ltRGDHcL@y z!sCG4#0Wr#_nsF_=Pt#sHUJEWq4;4mviXYwTO}ZdFsjmLZqDr7+BTUhreeipoC=rG zd;+}qK?Ay=K%I2p++8qS%xC_unG+{9Y&*ze_@=YzTSk*TYKxz}-M_Pn#oIyJ)qjQ| z0mRI*e{iK$!*(F}MivhPD!S!)H^S4Rg^evtPO*U54F6-`e-aI5x*UWWrvyVS0sR>c zHU#YUei3Te=fGMttjz?BL&jb(#a;ob3XgSpn|6U~;SVxv_jUu)Fjp<_zQS#~rm}P= zaXCy*6}JLC$3lrcjvF1fEdlyE2jL<%tug24+>&dmv|)TbUZI(LqOqM>;lEK?#lEa% zm$J_@Z$9vmNj(0UuJBFGPW4F1yQS}%8GadC(4TR%%hLsUZ5nP_!fjxmg~@oYnOVVn zgs)ev2k(C9-(f<#C(m5xwWWvm=Nl-u+Kun~jc}Ts+MVh-25^94|5+0{4U=QZGNx#* zyTkPORa~ypm9Jxu>h2rl@m83atL5P{)WYQ+ZnS$a?j2S5kgFka5H*fI>f$djU5BhI zEo&`Ha?T6^WE7qV?y%t%&X7}wcU}wrK!7i)dj&!438>f|n0NJ30~*0FrDkhWW61_f$*+o^~nBhK-M7 z+?%2Gm$FaMc-rMfotnayFgtd8@wAa}AM0BZB(tC&=Mq9YE`b-jjt5TrSDx%vF<-^x zn3<1*s=&S6?Di$HtJUmJ1Nz1A@0jXnD7wNcI9R^e1nKhZad#dr^A>o6YSr^2z!!)Z ziizSZBMv1^5|u#eY0XMaPzlp6`;Iys-du?6GH|1er-UMCF`=1T!KDTj()SNcFL)Ip zOwT%u0_N!YsPft6T+uO`Hnh$*F@iHFxB8BHn=#~D>H%}OiTKHoj`wVq%N3MVY%&-o z3DP8#SV_45RdPj-x|~6#bbpXIak*7@En_e)HY#+^5BJ)isXB1h`qpZ_AbDVE+Ba;~ z&nrGnthm=th8XmdabMfFw_fG4axzMhg4{nWKeWTI5+^=yJ-7GNbWB5V<}MvOah6{- z{=0ur}JK!#p|4^kEy5N0y$b~3Cbf%QV@VBKV4J}nO~%)X!tFnu?~Ht(q_G{|1x zFK75K7WPUV-rG+mYodh7UzpHN@h>n%9-GJQTgCc*v~W}t+e||aSSyDL8oZ#A zFP1|_2Ci%i6kwn@>%iL=D9;}DK`H>T3o5s&LF`b5)y_Q*L8=g|s<_X?ltA3oGPMqy zMB^3Ipx)zyA}MlK;L8|L7rhp+KXimFBQrtq%?lc4$bzUQ9~@Gs5^J%a40Al!#kVlM z5b~5ls$xvx6B?aT4^IiT`%<$KO1+xw%K<~MZh~;%pVF9WLWNhT8|N9c;6f=bRjAxU zEg6EGM*jJr!ktzPk?j0u{P?x%yl~Sj#`TW-e)(1bH z-7772O<-Nf)%c$>{CUBl?9zcm7JWimnP3sfyo`4a<3&t>K0v4Xf7R113Zf$4l169N z`5XS_p>hjv7t;Hfxt=N;47PU(}8imIDCu#!Dc^9!=%pW)^Q)hP7F zuJ#!InjGG62$*2g;(|VejnN(&IAHP!m0<|Hb3Nlf+i?+EDEfum_(0~}8OmyC^e$haXodJaV;rQ6C7`U_&6cNE$ zkIW%LemaPDkJA}Jl@gSQ4D$@B5k#>Ol&U*rK`S-vV?h%B@{@Jb7B8eO7P~4q+^Uh2 zb1haid%QTf#Z^xRs$&(OfNKJ$9^PTa0KLw<5oGi3i#7LE27D+08M9C*Sp^lGqMktZhGKzTuT-EPQK11du_;Pc?h_E-251IJTT zyZ8y@cGz}ZV94yB`Zs?M1BO43d13rs2H4!>0%aocg`5#};fjiz-6bR%UUcZupYU2j|0 zads%CES&a$ZnJu`Ze!W0(Xq=J!H5j>dM}iL%Gr0AJF2sbSm3Lubmf#r+_aW*c-u7* z*UHhxMvF~m0-GNi>l?dt<_&AMC7s(Hb|~{k7rbQ#cgSBEBCK)8`65I_kvKcn)LJ7d zjsnG6H)`pqkK6Mo^E92P_?{^%3gOivKG(-e|g;O4rP8cPEb7IpdA#C z?nQtux08N@vTB(E-4PA;0gnlf{ zf=LcqDwCqCa~XV52h}ujNG#E_!l9VLqGfOkV;mw;kxML*150PNPEH*2?E;<8Y(_76 m%pZYDONDa&klvp;A5+Hvv33Oe2>ew9s literal 13030 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 -- Gitee From 7eb2d806dd83dd872684a4f037af6cf3adf87a76 Mon Sep 17 00:00:00 2001 From: chief Date: Mon, 15 Mar 2021 21:38:35 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=B7=B2=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E8=AF=86=E5=88=AB=E5=AE=8C=E6=AF=95=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E4=B8=8B=E6=9D=A5=E6=95=B4=E5=90=88=E7=BB=93=E6=9E=9C=E5=8D=B3?= =?UTF-8?q?=E5=8F=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umlrecog/sddetector/MessageDetector.java | 163 +++++++++++------- .../hy/java/uct/umlrecog/util/Message.java | 9 +- .../hy/java/uct/umlrecog/util/UMLObject.java | 5 +- src/main/resources/sd/temp result.png | Bin 13612 -> 12855 bytes 4 files changed, 110 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java index 19df660..7a2fb22 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java +++ b/src/main/java/com/hy/java/uct/umlrecog/sddetector/MessageDetector.java @@ -1,14 +1,12 @@ package com.hy.java.uct.umlrecog.sddetector; +import java.io.File; import java.util.ArrayList; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.opencv.core.Mat; -import org.opencv.core.MatOfPoint; -import org.opencv.core.MatOfPoint2f; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; @@ -16,13 +14,17 @@ import org.opencv.core.Size; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; +import com.hy.java.uct.umlrecog.UMLDiagramRecognizer; import com.hy.java.uct.umlrecog.util.ImgProcessor; import com.hy.java.uct.umlrecog.util.Line; import com.hy.java.uct.umlrecog.util.Message; -import com.hy.java.uct.umlrecog.util.PolygonalLine; import com.hy.java.uct.umlrecog.util.UMLObject; import com.hy.java.utility.common.Pair; +import net.sourceforge.tess4j.ITesseract; +import net.sourceforge.tess4j.Tesseract; +import net.sourceforge.tess4j.TesseractException; + public class MessageDetector { private String sd_path = null; private String temp_res_path = null; @@ -37,15 +39,17 @@ public class MessageDetector { public void recog() { // 先检测实线。检测结果需借助对象的位置关系、去除“单纯的线” - Set solid_lines = detectLines(objects_in_sd, 0.0504, true); + Set solid_msgs = detectLines(objects_in_sd, 0.0504, true); // 再检测虚线。虚线检测除了间隔设置与实线不同外,其他完全一样 - Set dash_lines = detectLines(objects_in_sd, 0.0504, false); - // 再检测消息内容。由于会遍历所有关系,所以顺便将关系存在objects_in_sd中每个UMLObject的关系列表中 - // result = detectRelationType(objects_in_sd, solid_lines, dash_lines, 0.0001); + // Set dash_msgs = detectLines(objects_in_sd, 0.0504, false); + Set dash_msgs = null; + // 合并实线和虚线识别结果。对所有UMLObject设置out_relas和in_relas + result = mergeMessages(objects_in_sd, solid_msgs, dash_msgs); } private Set detectLines(Pair> objects_in_sd, double ratio, boolean detect_solid) { Set result = new HashSet<>(); + List temp_result = new ArrayList<>(); if (detect_solid) { System.out.println("开始识别" + sd_path + "中的实线"); } else { @@ -95,13 +99,36 @@ public class MessageDetector { } // 针对斜率为0的直线,如果两条直线y坐标相差像素较少,则合并为一条线(顺序图特点:同一行上只能有一条消息线) List possible_message_lines = new ArrayList<>(); - for (Line l : lines_k0) { + int lines_k0_size = lines_k0.size(); + for (int i = 0; i < lines_k0_size; i++) { + Line l = lines_k0.get(i); // 看一下效果,最后注释掉 // Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); // Imgcodecs.imwrite(temp_res_path, sd_diagram); - + if (l.should_be_del) { + continue; + } + for (int j = i + 1; j < lines_k0_size; j++) { + Line other_l = lines_k0.get(j); + // 记录l的左右端点 + Point l_left_pt = l.pt1.x < l.pt2.x ? l.pt1 : l.pt2; + Point l_right_pt = l.pt1.x > l.pt2.x ? l.pt1 : l.pt2; + // 记录other_l的左右端点 + Point other_l_left_pt = other_l.pt1.x < other_l.pt2.x ? other_l.pt1 : other_l.pt2; + Point other_l_right_pt = other_l.pt1.x > other_l.pt2.x ? other_l.pt1 : other_l.pt2; + if (Math.abs(l_left_pt.y - other_l_left_pt.y) <= 4) { + other_l.should_be_del = true; + Point merged_l_left_pt = l_left_pt.x < other_l_left_pt.x ? l_left_pt : other_l_left_pt; + Point merged_l_right_pt = l_right_pt.x > other_l_right_pt.x ? l_right_pt : other_l_right_pt; + l = new Line(merged_l_left_pt, merged_l_right_pt); + } + } possible_message_lines.add(l); } + // 看一下效果,最后注释掉 + /* + * for (Line l : possible_message_lines) { Imgproc.line(sd_diagram, l.pt1, l.pt2, new Scalar(25, 25, 25), 5); Imgcodecs.imwrite(temp_res_path, sd_diagram); } + */ // 然后对possible_message_lines中的每条线,在原图中切下包含该直线的部分,单独识别。将两端坐标与每个对象做比较,设置source、target for (Line l : possible_message_lines) { // 获取l的包络矩形 @@ -129,15 +156,64 @@ public class MessageDetector { // 目前line_segments_in_cutted里的“原始直线”都画完后,一定包含原关系线。现在需找出真正的那条线、舍去其他的 // 方法:看line_segments_in_cutted里的线是否与其他对象有关系。如果有,则设置source和target for (Line l_in_cutted : line_segments_in_cutted) { + // 由于cutted的图中的线的坐标与原图坐标不同,所以需将在cutted图中识别的线坐标转换为原图中的线坐标 + Line l_converted_to_uncutted = new Line(new Point(l_in_cutted.pt1.x, l_in_cutted.pt1.y + left_pt.y - 17), new Point(l_in_cutted.pt2.x, l_in_cutted.pt2.y + left_pt.y - 17)); // 看一下效果,最后注释掉 - // Imgproc.line(sd_diagram, new Point(l_in_cutted.pt1.x, l_in_cutted.pt1.y + left_pt.y - 17), new Point(l_in_cutted.pt2.x, l_in_cutted.pt2.y + - // left_pt.y - 17), new Scalar(25, 25, 25), 5); + // Imgproc.line(sd_diagram, l_converted_to_uncutted.pt1, l_converted_to_uncutted.pt2, new Scalar(25, 25, 25), 5); // Imgcodecs.imwrite(temp_res_path, sd_diagram); - // 识别完文字、添加进结果,就完事了。现在关系识别正确率100% - result.add(null); - // break; + // 检测线与对象间的位置关系 + Point uncutted_left_pt = l_converted_to_uncutted.pt1.x < l_converted_to_uncutted.pt2.x ? l_converted_to_uncutted.pt1 : l_converted_to_uncutted.pt2; + Point uncutted_right_pt = l_converted_to_uncutted.pt1.x > l_converted_to_uncutted.pt2.x ? l_converted_to_uncutted.pt1 : l_converted_to_uncutted.pt2; + for (UMLObject UML_object : UML_objects) { + if (Math.abs(UML_object.whole.x + UML_object.whole.width / 2 - uncutted_left_pt.x) < UML_object.whole.width / 4) { + boolean found_target = false; + for (UMLObject possible_target_UML_object : UML_objects) { + if (Math.abs(possible_target_UML_object.whole.x + possible_target_UML_object.whole.width / 2 - uncutted_right_pt.x) < possible_target_UML_object.whole.width / 4) { + Message msg = new Message(l_converted_to_uncutted); + msg.source = UML_object; + msg.target = possible_target_UML_object; + // 识别文字 + ITesseract instance = new Tesseract(); + instance.setDatapath(UMLDiagramRecognizer.tessdata_path); + try { + // 注意这里用的就是刚写入的cutted_img + msg.msg = instance.doOCR(new File(temp_res_path)); + } catch (TesseractException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // 识别完文字、添加进结果,就完事了。现在关系识别正确率100% + temp_result.add(msg); + found_target = true; + break; + } + } + if (found_target) { + break; + } + } + } } } + // 目前所有关系已识别出来,但可能有重复。去除一下冗余 + int temp_result_size = temp_result.size(); + for (int i = 0; i < temp_result_size; i++) { + Message msg = temp_result.get(i); + // 看一下效果,最后注释掉 + // Imgproc.line(sd_diagram, msg.line.pt1, msg.line.pt2, new Scalar(25, 25, 25), 5); + // Imgproc.putText(sd_diagram, msg.msg, msg.line.pt1, 5, 5, new Scalar(25, 25, 25)); + // Imgcodecs.imwrite(temp_res_path, sd_diagram); + if (msg.is_redu) { + continue; + } + for (int j = i + 1; j < temp_result_size; j++) { + Message other_msg = temp_result.get(j); + if (Math.abs(msg.line.pt1.y - other_msg.line.pt1.y) <= 2) { + other_msg.is_redu = true; + } + } + result.add(msg); + } /* * 在图中抹掉关系线,防止其影响后续识别 * @@ -145,31 +221,21 @@ public class MessageDetector { */ if (detect_solid) { // 实线识别结果 - for (Message 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 + - // ")"); + for (Message msg : result) { // 在图中抹掉已识别的线,防止干扰后续识别 - for (Line segment : rela.poly_line.line_list) { - Imgproc.line(sd_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); - } + Imgproc.line(sd_diagram, msg.line.pt1, msg.line.pt2, new Scalar(255, 255, 255), 5); // 看一眼。看结果相当于把抹掉的线再画出来,会影响后续识别,所以看完就注释掉 - // Imgproc.line(cls_diagram, rela.poly_line.pt1, rela.poly_line.pt2, new Scalar(55, 55, 55), 5); + // Imgproc.line(sd_diagram, rela.line.pt1, rela.line.pt2, new Scalar(25, 25, 25), 5); } Imgcodecs.imwrite(temp_res_path, sd_diagram); System.out.println("完成对" + sd_path + "中的实线识别,共" + result.size() + "条"); } else { // 虚线识别结果 - for (Message 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 + - // ")"); + for (Message msg : result) { // 在图中抹掉已识别的线,防止干扰后续识别 - for (Line segment : rela.poly_line.line_list) { - Imgproc.line(sd_diagram, segment.pt1, segment.pt2, new Scalar(255, 255, 255), 5); - } + Imgproc.line(sd_diagram, msg.line.pt1, msg.line.pt2, new Scalar(255, 255, 255), 5); // 看一眼。看结果相当于把抹掉的线再画出来,会影响后续识别,所以看完就注释掉 - // Imgproc.line(cls_diagram, rela.poly_line.pt1, rela.poly_line.pt2, new Scalar(55, 55, 55), 5); + // Imgproc.line(sd_diagram, rela.line.pt1, rela.line.pt2, new Scalar(25, 25, 25), 5); } Imgcodecs.imwrite(temp_res_path, sd_diagram); System.out.println("完成对" + sd_path + "中的虚线识别,共" + result.size() + "条"); @@ -177,38 +243,9 @@ public class MessageDetector { return result; } - /** - * 将斜率接近的两条直线合并成“最长”的一条线,并存在line中 - */ - private Line mergeCoincideLines(Line line, Line other_line) { - // 两条线的4个端点共可能有4C2条直线,把最长的一条存在line中即可 - Line l1 = new Line(line.pt1, line.pt2); - Line l2 = new Line(line.pt1, other_line.pt1); - Line l3 = new Line(line.pt1, other_line.pt2); - Line l4 = new Line(line.pt2, other_line.pt1); - Line l5 = new Line(line.pt2, other_line.pt2); - Line l6 = new Line(other_line.pt1, other_line.pt2); - List lines = new ArrayList<>(); - lines.add(l1); - lines.add(l2); - lines.add(l3); - lines.add(l4); - lines.add(l5); - lines.add(l6); - return MessageDetector.longestLine(lines); - } - - /** - * 返回一列直线中最长的直线 - */ - private static Line longestLine(List lines) { - lines.sort(new Comparator() { - @Override - public int compare(Line l1, Line l2) { - return Integer.compare((int) l1.length, (int) l2.length); - } - }); - return lines.get(lines.size() - 1); + private Pair> mergeMessages(Pair> objects_in_sd, Set solid_msgs, Set dash_msgs) { + // TODO Auto-generated method stub + return null; } public Pair> getResult() { diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java index b40a325..9086562 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/Message.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/Message.java @@ -2,6 +2,11 @@ package com.hy.java.uct.umlrecog.util; public class Message { + /** + * 标志其可能与其他msg重复 + */ + public boolean is_redu; + public UMLObject source; public UMLObject target; public Line line; @@ -10,7 +15,7 @@ public class Message { public PolygonalLine poly_line; - public Message(PolygonalLine pl) { - // TODO Auto-generated constructor stub + public Message(Line line) { + this.line = line; } } diff --git a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java index 8b8ff11..530ac65 100644 --- a/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java +++ b/src/main/java/com/hy/java/uct/umlrecog/util/UMLObject.java @@ -1,5 +1,6 @@ package com.hy.java.uct.umlrecog.util; +import java.util.ArrayList; import java.util.List; public class UMLObject { @@ -12,8 +13,8 @@ public class UMLObject { */ public Rectangle whole; private String title; - public List out_msgs; - public List in_msgs; + public List out_msgs = new ArrayList<>(); + public List in_msgs = new ArrayList<>(); public String getTitle() { return title; diff --git a/src/main/resources/sd/temp result.png b/src/main/resources/sd/temp result.png index 797a7b64740103e9c0d5d818348b101ecc80bcb0..b870453967f8ecf877d45a7b69e97c561eadde17 100644 GIT binary patch literal 12855 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 O;@)%cg)0uvss9arMhsE_ literal 13612 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 m%pZYDONDa&klvp;A5+Hvv33Oe2>ew9s -- Gitee