Skip to content

Commit a962582

Browse files
committed
try orientation with exif
1 parent 1d2d322 commit a962582

File tree

4 files changed

+176
-54
lines changed

4 files changed

+176
-54
lines changed

visionSamples/FaceTracker/app/src/main/cpp/native-lib.cpp

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -325,51 +325,48 @@ Java_dlib_android_FaceRecognizer_recognizeFace(JNIEnv *env, jobject instance, jo
325325
}
326326

327327
//todo: smth wrong with colors
328-
//dlib::save_bmp(img, "/storage/emulated/0/Download/test.bmp");
329-
330-
std::vector<dlib::rectangle> dets = detector(img);
331-
LOGI("detected size %d", dets.size());
332-
333-
float min_dist = 0.0;
334-
if(dets.size() > 0 ){
335-
auto face = dets.front();
336-
std::vector<matrix<rgb_pixel>> faces;
337-
int x = face.left();
338-
int y = face.top();
339-
int width = face.width();
340-
int height = face.height();
341-
342-
auto shape = sp(img, face);
343-
matrix<rgb_pixel> face_chip;
344-
extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
345-
faces.push_back(move(face_chip));
346-
347-
std::vector<matrix<float, 0, 1>> face_descriptors = net(faces);
348-
349-
if (face_descriptors.size() > 0)
350-
{
351-
matrix<float, 0, 1> face_desc = face_descriptors[0];
352-
for (auto& i : known_faces) {
353-
float dist = length(face_desc - i.second );
354-
if (dist < min_dist){
355-
min_dist = dist;
356-
}
357-
if( dist < FACE_RECOGNIZE_THRESH) //todo: extract thresh
358-
{
359-
LOGI("recognized");
360-
return env->NewStringUTF(i.first.c_str());
361-
}
362-
}
363-
}
364-
LOGI("not recognized, max dist %0.2f", min_dist);
365-
}
366-
328+
dlib::save_bmp(img, "/sdcard/Download/res.bmp");
329+
330+
// std::vector<dlib::rectangle> dets = detector(img);
331+
// LOGI("detected size %d", dets.size());
332+
//
333+
// float min_dist = 0.0;
334+
// if(dets.size() > 0 ){
335+
// auto face = dets.front();
336+
// std::vector<matrix<rgb_pixel>> faces;
337+
// int x = face.left();
338+
// int y = face.top();
339+
// int width = face.width();
340+
// int height = face.height();
341+
//
342+
// auto shape = sp(img, face);
343+
// matrix<rgb_pixel> face_chip;
344+
// extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
345+
// faces.push_back(move(face_chip));
346+
//
347+
// std::vector<matrix<float, 0, 1>> face_descriptors = net(faces);
348+
//
349+
// if (face_descriptors.size() > 0)
350+
// {
351+
// matrix<float, 0, 1> face_desc = face_descriptors[0];
352+
// for (auto& i : known_faces) {
353+
// float dist = length(face_desc - i.second );
354+
// if (dist < min_dist){
355+
// min_dist = dist;
356+
// }
357+
// if( dist < FACE_RECOGNIZE_THRESH) //todo: extract thresh
358+
// {
359+
// LOGI("recognized");
360+
// return env->NewStringUTF(i.first.c_str());
361+
// }
362+
// }
363+
// }
364+
// LOGI("not recognized, max dist %0.2f", min_dist);
365+
// }
366+
//
367367
LOGI("unlocking pixels");
368368
AndroidBitmap_unlockPixels(env, bmp);
369369

370-
//std::string returnValue = "Unknown" + std::to_string(min_dist);
371-
372-
373370
std::string returnValue = "Unknown";
374371
return env->NewStringUTF(returnValue.c_str());
375372
}

visionSamples/FaceTracker/app/src/main/java/com/google/android/gms/samples/vision/face/facetracker/CustomDetector.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.FileWriter;
2020
import java.io.IOException;
2121

22+
import dlib.android.Exif;
2223
import dlib.android.FaceRecognizer;
2324

2425
import static android.os.Environment.getExternalStorageDirectory;
@@ -83,6 +84,8 @@ public SparseArray<Face> detect(Frame frame) {
8384
yuvImage.compressToJpeg(new Rect(0, 0, frame.getMetadata().getWidth(),
8485
frame.getMetadata().getHeight()), 100, byteArrayOutputStream);
8586
byte[] jpegArray = byteArrayOutputStream.toByteArray();
87+
int orientation = Exif.getOrientation(jpegArray);
88+
Log.w(TAG, String.format("Orientation %d", orientation));
8689
Bitmap tmpBitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
8790
final Bitmap cropped = Bitmap.createBitmap(tmpBitmap, x, y, w, h);
8891
// try {

visionSamples/FaceTracker/app/src/main/java/com/google/android/gms/samples/vision/face/facetracker/FaceTrackerActivity.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public final class FaceTrackerActivity extends AppCompatActivity {
6262
private GraphicOverlay mGraphicOverlay;
6363
private Button mBtnDetect;
6464
private CustomDetector customDetector;
65-
private FaceDetector mPictureDetector;
65+
//private FaceDetector mPictureDetector;
6666

6767
private static final int RC_HANDLE_GMS = 9001;
6868
// permission request codes need to be < 256
@@ -185,16 +185,16 @@ private void createCameraSource() {
185185
.setClassificationType(FaceDetector.NO_CLASSIFICATIONS)
186186
.setProminentFaceOnly(false)
187187
.setMode(FaceDetector.ACCURATE_MODE)
188-
.setMinFaceSize(0.05f)
188+
.setMinFaceSize(0.015f)
189189
.build();
190190

191-
mPictureDetector = new FaceDetector.Builder(context)
192-
.setTrackingEnabled(false)
193-
.setProminentFaceOnly(false)
194-
.setMinFaceSize(0.015f) // 80 / 5312 detect up to 80 pixels head width
195-
.setMode(FaceDetector.ACCURATE_MODE)
196-
.setClassificationType(FaceDetector.NO_CLASSIFICATIONS)
197-
.build();
191+
// mPictureDetector = new FaceDetector.Builder(context)
192+
// .setTrackingEnabled(false)
193+
// .setProminentFaceOnly(false)
194+
// .setMinFaceSize(0.015f) // 80 / 5312 detect up to 80 pixels head width
195+
// .setMode(FaceDetector.ACCURATE_MODE)
196+
// .setClassificationType(FaceDetector.NO_CLASSIFICATIONS)
197+
// .build();
198198

199199
//mFaceRecognizer
200200
customDetector = new CustomDetector(detector, mFaceRecognizer);
@@ -215,9 +215,9 @@ private void createCameraSource() {
215215
Log.w(TAG, "Face detector dependencies are not yet available.");
216216
}
217217

218-
if (!mPictureDetector.isOperational()) {
219-
Log.w(TAG, "mPictureDetector dependencies are not yet available.");
220-
}
218+
// if (!mPictureDetector.isOperational()) {
219+
// Log.w(TAG, "mPictureDetector dependencies are not yet available.");
220+
// }
221221

222222
//.setRequestedPreviewSize(640, 480)
223223
//.setRequestedFps(30.0f)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package dlib.android;
2+
3+
import android.util.Log;
4+
5+
//https://github.com/googlesamples/android-vision/issues/124
6+
public class Exif {
7+
private static final String TAG = "CameraExif";
8+
9+
// Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
10+
public static int getOrientation(byte[] jpeg) {
11+
if (jpeg == null) {
12+
return 0;
13+
}
14+
15+
int offset = 0;
16+
int length = 0;
17+
18+
// ISO/IEC 10918-1:1993(E)
19+
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
20+
int marker = jpeg[offset] & 0xFF;
21+
22+
// Check if the marker is a padding.
23+
if (marker == 0xFF) {
24+
continue;
25+
}
26+
offset++;
27+
28+
// Check if the marker is SOI or TEM.
29+
if (marker == 0xD8 || marker == 0x01) {
30+
continue;
31+
}
32+
// Check if the marker is EOI or SOS.
33+
if (marker == 0xD9 || marker == 0xDA) {
34+
break;
35+
}
36+
37+
// Get the length and check if it is reasonable.
38+
length = pack(jpeg, offset, 2, false);
39+
if (length < 2 || offset + length > jpeg.length) {
40+
Log.e(TAG, "Invalid length");
41+
return 0;
42+
}
43+
44+
// Break if the marker is EXIF in APP1.
45+
if (marker == 0xE1 && length >= 8 &&
46+
pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
47+
pack(jpeg, offset + 6, 2, false) == 0) {
48+
offset += 8;
49+
length -= 8;
50+
break;
51+
}
52+
53+
// Skip other markers.
54+
offset += length;
55+
length = 0;
56+
}
57+
58+
// JEITA CP-3451 Exif Version 2.2
59+
if (length > 8) {
60+
// Identify the byte order.
61+
int tag = pack(jpeg, offset, 4, false);
62+
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
63+
Log.e(TAG, "Invalid byte order");
64+
return 0;
65+
}
66+
boolean littleEndian = (tag == 0x49492A00);
67+
68+
// Get the offset and check if it is reasonable.
69+
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
70+
if (count < 10 || count > length) {
71+
Log.e(TAG, "Invalid offset");
72+
return 0;
73+
}
74+
offset += count;
75+
length -= count;
76+
77+
// Get the count and go through all the elements.
78+
count = pack(jpeg, offset - 2, 2, littleEndian);
79+
while (count-- > 0 && length >= 12) {
80+
// Get the tag and check if it is orientation.
81+
tag = pack(jpeg, offset, 2, littleEndian);
82+
if (tag == 0x0112) {
83+
// We do not really care about type and count, do we?
84+
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
85+
switch (orientation) {
86+
case 1:
87+
return 0;
88+
case 3:
89+
return 180;
90+
case 6:
91+
return 90;
92+
case 8:
93+
return 270;
94+
}
95+
Log.i(TAG, "Unsupported orientation");
96+
return 0;
97+
}
98+
offset += 12;
99+
length -= 12;
100+
}
101+
}
102+
103+
Log.i(TAG, "Orientation not found");
104+
return 0;
105+
}
106+
107+
private static int pack(byte[] bytes, int offset, int length,
108+
boolean littleEndian) {
109+
int step = 1;
110+
if (littleEndian) {
111+
offset += length - 1;
112+
step = -1;
113+
}
114+
115+
int value = 0;
116+
while (length-- > 0) {
117+
value = (value << 8) | (bytes[offset] & 0xFF);
118+
offset += step;
119+
}
120+
return value;
121+
}
122+
}

0 commit comments

Comments
 (0)