[shotwell/wip/phako/enhanced-faces: 8/136] Facedetect process talks over DBus



commit 4c84248b80ebf3a1f1eb05aa60625d9d8c5d0134
Author: NarendraMA <narendra_m_a yahoo com>
Date:   Thu Jun 28 16:46:03 2018 +0530

    Facedetect process talks over DBus

 facedetect/org.gnome.ShotwellFaces1.xml |  6 +++
 facedetect/shotwell-facedetect.cpp      | 11 ++++-
 src/AppDirs.vala                        |  3 +-
 src/faces/Face.vala                     | 29 ++++++++++++
 src/faces/FaceDetect.vala               | 73 +++++++++++++++++++++++++++++
 src/faces/FacesTool.vala                | 81 ++++++++-------------------------
 src/faces_opencv/faces_opencv.cpp       |  8 ++--
 src/meson.build                         |  4 +-
 vapi/faces.vapi                         | 38 ----------------
 9 files changed, 145 insertions(+), 108 deletions(-)
---
diff --git a/facedetect/org.gnome.ShotwellFaces1.xml b/facedetect/org.gnome.ShotwellFaces1.xml
index b621f56f..17d1ba1b 100644
--- a/facedetect/org.gnome.ShotwellFaces1.xml
+++ b/facedetect/org.gnome.ShotwellFaces1.xml
@@ -48,5 +48,11 @@
       <arg type="d" name="threshold" direction="in" />
       <arg type="a(sd)" name="labels" direction="out" />
     </method>
+
+    <!--
+        Terminate
+    -->
+    <method name="Terminate">
+    </method>
   </interface>
 </node>
diff --git a/facedetect/shotwell-facedetect.cpp b/facedetect/shotwell-facedetect.cpp
index 9f3f52f2..a1f75f60 100644
--- a/facedetect/shotwell-facedetect.cpp
+++ b/facedetect/shotwell-facedetect.cpp
@@ -29,13 +29,13 @@ static gboolean on_handle_detect_faces(ShotwellFaces1 *object,
     for (vector<FaceRect>::const_iterator r = rects.begin(); r != rects.end(); r++) {
         GVariant *rect = g_variant_new("(dddd)", r->x, r->y, r->width, r->height);
         g_variant_builder_add(builder, "(dddd)", rect);
+        g_debug("Returning %f,%f", r->x, r->y);
     }
     faces = g_variant_new("a(dddd)", builder);
     g_variant_builder_unref (builder);
     // Call return
     shotwell_faces1_complete_detect_faces(object, invocation,
                                           faces);
-    g_free(faces);
     return TRUE;
 }
 
@@ -55,12 +55,21 @@ gboolean on_handle_recognise_face(ShotwellFaces1 *object,
     return TRUE;
 }
 
+gboolean on_handle_terminate(ShotwellFaces1 *object,
+                             GDBusMethodInvocation *invocation) {
+    g_debug("Exiting...");
+    exit(0);
+    return TRUE;
+}
+
 static void on_name_acquired(GDBusConnection *connection,
                              const gchar *name, gpointer user_data) {
     ShotwellFaces1 *interface;
     GError *error;
     interface = shotwell_faces1_skeleton_new();
+    g_debug("Got name %s", name);
     g_signal_connect(interface, "handle-detect-faces", G_CALLBACK (on_handle_detect_faces), NULL);
+    g_signal_connect(interface, "handle-terminate", G_CALLBACK (on_handle_terminate), NULL);
     error = NULL;
     !g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface), connection, 
"/org/gnome/shotwell/faces", &error);
 }
diff --git a/src/AppDirs.vala b/src/AppDirs.vala
index 1515f05a..d42b7b32 100644
--- a/src/AppDirs.vala
+++ b/src/AppDirs.vala
@@ -330,7 +330,6 @@ class AppDirs {
     }
 
 #if ENABLE_FACES
-/*
     public static File get_facedetect_bin() {
         const string filename = "shotwell-facedetect";
         File f = AppDirs.get_libexec_dir().get_parent().get_child("facedetect").get_child (filename);
@@ -339,7 +338,7 @@ class AppDirs {
         }
         return f;
     }
-  */  
+
     public static File get_haarcascade_file() {
         File f = 
File.new_for_path(AppDirs.get_exec_dir().get_parent().get_parent().get_child("facedetect").get_child("facedetect-haarcascade.xml").get_path());
         if (f.query_exists()) {//testing meson builddir
diff --git a/src/faces/Face.vala b/src/faces/Face.vala
index 9be33c9d..722e1727 100644
--- a/src/faces/Face.vala
+++ b/src/faces/Face.vala
@@ -346,9 +346,18 @@ public class Face : DataSource, ContainerSource, Proxyable, Indexable {
         // add them all at once to the SourceCollection
         global.add_many(faces);
         global.init_add_many_unlinked(unlinked);
+
+#if ENABLE_FACES       
+        // Start the face detection background process
+        // FaceTool talks to it over DBus
+        start_facedetect_process();
+#endif
     }
     
     public static void terminate() {
+        try {
+            FaceDetect.interface.terminate();
+        } catch(Error e) {}
     }
     
     public static int compare_names(void *a, void *b) {
@@ -366,6 +375,26 @@ public class Face : DataSource, ContainerSource, Proxyable, Indexable {
     public static bool equal_name_strings(void *a, void *b) {
         return String.collated_equals(a, b);
     }
+
+#if ENABLE_FACES       
+    private static void start_facedetect_process() {
+        message("Launching facedetect process: %s", AppDirs.get_facedetect_bin().get_path());
+        // Start the watcher
+        FaceDetect.init();
+        // Start the background process
+        string[] argv = {AppDirs.get_facedetect_bin().get_path()};
+        int child_pid;
+        try {
+            GLib.Process.spawn_async(null, argv, null, GLib.SpawnFlags.SEARCH_PATH | 
+                                     GLib.SpawnFlags.DO_NOT_REAP_CHILD, null, out child_pid);
+            message("Spawned facedetect, child pid: %d", (int)child_pid);
+        } catch (Error e) {
+            debug("Error spawning process: %s", e.message);
+            if (child_pid != 0)
+                GLib.Process.close_pid(child_pid);
+        }
+    }
+#endif
     
     // Returns a Face for the name, creating a new empty one if it does not already exist.
     // name should have already been prepared by prep_face_name.
diff --git a/src/faces/FaceDetect.vala b/src/faces/FaceDetect.vala
new file mode 100644
index 00000000..259d11e0
--- /dev/null
+++ b/src/faces/FaceDetect.vala
@@ -0,0 +1,73 @@
+/**
+ * Face detection and recognition functions
+ * Copyright 2018 Narendra A (narendra_m_a(at)yahoo(dot)com)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+// DBus interface definition
+public struct FaceRect {
+    public double x;
+    public double y;
+    public double width;
+    public double height;
+}
+
+[DBus (name = "org.gnome.Shotwell.Faces1")]
+public interface FaceDetectInterface : Object {
+    public abstract FaceRect[] detect_faces(string inputName, string cascadeName, double scale)
+        throws IOError, DBusError;
+    public abstract void terminate() throws IOError, DBusError;
+}
+
+// Class to communicate with facedetect process over DBus
+public class FaceDetect {
+    public const string DBUS_NAME = "org.gnome.shotwell.faces";
+    public const string DBUS_PATH = "/org/gnome/shotwell/faces";
+    public static bool connected = false;
+    
+    public static FaceDetectInterface interface;
+
+    public static void create_interface(DBusConnection connection, string bus_name, string owner) {
+        message("Dbus name %s available", bus_name);
+        if (bus_name == DBUS_NAME) {
+            try {
+                interface = Bus.get_proxy_sync (BusType.SESSION, DBUS_NAME, DBUS_PATH);
+                connected = true;
+            } catch(IOError e) {
+            }
+        }
+    }
+
+    public static void interface_gone(DBusConnection connection, string bus_name) {
+        message("Dbus name %s gone", bus_name);
+        connected = false;
+    }
+    
+    public static void init() {
+        //Bus.watch_name(BusType.SYSTEM, DBUS_NAME, BusNameWatcherFlags.NONE, create_interface, 
interface_gone);
+        try {
+            interface = Bus.get_proxy_sync(BusType.SESSION, DBUS_NAME, DBUS_PATH);
+            connected = true;
+        } catch(IOError e) {
+        }
+    }
+}
diff --git a/src/faces/FacesTool.vala b/src/faces/FacesTool.vala
index 7ff3e52c..00a8b7e0 100644
--- a/src/faces/FacesTool.vala
+++ b/src/faces/FacesTool.vala
@@ -314,8 +314,7 @@ public class FacesTool : EditingTools.EditingTool {
     private class FaceDetectionJob : BackgroundJob {
         private Gee.Queue<string> faces = null;
         private string image_path;
-        //private string output;
-        public SpawnError? spawnError;
+        public string? spawnError;
 
         public FaceDetectionJob(FacesToolWindow owner, string image_path,
             CompletionCallback completion_callback, Cancellable cancellable,
@@ -326,66 +325,26 @@ public class FacesTool : EditingTools.EditingTool {
         }
 
         public override void execute() {
-            Faces.FaceRect[] rects;
-            debug("checking faces");
-            Faces.detect_faces(image_path, AppDirs.get_haarcascade_file().get_path(), 4, out rects);
-            faces = new Gee.PriorityQueue<string>();
-            string serialized = "%s;%s".printf(
-                   FaceRectangle.SHAPE_TYPE,
-                   parse_serialized_geometry("x=%s&y=%s&width=%s&height=%s".printf(
-                        rects[0].x.to_string(), rects[0].y.to_string(), rects[0].width.to_string(), 
rects[0].height.to_string())));
-            debug("saw face %s", serialized);
-            faces.add(serialized);
-
-            /* try {
-                string[] argv = {
-                    AppDirs.get_facedetect_bin().get_path(),
-                    "--cascade=" + AppDirs.get_haarcascade_file().get_path(),
-                    "--scale=1.2",
-                    image_path
-                };
-                Process.spawn_sync(null, argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out output);
-
-            } catch (SpawnError e) {
-                spawnError = e;
-                critical(e.message);
-
+            if (!FaceDetect.connected) {
+                spawnError = "Face detect process not connected!\n";
                 return;
             }
-
-            string[] lines = output.split("\n");
-            foreach (string line in lines) {
-                if (line.length == 0)
-                    continue;
-
-                string[] type_and_serialized = line.split(";");
-                if (type_and_serialized.length != 2) {
-                    critical("Wrong serialized line in face detection program output.");
-                    assert_not_reached();
-                }
-
-                switch (type_and_serialized[0]) {
-                    case "face":
-                        StringBuilder serialized_geometry = new StringBuilder();
-                        serialized_geometry.append(FaceRectangle.SHAPE_TYPE);
-                        serialized_geometry.append(";");
-                        serialized_geometry.append(parse_serialized_geometry(type_and_serialized[1]));
-
-                        faces.add(serialized_geometry.str);
-                        break;
-
-                    case "warning":
-                        warning("%s\n", type_and_serialized[1]);
-                        break;
-
-                    case "error":
-                        critical("%s\n", type_and_serialized[1]);
-                        assert_not_reached();
-
-                    default:
-                        assert_not_reached();
-                }
-            } */
+            FaceRect[] rects;
+            try {
+                rects = FaceDetect.interface.detect_faces(image_path, 
AppDirs.get_haarcascade_file().get_path(), 1.3);
+            } catch(Error e) {
+                spawnError = "DBus error: " + e.message + "!\n";
+                return;
+            }
+            faces = new Gee.PriorityQueue<string>();
+            for (int i = 0; i < rects.length; i++) {
+                string serialized = "%s;%s".printf(
+                       FaceRectangle.SHAPE_TYPE,
+                       parse_serialized_geometry("x=%s&y=%s&width=%s&height=%s".printf(
+                            rects[i].x.to_string(), rects[i].y.to_string(), rects[i].width.to_string(), 
rects[i].height.to_string())));
+                debug("saw face %s", serialized);
+                faces.add(serialized);
+            }
         }
 
         private string parse_serialized_geometry(string serialized_geometry) {
@@ -963,7 +922,7 @@ public class FacesTool : EditingTools.EditingTool {
         
         if (face_detection.spawnError != null){
             string spawnErrorMessage = _("Error trying to spawn face detection program:\n");
-            AppWindow.error_message(spawnErrorMessage + face_detection.spawnError.message + "\n");
+            AppWindow.error_message(spawnErrorMessage + face_detection.spawnError + "\n");
             faces_tool_window.set_editing_phase(EditingPhase.DETECTING_FACES_FINISHED);
         } else
             pick_faces_from_autodetected();
diff --git a/src/faces_opencv/faces_opencv.cpp b/src/faces_opencv/faces_opencv.cpp
index dc04c1d3..b67fddb5 100644
--- a/src/faces_opencv/faces_opencv.cpp
+++ b/src/faces_opencv/faces_opencv.cpp
@@ -22,10 +22,12 @@ using namespace cv;
 
 // OpenCV calls in C++
 vector<FaceRect> ocvDetectFaces(Mat &img, CascadeClassifier &cascade, double scale) {
-  Mat gray;
-  cvtColor(img, gray, CV_BGR2GRAY);
+  UMat gray, uimg;
 
-  Mat smallImg(cvRound(img.rows / scale), cvRound(img.cols / scale), CV_8UC1);
+  img.copyTo(uimg);
+  cvtColor(uimg, gray, CV_BGR2GRAY);
+
+  UMat smallImg(cvRound(uimg.rows / scale), cvRound(uimg.cols / scale), CV_8UC1);
   Size smallImgSize = smallImg.size();
 
   resize(gray, smallImg, smallImgSize, 0, 0, INTER_LINEAR);
diff --git a/src/meson.build b/src/meson.build
index b537438e..ce0788f0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -27,18 +27,16 @@ face_sources = []
 face_obj = ''
 
 if get_option('face-detection')
-  subdir('faces_opencv')
   face_sources = (['faces/FacesBranch.vala',
                      'faces/FaceLocation.vala',
                      'faces/FacePage.vala',
                      'faces/FaceShape.vala',
                      'faces/Faces.vala',
                      'faces/Face.vala',
+                     'faces/FaceDetect.vala',
                      'db/FaceLocationTable.vala',
                      'db/FaceTable.vala',
                      'faces/FacesTool.vala'])
-   shotwell_deps += [faces_dep]
-   shotwell_libs += [faces_lib]
 endif
 
 if unity_available


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]