[shotwell/wip/phako/enhanced-faces: 38/136] Restructuring face-to-vec process to happen with face-detection
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shotwell/wip/phako/enhanced-faces: 38/136] Restructuring face-to-vec process to happen with face-detection
- Date: Thu, 11 Oct 2018 09:56:25 +0000 (UTC)
commit 97da43c65e79b22d568b02d397dd05eacd6cf94f
Author: NarendraMA <narendra_m_a yahoo com>
Date: Sun Jul 22 19:27:10 2018 +0530
Restructuring face-to-vec process to happen with face-detection
facedetect/facedetect-opencv.cpp | 37 +++++++++++++++++---------
facedetect/org.gnome.ShotwellFaces1.xml | 3 ++-
facedetect/shotwell-facedetect.cpp | 22 +++++++++++-----
facedetect/shotwell-facedetect.hpp | 4 ++-
src/AppDirs.vala | 6 +++++
src/AppWindow.vala | 2 +-
src/Commands.vala | 20 ++++++++++++++
src/Resources.vala | 12 +++++++++
src/db/Db.vala | 17 +++++++-----
src/db/FaceLocationTable.vala | 46 +++++++--------------------------
src/db/FaceTable.vala | 15 +++++++++++
src/faces/Face.vala | 10 +++++++
src/faces/FaceDetect.vala | 5 ++--
src/faces/FaceLocation.vala | 10 ++++---
src/faces/FacePage.vala | 14 ++++++++++
src/faces/FacesTool.vala | 13 ++++------
16 files changed, 159 insertions(+), 77 deletions(-)
---
diff --git a/facedetect/facedetect-opencv.cpp b/facedetect/facedetect-opencv.cpp
index 9bf151c0..203c487a 100644
--- a/facedetect/facedetect-opencv.cpp
+++ b/facedetect/facedetect-opencv.cpp
@@ -1,7 +1,7 @@
#include "shotwell-facedetect.hpp"
// Detect faces in a photo
-std::vector<FaceRect> detectFaces(cv::String inputName, cv::String cascadeName, double scale) {
+std::vector<FaceRect> detectFaces(cv::String inputName, cv::String cascadeName, double scale, bool infer =
false) {
cv::CascadeClassifier cascade;
if (!cascade.load(cascadeName)) {
std::cout << "error;Could not load classifier cascade. Filename: \"" << cascadeName << "\"" <<
std::endl;
@@ -35,6 +35,14 @@ std::vector<FaceRect> detectFaces(cv::String inputName, cv::String cascadeName,
i.y = (float) r->y / smallImgSize.height;
i.width = (float) r->width / smallImgSize.width;
i.height = (float) r->height / smallImgSize.height;
+ if (infer && !faceRecogNet.empty()) {
+ // Get colour image for vector generation
+ cv::Mat colourImg;
+ cv::resize(img, colourImg, smallImgSize, 0, 0, cv::INTER_LINEAR);
+ i.vec = faceToVecMat(colourImg(*r)); // Run vector conversion on the face
+ } else {
+ i.vec.assign(128, 0);
+ }
scaled.push_back(i);
}
@@ -61,27 +69,32 @@ bool loadNet(cv::String netFile) {
// Face to vector convertor
// Adapted from OpenCV example:
// https://github.com/opencv/opencv/blob/master/samples/dnn/js_face_recognition.html
-std::vector<double> faceToVec(cv::String inputName) {
+std::vector<double> faceToVecMat(cv::Mat img) {
std::vector<double> ret;
- cv::Mat img = imread(inputName, 1);
- if (img.empty()) {
- std::cout << "error;Could not load the file to process. Filename: \"" << inputName << "\"" <<
std::endl;
- return ret;
- }
-
cv::Mat smallImg(96, 96, CV_8UC1);
cv::Size smallImgSize = smallImg.size();
- cv::resize(img, smallImg, smallImgSize, 0, 0, cv::INTER_LINEAR);
+ cv::resize(img, smallImg, smallImgSize, 0, 0, cv::INTER_LINEAR);
// Generate 128 element face vector using DNN
cv::Mat blob = cv::dnn::blobFromImage(smallImg, 1.0 / 255, smallImgSize,
cv::Scalar(), true, false);
faceRecogNet.setInput(blob);
- std::cout << "Starting recognition on " << inputName << " blob height " <<
- blob.size().height << " width " << blob.size().width << std::endl;
cv::Mat vec = faceRecogNet.forward();
- std::cout << "Recognition done!" << std::endl;
// Return vector
ret.assign((double*)vec.datastart, (double*)vec.dataend);
+ std::cout << "Recognition done! " << ret.back() << std::endl;
+ return ret;
+}
+
+std::vector<double> faceToVec(cv::String inputName) {
+ std::vector<double> ret;
+ cv::Mat img = imread(inputName, 1);
+ if (img.empty()) {
+ std::cout << "error;Could not load the file to process. Filename: \"" << inputName << "\"" <<
std::endl;
+ ret.assign(128, 0);
+ return ret;
+ }
+ ret = faceToVecMat(img);
return ret;
}
+
diff --git a/facedetect/org.gnome.ShotwellFaces1.xml b/facedetect/org.gnome.ShotwellFaces1.xml
index 26bb321b..6bc84f19 100644
--- a/facedetect/org.gnome.ShotwellFaces1.xml
+++ b/facedetect/org.gnome.ShotwellFaces1.xml
@@ -18,7 +18,8 @@
<arg type="s" name="image" direction="in" />
<arg type="s" name="cascade" direction="in" />
<arg type="d" name="scale" direction="in" />
- <arg type="a(dddd)" name="faces" direction="out" />
+ <arg type="b" name="infer" direction="in" />
+ <arg type="a(ddddad)" name="faces" direction="out" />
</method>
<!--
diff --git a/facedetect/shotwell-facedetect.cpp b/facedetect/shotwell-facedetect.cpp
index 8061a844..d6d46d36 100644
--- a/facedetect/shotwell-facedetect.cpp
+++ b/facedetect/shotwell-facedetect.cpp
@@ -16,19 +16,27 @@ static gboolean on_handle_detect_faces(ShotwellFaces1 *object,
GDBusMethodInvocation *invocation,
const gchar *arg_image,
const gchar *arg_cascade,
- gdouble arg_scale) {
+ gdouble arg_scale,
+ gboolean arg_infer) {
GVariantBuilder *builder;
GVariant *faces;
std::vector<FaceRect> rects =
- detectFaces(arg_image, arg_cascade, arg_scale);
+ detectFaces(arg_image, arg_cascade, arg_scale, arg_infer);
// Construct return value
- builder = g_variant_builder_new(G_VARIANT_TYPE ("a(dddd)"));
+ builder = g_variant_builder_new(G_VARIANT_TYPE ("a(ddddad)"));
for (std::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);
+ GVariantBuilder *arr_builder = g_variant_builder_new(G_VARIANT_TYPE ("ad"));
+ for (std::vector<double>::const_iterator v = r->vec.begin(); v != r->vec.end(); v++) {
+ GVariant *d = g_variant_new("d", *v);
+ g_variant_builder_add(arr_builder, "d", d);
+ }
+ GVariant *vec = g_variant_new("ad", arr_builder);
+ g_variant_builder_unref(arr_builder);
+ GVariant *rect = g_variant_new("(dddd@ad)", r->x, r->y, r->width, r->height, vec);
+ g_variant_builder_add(builder, "@(ddddad)", rect);
+ g_debug("Returning %f,%f-%f", r->x, r->y, r->vec.back());
}
- faces = g_variant_new("a(dddd)", builder);
+ faces = g_variant_new("a(ddddad)", builder);
g_variant_builder_unref (builder);
// Call return
shotwell_faces1_complete_detect_faces(object, invocation,
diff --git a/facedetect/shotwell-facedetect.hpp b/facedetect/shotwell-facedetect.hpp
index 0fdff2b7..d8413952 100644
--- a/facedetect/shotwell-facedetect.hpp
+++ b/facedetect/shotwell-facedetect.hpp
@@ -18,11 +18,13 @@
typedef struct {
float x, y, width, height;
+ std::vector<double> vec;
} FaceRect;
// Global variable for DNN to generate vector out of face
static cv::dnn::Net faceRecogNet;
bool loadNet(cv::String netFile);
-std::vector<FaceRect> detectFaces(cv::String inputName, cv::String cascadeName, double scale);
+std::vector<FaceRect> detectFaces(cv::String inputName, cv::String cascadeName, double scale, bool infer);
+std::vector<double> faceToVecMat(cv::Mat img);
std::vector<double> faceToVec(cv::String inputName);
diff --git a/src/AppDirs.vala b/src/AppDirs.vala
index 331a3f30..e2a5065a 100644
--- a/src/AppDirs.vala
+++ b/src/AppDirs.vala
@@ -210,6 +210,12 @@ class AppDirs {
return tmp_dir;
}
+
+ public static string get_temp_filename() {
+ string tmp_dir = get_temp_dir().get_path();
+ assert(tmp_dir != null);
+ return Path.build_filename(tmp_dir, "face_XXXXXX.png");
+ }
public static File get_data_subdir(string name, string? subname = null) {
File subdir = get_data_dir().get_child(name);
diff --git a/src/AppWindow.vala b/src/AppWindow.vala
index b746ebbd..fd831569 100644
--- a/src/AppWindow.vala
+++ b/src/AppWindow.vala
@@ -578,7 +578,7 @@ public abstract class AppWindow : PageWindow {
panic(_("A fatal error occurred when accessing Shotwell’s library. Shotwell cannot
continue.\n\n%s").printf(
err.message));
}
-
+
public static void panic(string msg) {
critical(msg);
error_message(msg);
diff --git a/src/Commands.vala b/src/Commands.vala
index a0d3766c..014f11dd 100644
--- a/src/Commands.vala
+++ b/src/Commands.vala
@@ -2574,6 +2574,26 @@ public class RenameFaceCommand : SimpleProxyableCommand {
}
}
+public class SetFaceRefCommand : SimpleProxyableCommand {
+ private FaceLocation face_loc;
+
+ public SetFaceRefCommand(Face face, MediaSource source) {
+ base (face, Resources.set_face_from_photo_label(face.get_name()), face.get_name());
+ Gee.Map<FaceID?, FaceLocation>? face_loc_map = FaceLocation.get_locations_by_photo((Photo)source);
+ face_loc = face_loc_map.get(face.get_face_id());
+ }
+
+ protected override void execute_on_source(DataSource source) {
+ if (!((Face) source).set_reference(face_loc))
+ AppWindow.error_message(Resources.set_face_from_photo_error());
+ }
+
+ protected override void undo_on_source(DataSource source) {
+ //if (!((Face) source).rename(old_name))
+ // AppWindow.error_message(Resources.rename_face_exists_message(old_name));
+ }
+}
+
public class DeleteFaceCommand : SimpleProxyableCommand {
private Gee.Map<PhotoID?, string> photo_geometry_map = new Gee.HashMap<PhotoID?, string>
((Gee.HashDataFunc)FaceLocation.photo_id_hash, (Gee.EqualDataFunc)FaceLocation.photo_ids_equal);
diff --git a/src/Resources.vala b/src/Resources.vala
index ff364132..8332f4c5 100644
--- a/src/Resources.vala
+++ b/src/Resources.vala
@@ -417,6 +417,18 @@ along with Shotwell; if not, write to the Free Software Foundation, Inc.,
return ngettext ("Remove Face “%s” From Photo",
"Remove Face “%s” From Photos", count).printf(name);
}
+
+ public string set_face_from_photo_menu(string name) {
+ return _("_Train Face “%s” From Photo").printf(name);
+ }
+
+ public string set_face_from_photo_label(string name) {
+ return _("_Train Face “%s” From Photo").printf(name);
+ }
+
+ public static string set_face_from_photo_error() {
+ return "Unable to set face as reference";
+ }
public string rename_face_menu(string name) {
return _("Re_name Face “%s”…").printf(name);
diff --git a/src/db/Db.vala b/src/db/Db.vala
index 6facbbc3..ac24f113 100644
--- a/src/db/Db.vala
+++ b/src/db/Db.vala
@@ -357,14 +357,19 @@ private VerifyResult upgrade_database(int input_version) {
// * Added face vector column to FaceTable
//
- if (!DatabaseTable.has_column("FaceLocationTable", "pix")) {
- message("upgrade_database: adding pix column to FaceLocationTable");
- if (!DatabaseTable.add_column("FaceLocationTable", "pix", "BLOB"))
+ if (!DatabaseTable.has_column("FaceLocationTable", "vec")) {
+ message("upgrade_database: adding vec column to FaceLocationTable");
+ if (!DatabaseTable.add_column("FaceLocationTable", "vec", "TEXT"))
return VerifyResult.UPGRADE_ERROR;
}
- if (!DatabaseTable.has_column("FaceTable", "vec")) {
- message("upgrade_database: adding vec column to FaceTable");
- if (!DatabaseTable.add_column("FaceTable", "vec", "TEXT"))
+ if (!DatabaseTable.has_column("FaceLocationTable", "guess")) {
+ message("upgrade_database: adding guess column to FaceLocationTable");
+ if (!DatabaseTable.add_column("FaceLocationTable", "guess", "INTEGER DEFAULT 0"))
+ return VerifyResult.UPGRADE_ERROR;
+ }
+ if (!DatabaseTable.has_column("FaceTable", "ref")) {
+ message("upgrade_database: adding ref column to FaceTable");
+ if (!DatabaseTable.add_column("FaceTable", "ref", "INTEGER DEFAULT -1"))
return VerifyResult.UPGRADE_ERROR;
}
diff --git a/src/db/FaceLocationTable.vala b/src/db/FaceLocationTable.vala
index f8132615..219928d9 100644
--- a/src/db/FaceLocationTable.vala
+++ b/src/db/FaceLocationTable.vala
@@ -29,7 +29,7 @@ public class FaceLocationRow {
public FaceID face_id;
public PhotoID photo_id;
public string geometry;
- public uint8[] pix;
+ public string vec;
}
public class FaceLocationTable : DatabaseTable {
@@ -46,7 +46,7 @@ public class FaceLocationTable : DatabaseTable {
+ "face_id INTEGER NOT NULL, "
+ "photo_id INTEGER NOT NULL, "
+ "geometry TEXT, "
- + "pix BLOB"
+ + "vec TEXT"
+ ")", -1, out stmt);
assert(res == Sqlite.OK);
@@ -62,10 +62,10 @@ public class FaceLocationTable : DatabaseTable {
return instance;
}
- public FaceLocationRow add(FaceID face_id, PhotoID photo_id, string geometry, uint8[]? pix = null)
throws DatabaseError {
+ public FaceLocationRow add(FaceID face_id, PhotoID photo_id, string geometry, string? vec = null) throws
DatabaseError {
Sqlite.Statement stmt;
int res = db.prepare_v2(
- "INSERT INTO FaceLocationTable (face_id, photo_id, geometry, pix) VALUES (?, ?, ?, ?)",
+ "INSERT INTO FaceLocationTable (face_id, photo_id, geometry, vec) VALUES (?, ?, ?, ?)",
-1, out stmt);
assert(res == Sqlite.OK);
@@ -75,12 +75,7 @@ public class FaceLocationTable : DatabaseTable {
assert(res == Sqlite.OK);
res = stmt.bind_text(3, geometry);
assert(res == Sqlite.OK);
- message("face table pix len %d", pix.length);
- if (pix == null) {
- res = stmt.bind_blob(4, null, 0);
- } else {
- res = stmt.bind_blob(4, pix, pix.length);
- }
+ res = stmt.bind_text(4, vec);
assert(res == Sqlite.OK);
res = stmt.step();
@@ -92,7 +87,7 @@ public class FaceLocationTable : DatabaseTable {
row.face_id = face_id;
row.photo_id = photo_id;
row.geometry = geometry;
- row.pix = pix;
+ row.vec = vec;
return row;
}
@@ -100,7 +95,7 @@ public class FaceLocationTable : DatabaseTable {
public Gee.List<FaceLocationRow?> get_all_rows() throws DatabaseError {
Sqlite.Statement stmt;
int res = db.prepare_v2(
- "SELECT id, face_id, photo_id, geometry FROM FaceLocationTable",
+ "SELECT id, face_id, photo_id, geometry, vec FROM FaceLocationTable",
-1, out stmt);
assert(res == Sqlite.OK);
@@ -119,6 +114,7 @@ public class FaceLocationTable : DatabaseTable {
row.face_id = FaceID(stmt.column_int64(1));
row.photo_id = PhotoID(stmt.column_int64(2));
row.geometry = stmt.column_text(3);
+ row.vec = stmt.column_text(4);
rows.add(row);
}
@@ -175,28 +171,6 @@ public class FaceLocationTable : DatabaseTable {
return stmt.column_text(0);
}
- public uint8[]? get_face_source_pix(Face face, MediaSource source)
- throws DatabaseError {
- Sqlite.Statement stmt;
- int res = db.prepare_v2(
- "SELECT pix FROM FaceLocationTable WHERE face_id=? AND photo_id=?",
- -1, out stmt);
- assert(res == Sqlite.OK);
-
- res = stmt.bind_int64(1, face.get_instance_id());
- assert(res == Sqlite.OK);
- res = stmt.bind_int64(2, ((Photo) source).get_instance_id());
- assert(res == Sqlite.OK);
-
- res = stmt.step();
- if (res == Sqlite.DONE)
- return null;
- else if (res != Sqlite.ROW)
- throw_error("FaceLocationTable.get_face_source_pix", res);
-
- return (uint8[])stmt.column_blob(0);
- }
-
public void remove_face_from_source(FaceID face_id, PhotoID photo_id) throws DatabaseError {
Sqlite.Statement stmt;
int res = db.prepare_v2(
@@ -233,13 +207,13 @@ public class FaceLocationTable : DatabaseTable {
public void update_face_location_face_data(FaceLocation face_location)
throws DatabaseError {
Sqlite.Statement stmt;
- int res = db.prepare_v2("UPDATE FaceLocationTable SET geometry=?, pix=? WHERE id=?", -1, out stmt);
+ int res = db.prepare_v2("UPDATE FaceLocationTable SET geometry=?, vec=? WHERE id=?", -1, out stmt);
assert(res == Sqlite.OK);
FaceLocationData face_data = face_location.get_face_data();
res = stmt.bind_text(1, face_data.geometry);
assert(res == Sqlite.OK);
- res = stmt.bind_blob(2, face_data.pixbuf, face_data.pixbuf.length);
+ res = stmt.bind_text(2, face_data.vec);
assert(res == Sqlite.OK);
res = stmt.bind_int64(3, face_location.get_face_location_id().id);
assert(res == Sqlite.OK);
diff --git a/src/db/FaceTable.vala b/src/db/FaceTable.vala
index a6e0bad6..c8e934cd 100644
--- a/src/db/FaceTable.vala
+++ b/src/db/FaceTable.vala
@@ -165,5 +165,20 @@ public class FaceTable : DatabaseTable {
public void rename(FaceID face_id, string new_name) throws DatabaseError {
update_text_by_id_2(face_id.id, "name", new_name);
}
+
+ public void set_reference(FaceID face_id, PhotoID photo_id)
+ throws DatabaseError {
+ Sqlite.Statement stmt;
+ int res = db.prepare_v2("UPDATE FaceTable SET ref=? WHERE id=?", -1, out stmt);
+ assert(res == Sqlite.OK);
+ res = stmt.bind_int64(1, photo_id.id);
+ assert(res == Sqlite.OK);
+ res = stmt.bind_int64(2, face_id.id);
+ assert(res == Sqlite.OK);
+
+ res = stmt.step();
+ if (res != Sqlite.DONE)
+ throw_error("FaceTable.set_reference", res);
+ }
}
#endif
diff --git a/src/faces/Face.vala b/src/faces/Face.vala
index 66968c58..1c180b25 100644
--- a/src/faces/Face.vala
+++ b/src/faces/Face.vala
@@ -592,6 +592,16 @@ public class Face : DataSource, ContainerSource, Proxyable, Indexable {
return true;
}
+
+ public bool set_reference(FaceLocation face_loc) {
+ try {
+ FaceTable.get_instance().set_reference(row.face_id, face_loc.get_photo_id());
+ } catch (DatabaseError err) {
+ AppWindow.database_error(err);
+ return false;
+ }
+ return true;
+ }
public bool contains(MediaSource source) {
return media_views.has_view_for_source(source);
diff --git a/src/faces/FaceDetect.vala b/src/faces/FaceDetect.vala
index 25086069..7a027b48 100644
--- a/src/faces/FaceDetect.vala
+++ b/src/faces/FaceDetect.vala
@@ -29,15 +29,16 @@ public struct FaceRect {
public double y;
public double width;
public double height;
+ public double[] vec;
}
[DBus (name = "org.gnome.Shotwell.Faces1")]
public interface FaceDetectInterface : Object {
- public abstract FaceRect[] detect_faces(string inputName, string cascadeName, double scale)
+ public abstract FaceRect[] detect_faces(string inputName, string cascadeName, double scale, bool infer)
throws IOError, DBusError;
public abstract bool load_net(string netFile)
throws IOError, DBusError;
- public abstract bool face_to_vec(string inputName)
+ public abstract double[] face_to_vec(string inputName)
throws IOError, DBusError;
public abstract void terminate() throws IOError, DBusError;
}
diff --git a/src/faces/FaceLocation.vala b/src/faces/FaceLocation.vala
index fce8e99e..c7e2c6c2 100644
--- a/src/faces/FaceLocation.vala
+++ b/src/faces/FaceLocation.vala
@@ -9,7 +9,7 @@
// Encapsulate geometry and pixels of a Face
public struct FaceLocationData {
public string geometry;
- public uint8[] pixbuf;
+ public string vec;
}
public class FaceLocation : Object {
@@ -58,7 +58,7 @@ public class FaceLocation : Object {
try {
face_location =
FaceLocation.add_from_row(
- FaceLocationTable.get_instance().add(face_id, photo_id, face_data.geometry,
face_data.pixbuf));
+ FaceLocationTable.get_instance().add(face_id, photo_id, face_data.geometry,
face_data.vec));
} catch (DatabaseError err) {
AppWindow.database_error(err);
}
@@ -92,7 +92,7 @@ public class FaceLocation : Object {
FaceLocation face_location =
new FaceLocation(row.face_location_id, row.face_id, row.photo_id,
- { row.geometry, row.pix });
+ { row.geometry, row.vec });
Gee.Map<PhotoID?, FaceLocation> photos_map = face_photos_map.get(row.face_id);
if (photos_map == null) {photos_map = new Gee.HashMap<PhotoID?, FaceLocation>
@@ -214,6 +214,10 @@ public class FaceLocation : Object {
public FaceLocationData get_face_data() {
return face_data;
}
+
+ public PhotoID get_photo_id() {
+ return photo_id;
+ }
private void set_face_data(FaceLocationData face_data) {
this.face_data = face_data;
diff --git a/src/faces/FacePage.vala b/src/faces/FacePage.vala
index 41d1cef1..d9b60640 100644
--- a/src/faces/FacePage.vala
+++ b/src/faces/FacePage.vala
@@ -46,6 +46,7 @@ public class FacePage : CollectionPage {
{ "DeleteFace", on_delete_face },
{ "RenameFace", on_rename_face },
{ "RemoveFaceFromPhotos", on_remove_face_from_photos },
+ { "SetFaceRefFromPhoto", on_set_face_ref },
{ "DeleteFaceSidebar", on_delete_face },
{ "RenameFaceSidebar", on_rename_face }
};
@@ -76,6 +77,7 @@ public class FacePage : CollectionPage {
menuFaces.add_menu_item(Resources.remove_face_from_photos_menu(this.face.get_name(),
get_view().get_count()), "RemoveFaceFromPhotos", "<Primary>r");
menuFaces.add_menu_item(Resources.rename_face_menu(this.face.get_name()), "RenameFace",
"<Primary>e");
+ menuFaces.add_menu_item(Resources.set_face_from_photo_menu(this.face.get_name()),
"SetFaceRefFromPhoto", "<Primary>r");
menuFaces.add_menu_item(Resources.delete_face_menu(this.face.get_name()), "DeleteFace",
"<Primary>t");
return menuFaces;
@@ -104,6 +106,11 @@ public class FacePage : CollectionPage {
null,
selected_count > 0);
+ set_action_details("SetFaceRefFromPhoto",
+ Resources.set_face_from_photo_menu(face.get_name()),
+ null,
+ selected_count == 1);
+
base.update_actions(selected_count, count);
}
@@ -122,6 +129,13 @@ public class FacePage : CollectionPage {
(Gee.Collection<MediaSource>) get_view().get_selected_sources()));
}
}
+
+ private void on_set_face_ref() {
+ if (get_view().get_selected_count() == 1) {
+ get_command_manager().execute(new SetFaceRefCommand(face,
+ (MediaSource) get_view().get_selected_at(0).get_source()));
+ }
+ }
}
#endif
diff --git a/src/faces/FacesTool.vala b/src/faces/FacesTool.vala
index 2c5faf6a..65c532ab 100644
--- a/src/faces/FacesTool.vala
+++ b/src/faces/FacesTool.vala
@@ -334,7 +334,7 @@ public class FacesTool : EditingTools.EditingTool {
FaceRect[] rects;
try {
rects = FaceDetect.interface.detect_faces(image_path,
- AppDirs.get_haarcascade_file().get_path(), scale);
+ AppDirs.get_haarcascade_file().get_path(), scale,
true);
} catch(Error e) {
spawnError = "DBus error: " + e.message + "!\n";
return;
@@ -763,15 +763,12 @@ public class FacesTool : EditingTools.EditingTool {
continue;
Face new_face = Face.for_name(face_shape.get_name());
- uint8[] face_pix;
- try {
- face_shape.get_pixbuf().save_to_buffer(out face_pix, "png");
- message("face pix length %d", face_pix.length);
- } catch (Error e) {
- AppWindow.error_message("Cannot get pixbuf for image\n");
+ string face_vec_str = "";
+ if (face_vec != null) {
+ foreach (var d in face_vec) { face_vec_str += d.to_string() + ","; }
}
FaceLocationData face_data = {
- face_shape.serialize(), face_pix
+ face_shape.serialize(), face_vec_str
};
new_faces.set(new_face, face_data);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]