diff options
-rw-r--r-- | apps/CameraITS/tests/scene1/test_capture_result.py | 326 | ||||
-rw-r--r-- | apps/CameraITS/tests/scene1/test_crop_regions.py | 16 | ||||
-rw-r--r-- | apps/CameraITS/tests/scene1/test_raw_sensitivity.py | 2 | ||||
-rw-r--r-- | apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py (renamed from apps/CameraITS/tests/scene1/test_formats.py) | 3 |
4 files changed, 175 insertions, 172 deletions
diff --git a/apps/CameraITS/tests/scene1/test_capture_result.py b/apps/CameraITS/tests/scene1/test_capture_result.py index 56bde60..c88a2e0 100644 --- a/apps/CameraITS/tests/scene1/test_capture_result.py +++ b/apps/CameraITS/tests/scene1/test_capture_result.py @@ -25,171 +25,49 @@ import mpl_toolkits.mplot3d def main(): """Test that valid data comes back in CaptureResult objects. """ - NAME = os.path.basename(__file__).split(".")[0] + global NAME, auto_req, manual_req, w_map, h_map + global manual_tonemap, manual_transform, manual_gains, manual_region + global manual_exp_time, manual_sensitivity, manual_gains_ok - manual_tonemap = [0,0, 1,1] # Linear - manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9]) - manual_gains = [1,2,3,4] - manual_region = [{"x":8,"y":8,"width":128,"height":128,"weight":1}] - # TODO: Stop using hardcoded exposure values. - manual_exp_time = 100*1000*1000 - manual_sensitivity = 100 - - # The camera HAL may not support different gains for the two G channels. - manual_gains_ok = [[1,2,3,4],[1,2,2,4],[1,3,3,4]] - - auto_req = its.objects.auto_capture_request() - auto_req["android.statistics.lensShadingMapMode"] = 1 - - manual_req = { - "android.control.mode": 0, - "android.control.aeMode": 0, - "android.control.awbMode": 0, - "android.control.afMode": 0, - "android.sensor.frameDuration": 0, - "android.sensor.sensitivity": manual_sensitivity, - "android.sensor.exposureTime": manual_exp_time, - "android.colorCorrection.mode": 0, - "android.colorCorrection.transform": manual_transform, - "android.colorCorrection.gains": manual_gains, - "android.tonemap.mode": 0, - "android.tonemap.curveRed": manual_tonemap, - "android.tonemap.curveGreen": manual_tonemap, - "android.tonemap.curveBlue": manual_tonemap, - "android.control.aeRegions": manual_region, - "android.control.afRegions": manual_region, - "android.control.awbRegions": manual_region, - "android.statistics.lensShadingMapMode":1 - } - - # A very loose definition for two floats being close to each other; - # there may be different interpolation and rounding used to get the - # two values, and all this test is looking at is whether there is - # something obviously broken; it's not looking for a perfect match. - def is_close_float(n1, n2): - return abs(n1 - n2) < 0.05 - - def is_close_rational(n1, n2): - return is_close_float(its.objects.rational_to_float(n1), - its.objects.rational_to_float(n2)) - - def draw_lsc_plot(w_map, h_map, lsc_map, name): - for ch in range(4): - fig = matplotlib.pyplot.figure() - ax = fig.gca(projection='3d') - xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map) - ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape( - h_map, w_map) - zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map) - ax.plot_wireframe(xs, ys, zs) - matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch)) - - def test_auto(cam, w_map, h_map): - # Get 3A lock first, so the auto values in the capture result are - # populated properly. - rect = [[0,0,1,1,1]] - cam.do_3a(rect, rect, rect, True, True, False) - - cap = cam.do_capture(auto_req) - cap_res = cap["metadata"] - - gains = cap_res["android.colorCorrection.gains"] - transform = cap_res["android.colorCorrection.transform"] - exp_time = cap_res['android.sensor.exposureTime'] - lsc_map = cap_res["android.statistics.lensShadingMap"] - ctrl_mode = cap_res["android.control.mode"] - - print "Control mode:", ctrl_mode - print "Gains:", gains - print "Transform:", [its.objects.rational_to_float(t) - for t in transform] - print "AE region:", cap_res['android.control.aeRegions'] - print "AF region:", cap_res['android.control.afRegions'] - print "AWB region:", cap_res['android.control.awbRegions'] - print "LSC map:", w_map, h_map, lsc_map[:8] - - assert(ctrl_mode == 1) - - # Color correction gain and transform must be valid. - assert(len(gains) == 4) - assert(len(transform) == 9) - assert(all([g > 0 for g in gains])) - assert(all([t["denominator"] != 0 for t in transform])) - - # Color correction should not match the manual settings. - assert(any([not is_close_float(gains[i], manual_gains[i]) - for i in xrange(4)])) - assert(any([not is_close_rational(transform[i], manual_transform[i]) - for i in xrange(9)])) - - # Exposure time must be valid. - assert(exp_time > 0) - - # Lens shading map must be valid. - assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) - assert(all([m >= 1 for m in lsc_map])) - - draw_lsc_plot(w_map, h_map, lsc_map, "auto") - - return lsc_map - - def test_manual(cam, w_map, h_map, lsc_map_auto): - cap = cam.do_capture(manual_req) - cap_res = cap["metadata"] - - gains = cap_res["android.colorCorrection.gains"] - transform = cap_res["android.colorCorrection.transform"] - curves = [cap_res["android.tonemap.curveRed"], - cap_res["android.tonemap.curveGreen"], - cap_res["android.tonemap.curveBlue"]] - exp_time = cap_res['android.sensor.exposureTime'] - lsc_map = cap_res["android.statistics.lensShadingMap"] - ctrl_mode = cap_res["android.control.mode"] - - print "Control mode:", ctrl_mode - print "Gains:", gains - print "Transform:", [its.objects.rational_to_float(t) - for t in transform] - print "Tonemap:", curves[0][1::16] - print "AE region:", cap_res['android.control.aeRegions'] - print "AF region:", cap_res['android.control.afRegions'] - print "AWB region:", cap_res['android.control.awbRegions'] - print "LSC map:", w_map, h_map, lsc_map[:8] - - assert(ctrl_mode == 0) - - # Color correction gain and transform must be valid. - # Color correction gains and transform should be the same size and - # values as the manually set values. - assert(len(gains) == 4) - assert(len(transform) == 9) - assert( all([is_close_float(gains[i], manual_gains_ok[0][i]) - for i in xrange(4)]) or - all([is_close_float(gains[i], manual_gains_ok[1][i]) - for i in xrange(4)]) or - all([is_close_float(gains[i], manual_gains_ok[2][i]) - for i in xrange(4)])) - assert(all([is_close_rational(transform[i], manual_transform[i]) - for i in xrange(9)])) - - # Tonemap must be valid. - # The returned tonemap must be linear. - for c in curves: - assert(len(c) > 0) - assert(all([is_close_float(c[i], c[i+1]) - for i in xrange(0,len(c),2)])) - - # Exposure time must be close to the requested exposure time. - assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0)) - - # Lens shading map must be valid. - assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) - assert(all([m >= 1 for m in lsc_map])) - - draw_lsc_plot(w_map, h_map, lsc_map, "manual") + NAME = os.path.basename(__file__).split(".")[0] with its.device.ItsSession() as cam: props = cam.get_camera_properties() + + manual_tonemap = [0,0, 1,1] # Linear + manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9]) + manual_gains = [1,2,3,4] + manual_region = [{"x":8,"y":8,"width":128,"height":128,"weight":1}] + manual_exp_time = min(props['android.sensor.info.exposureTimeRange']) + manual_sensitivity = min(props['android.sensor.info.sensitivityRange']) + + # The camera HAL may not support different gains for two G channels. + manual_gains_ok = [[1,2,3,4],[1,2,2,4],[1,3,3,4]] + + auto_req = its.objects.auto_capture_request() + auto_req["android.statistics.lensShadingMapMode"] = 1 + + manual_req = { + "android.control.mode": 0, + "android.control.aeMode": 0, + "android.control.awbMode": 0, + "android.control.afMode": 0, + "android.sensor.frameDuration": 0, + "android.sensor.sensitivity": manual_sensitivity, + "android.sensor.exposureTime": manual_exp_time, + "android.colorCorrection.mode": 0, + "android.colorCorrection.transform": manual_transform, + "android.colorCorrection.gains": manual_gains, + "android.tonemap.mode": 0, + "android.tonemap.curveRed": manual_tonemap, + "android.tonemap.curveGreen": manual_tonemap, + "android.tonemap.curveBlue": manual_tonemap, + "android.control.aeRegions": manual_region, + "android.control.afRegions": manual_region, + "android.control.awbRegions": manual_region, + "android.statistics.lensShadingMapMode":1 + } + w_map = props["android.lens.info.shadingMapSize"]["width"] h_map = props["android.lens.info.shadingMapSize"]["height"] @@ -200,6 +78,132 @@ def main(): print "Testing auto capture results again" test_auto(cam, w_map, h_map) +# A very loose definition for two floats being close to each other; +# there may be different interpolation and rounding used to get the +# two values, and all this test is looking at is whether there is +# something obviously broken; it's not looking for a perfect match. +def is_close_float(n1, n2): + return abs(n1 - n2) < 0.05 + +def is_close_rational(n1, n2): + return is_close_float(its.objects.rational_to_float(n1), + its.objects.rational_to_float(n2)) + +def draw_lsc_plot(w_map, h_map, lsc_map, name): + for ch in range(4): + fig = matplotlib.pyplot.figure() + ax = fig.gca(projection='3d') + xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map) + ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape( + h_map, w_map) + zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map) + ax.plot_wireframe(xs, ys, zs) + matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch)) + +def test_auto(cam, w_map, h_map): + # Get 3A lock first, so the auto values in the capture result are + # populated properly. + rect = [[0,0,1,1,1]] + cam.do_3a(rect, rect, rect, True, True, False) + + cap = cam.do_capture(auto_req) + cap_res = cap["metadata"] + + gains = cap_res["android.colorCorrection.gains"] + transform = cap_res["android.colorCorrection.transform"] + exp_time = cap_res['android.sensor.exposureTime'] + lsc_map = cap_res["android.statistics.lensShadingMap"] + ctrl_mode = cap_res["android.control.mode"] + + print "Control mode:", ctrl_mode + print "Gains:", gains + print "Transform:", [its.objects.rational_to_float(t) + for t in transform] + print "AE region:", cap_res['android.control.aeRegions'] + print "AF region:", cap_res['android.control.afRegions'] + print "AWB region:", cap_res['android.control.awbRegions'] + print "LSC map:", w_map, h_map, lsc_map[:8] + + assert(ctrl_mode == 1) + + # Color correction gain and transform must be valid. + assert(len(gains) == 4) + assert(len(transform) == 9) + assert(all([g > 0 for g in gains])) + assert(all([t["denominator"] != 0 for t in transform])) + + # Color correction should not match the manual settings. + assert(any([not is_close_float(gains[i], manual_gains[i]) + for i in xrange(4)])) + assert(any([not is_close_rational(transform[i], manual_transform[i]) + for i in xrange(9)])) + + # Exposure time must be valid. + assert(exp_time > 0) + + # Lens shading map must be valid. + assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) + assert(all([m >= 1 for m in lsc_map])) + + draw_lsc_plot(w_map, h_map, lsc_map, "auto") + + return lsc_map + +def test_manual(cam, w_map, h_map, lsc_map_auto): + cap = cam.do_capture(manual_req) + cap_res = cap["metadata"] + + gains = cap_res["android.colorCorrection.gains"] + transform = cap_res["android.colorCorrection.transform"] + curves = [cap_res["android.tonemap.curveRed"], + cap_res["android.tonemap.curveGreen"], + cap_res["android.tonemap.curveBlue"]] + exp_time = cap_res['android.sensor.exposureTime'] + lsc_map = cap_res["android.statistics.lensShadingMap"] + ctrl_mode = cap_res["android.control.mode"] + + print "Control mode:", ctrl_mode + print "Gains:", gains + print "Transform:", [its.objects.rational_to_float(t) + for t in transform] + print "Tonemap:", curves[0][1::16] + print "AE region:", cap_res['android.control.aeRegions'] + print "AF region:", cap_res['android.control.afRegions'] + print "AWB region:", cap_res['android.control.awbRegions'] + print "LSC map:", w_map, h_map, lsc_map[:8] + + assert(ctrl_mode == 0) + + # Color correction gain and transform must be valid. + # Color correction gains and transform should be the same size and + # values as the manually set values. + assert(len(gains) == 4) + assert(len(transform) == 9) + assert( all([is_close_float(gains[i], manual_gains_ok[0][i]) + for i in xrange(4)]) or + all([is_close_float(gains[i], manual_gains_ok[1][i]) + for i in xrange(4)]) or + all([is_close_float(gains[i], manual_gains_ok[2][i]) + for i in xrange(4)])) + assert(all([is_close_rational(transform[i], manual_transform[i]) + for i in xrange(9)])) + + # Tonemap must be valid. + # The returned tonemap must be linear. + for c in curves: + assert(len(c) > 0) + assert(all([is_close_float(c[i], c[i+1]) + for i in xrange(0,len(c),2)])) + + # Exposure time must be close to the requested exposure time. + assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0)) + + # Lens shading map must be valid. + assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) + assert(all([m >= 1 for m in lsc_map])) + + draw_lsc_plot(w_map, h_map, lsc_map, "manual") + if __name__ == '__main__': main() diff --git a/apps/CameraITS/tests/scene1/test_crop_regions.py b/apps/CameraITS/tests/scene1/test_crop_regions.py index d0cd70a..eee9d4a 100644 --- a/apps/CameraITS/tests/scene1/test_crop_regions.py +++ b/apps/CameraITS/tests/scene1/test_crop_regions.py @@ -23,9 +23,6 @@ import matplotlib.pyplot import copy import numpy -# TODO: Fix this test. Currently assumes a non-supported output size in the -# HAL-cropped images. - def main(): """Test that crop regions work. """ @@ -47,6 +44,9 @@ def main(): e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"] print "Active sensor region (%d,%d %dx%d)" % (ax, ay, aw, ah) + # Uses a 2x digital zoom. + assert(props['android.scaler.availableMaxDigitalZoom'] >= 2) + # Capture a full frame. req = its.objects.manual_capture_request(s,e) cap_full = cam.do_capture(req) @@ -55,9 +55,9 @@ def main(): wfull, hfull = cap_full["width"], cap_full["height"] # Capture a burst of crop region frames. - # Each is captured into an image 1/2x1/2 the size, which should allow - # these crop images to be compared with 1/2x1/2 regions that are - # cropped from the full frame. + # Note that each region is 1/2x1/2 of the full frame, and is digitally + # zoomed into the full size output image, so must be downscaled (below) + # by 2x when compared to a tile of the full image. reqs = [] for x,y,w,h in REGIONS: req = its.objects.manual_capture_request(s,e) @@ -67,8 +67,7 @@ def main(): "right": int(ax + aw * (x + w)), "bottom": int(ay + ah * (y + h))} reqs.append(req) - fmt = {"format":"yuv", "width":wfull/2, "height":hfull/2} - caps_regions = cam.do_capture(reqs, fmt) + caps_regions = cam.do_capture(reqs) match_failed = False for i,cap in enumerate(caps_regions): a = cap["metadata"]["android.scaler.cropRegion"] @@ -79,6 +78,7 @@ def main(): # the full image, to find the best match (which should be # the region that corresponds to this crop image). img_crop = its.image.convert_capture_to_rgb_image(cap) + img_crop = its.image.downscale_image(img_crop, 2) its.image.write_image(img_crop, "%s_crop%d.jpg" % (NAME, i)) min_diff = None min_diff_region = None diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py index c53dc01..9845623 100644 --- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py +++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py @@ -48,7 +48,7 @@ def main(): e = int(s_e_prod / float(s)) req = its.objects.manual_capture_request(s, e) - # TODO: Capture using raw-only, once it works reliably. + # Capture raw+yuv, but only look at the raw. cap,_ = cam.do_capture(req, cam.CAP_RAW_YUV) # Measure the variance. Each shot should be noisier than the diff --git a/apps/CameraITS/tests/scene1/test_formats.py b/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py index 402a3e2..aed9b66 100644 --- a/apps/CameraITS/tests/scene1/test_formats.py +++ b/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py @@ -25,8 +25,7 @@ def main(): """ NAME = os.path.basename(__file__).split(".")[0] - # TODO: Look into why some of the RMS diffs are higher in this test. - THRESHOLD_MAX_RMS_DIFF = 0.1 + THRESHOLD_MAX_RMS_DIFF = 0.03 with its.device.ItsSession() as cam: props = cam.get_camera_properties() |