CameraITS: add face detection test
Add a new test scene for face detection.
Also fix typo in CTS face detection test.
Bug: 21616680
Change-Id: I8f6674e8402f21c3f6fae2325c84c0a575a3e025
diff --git a/apps/CameraITS/CameraITS.pdf b/apps/CameraITS/CameraITS.pdf
index 2430420..3866930 100644
--- a/apps/CameraITS/CameraITS.pdf
+++ b/apps/CameraITS/CameraITS.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/inprog/test_faces.py b/apps/CameraITS/tests/inprog/test_faces.py
deleted file mode 100644
index 228dac8..0000000
--- a/apps/CameraITS/tests/inprog/test_faces.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import its.image
-import its.device
-import its.objects
-import os.path
-
-def main():
- """Test face detection.
- """
- NAME = os.path.basename(__file__).split(".")[0]
-
- with its.device.ItsSession() as cam:
- cam.do_3a()
- req = its.objects.auto_capture_request()
- req['android.statistics.faceDetectMode'] = 2
- caps = cam.do_capture([req]*5)
- for i,cap in enumerate(caps):
- md = cap['metadata']
- print "Frame %d face metadata:" % i
- print " Ids:", md['android.statistics.faceIds']
- print " Landmarks:", md['android.statistics.faceLandmarks']
- print " Rectangles:", md['android.statistics.faceRectangles']
- print " Scores:", md['android.statistics.faceScores']
- print ""
-
-if __name__ == '__main__':
- main()
-
diff --git a/apps/CameraITS/tests/scene2/SampleTarget.jpg b/apps/CameraITS/tests/scene2/SampleTarget.jpg
new file mode 100644
index 0000000..c054f7e
--- /dev/null
+++ b/apps/CameraITS/tests/scene2/SampleTarget.jpg
Binary files differ
diff --git a/apps/CameraITS/tests/scene2/test_faces.py b/apps/CameraITS/tests/scene2/test_faces.py
new file mode 100644
index 0000000..cce74e7
--- /dev/null
+++ b/apps/CameraITS/tests/scene2/test_faces.py
@@ -0,0 +1,102 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import its.image
+import its.device
+import its.objects
+import os.path
+
+def main():
+ """Test face detection.
+ """
+ NAME = os.path.basename(__file__).split(".")[0]
+ NUM_TEST_FRAMES = 20
+ FD_MODE_OFF = 0
+ FD_MODE_SIMPLE = 1
+ FD_MODE_FULL = 2
+
+ with its.device.ItsSession() as cam:
+ props = cam.get_camera_properties()
+ fd_modes = props['android.statistics.info.availableFaceDetectModes']
+ a = props['android.sensor.info.activeArraySize']
+ aw, ah = a['right'] - a['left'], a['bottom'] - a['top']
+ cam.do_3a()
+ for fd_mode in fd_modes:
+ assert(FD_MODE_OFF <= fd_mode <= FD_MODE_FULL)
+ req = its.objects.auto_capture_request()
+ req['android.statistics.faceDetectMode'] = fd_mode
+ caps = cam.do_capture([req]*NUM_TEST_FRAMES)
+ for i,cap in enumerate(caps):
+ md = cap['metadata']
+ assert(md['android.statistics.faceDetectMode'] == fd_mode)
+ faces = md['android.statistics.faces']
+
+ # 0 faces should be returned for OFF mode
+ if fd_mode == FD_MODE_OFF:
+ assert(len(faces) == 0)
+ continue
+ # Face detection could take several frames to warm up,
+ # but it should detect at least one face in last frame
+ if i == NUM_TEST_FRAMES - 1:
+ if len(faces) == 0:
+ print "Error: no face detected in mode", fd_mode
+ assert(0)
+ if len(faces) == 0:
+ continue
+
+ print "Frame %d face metadata:" % i
+ print " Faces:", faces
+ print ""
+
+ face_scores = [face['score'] for face in faces]
+ face_rectangles = [face['bounds'] for face in faces]
+ for score in face_scores:
+ assert(score >= 1 and score <= 100)
+ # Face bounds should be within active array
+ for rect in face_rectangles:
+ assert(rect['top'] < rect['bottom'])
+ assert(rect['left'] < rect['right'])
+ assert(0 <= rect['top'] <= ah)
+ assert(0 <= rect['bottom'] <= ah)
+ assert(0 <= rect['left'] <= aw)
+ assert(0 <= rect['right'] <= aw)
+
+ # Face landmarks are reported if and only if fd_mode is FULL
+ # Face ID should be -1 for SIMPLE and unique for FULL
+ if fd_mode == FD_MODE_SIMPLE:
+ for face in faces:
+ assert('leftEye' not in face)
+ assert('rightEye' not in face)
+ assert('mouth' not in face)
+ assert(face['id'] == -1)
+ elif fd_mode == FD_MODE_FULL:
+ face_ids = [face['id'] for face in faces]
+ assert(len(face_ids) == len(set(face_ids)))
+ # Face landmarks should be within face bounds
+ for face in faces:
+ left_eye = face['leftEye']
+ right_eye = face['rightEye']
+ mouth = face['mouth']
+ l, r = face['bounds']['left'], face['bounds']['right']
+ t, b = face['bounds']['top'], face['bounds']['bottom']
+ assert(l <= left_eye['x'] <= r)
+ assert(t <= left_eye['y'] <= b)
+ assert(l <= right_eye['x'] <= r)
+ assert(t <= right_eye['y'] <= b)
+ assert(l <= mouth['x'] <= r)
+ assert(t <= mouth['y'] <= b)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 2bbd387..c065f12 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -41,12 +41,18 @@
"test_ev_compensation_advanced",
"test_ev_compensation_basic",
"test_yuv_plus_jpeg"
- ]
+ ],
+ "scene2":[]
}
# Get all the scene0 and scene1 tests, which can be run using the same
# physical setup.
- scenes = ["scene0", "scene1"]
+ scenes = ["scene0", "scene1", "scene2"]
+ scene_req = {
+ "scene0" : None,
+ "scene1" : "A grey card covering at least the middle 30% of the scene",
+ "scene2" : "A picture containing human faces"
+ }
tests = []
for d in scenes:
tests += [(d,s[:-3],os.path.join("tests", d, s))
@@ -86,14 +92,6 @@
for d in scenes:
os.mkdir(os.path.join(topdir, camera_id, d))
- out_path = os.path.join(topdir, camera_id, "scene.jpg")
- out_arg = "out=" + out_path
- cmd = ['python',
- os.path.join(os.getcwd(),"tools/validate_scene.py"),
- camera_id_arg, out_arg]
- retcode = subprocess.call(cmd,cwd=topdir)
- assert(retcode == 0)
-
print "Start running ITS on camera: ", camera_id
# Run each test, capturing stdout and stderr.
summary = "ITS test result summary for camera " + camera_id + "\n"
@@ -102,7 +100,19 @@
numnotmandatedfail = 0
numfail = 0
+ prev_scene = ""
for (scene,testname,testpath) in tests:
+ if scene != prev_scene and scene_req[scene] != None:
+ out_path = os.path.join(topdir, camera_id, scene+".jpg")
+ out_arg = "out=" + out_path
+ scene_arg = "scene=" + scene_req[scene]
+ cmd = ['python',
+ os.path.join(os.getcwd(),"tools/validate_scene.py"),
+ camera_id_arg, out_arg, scene_arg]
+ retcode = subprocess.call(cmd,cwd=topdir)
+ assert(retcode == 0)
+ print "Start running tests for", scene
+ prev_scene = scene
cmd = ['python', os.path.join(os.getcwd(),testpath)] + \
sys.argv[1:] + [camera_id_arg]
outdir = os.path.join(topdir,camera_id,scene)
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index ea851b7..1f35163 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -17,17 +17,25 @@
import its.objects
import its.image
import its.caps
+import re
def main():
"""capture a yuv image and save it to argv[1]
"""
camera_id = -1
out_path = ""
+ scene_name = ""
+ scene_desc = "No requirement"
for s in sys.argv[1:]:
if s[:7] == "camera=" and len(s) > 7:
camera_id = s[7:]
elif s[:4] == "out=" and len(s) > 4:
out_path = s[4:]
+ elif s[:6] == "scene=" and len(s) > 6:
+ scene_desc = s[6:]
+
+ if out_path != "":
+ scene_name = re.split("/|\.", out_path)[-2]
if camera_id == -1:
print "Error: need to specify which camera to use"
@@ -35,7 +43,8 @@
with its.device.ItsSession() as cam:
raw_input("Press Enter after placing camera " + camera_id +
- " to frame the test scene")
+ " to frame the test scene: " + scene_name +
+ "\nThe scene setup should be: " + scene_desc )
# Converge 3A prior to capture.
cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
props = cam.get_camera_properties()
@@ -52,7 +61,8 @@
its.image.write_image(img, out_path)
print "Please check scene setup in", out_path
choice = raw_input(
- "Is the image okay for ITS scene1? (Y/N)").lower()
+ "Is the image okay for ITS " + scene_name +\
+ "? (Y/N)").lower()
if choice == "y":
break
else:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
index cf8365a..57d0c8f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
@@ -116,9 +116,15 @@
faceObj.put("bounds", serializeRect(face.getBounds()));
faceObj.put("score", face.getScore());
faceObj.put("id", face.getId());
- faceObj.put("leftEye", serializePoint(face.getLeftEyePosition()));
- faceObj.put("rightEye", serializePoint(face.getRightEyePosition()));
- faceObj.put("mouth", serializePoint(face.getMouthPosition()));
+ if (face.getLeftEyePosition() != null) {
+ faceObj.put("leftEye", serializePoint(face.getLeftEyePosition()));
+ }
+ if (face.getRightEyePosition() != null) {
+ faceObj.put("rightEye", serializePoint(face.getRightEyePosition()));
+ }
+ if (face.getMouthPosition() != null) {
+ faceObj.put("mouth", serializePoint(face.getMouthPosition()));
+ }
return faceObj;
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index f3acf4c..964e6b6 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -1375,7 +1375,7 @@
}
}
}
- mCollector.expectValuesInRange("Face scores are invalid", faceIds,
+ mCollector.expectValuesInRange("Face scores are invalid", faceScores,
Face.SCORE_MIN, Face.SCORE_MAX);
mCollector.expectValuesUnique("Face ids are invalid", faceIds);
}