Squashed mnc-dev changes:
This contains all of the changes from b54aa51 to
791e51a on mnc-dev, except the changes
to tests/tests/security.
Bug: 24846656
Change-Id: I01f53a1a238ac49f86928e0e22796dc73e0e34af
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 756f959..835a4a4 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -448,8 +448,8 @@
The out_surfaces field can specify the width(s), height(s), and
format(s) of the captured image. The formats may be "yuv", "jpeg",
- "dng", "raw", "raw10", or "raw12". The default is a YUV420 frame ("yuv")
- corresponding to a full sensor frame.
+ "dng", "raw", "raw10", "raw12", or "rawStats". The default is a YUV420
+ frame ("yuv") corresponding to a full sensor frame.
Note that one or more surfaces can be specified, allowing a capture to
request images back in multiple formats (e.g.) raw+yuv, raw+jpeg,
@@ -536,6 +536,25 @@
yuv_caps = do_capture( [req1,req2], yuv_fmt )
yuv_caps, raw_caps = do_capture( [req1,req2], [yuv_fmt,raw_fmt] )
+ The "rawStats" format processes the raw image and returns a new image
+ of statistics from the raw image. The format takes additional keys,
+ "gridWidth" and "gridHeight" which are size of grid cells in a 2D grid
+ of the raw image. For each grid cell, the mean and variance of each raw
+ channel is computed, and the do_capture call returns two 4-element float
+ images of dimensions (rawWidth / gridWidth, rawHeight / gridHeight),
+ concatenated back-to-back, where the first iamge contains the 4-channel
+ means and the second contains the 4-channel variances.
+
+ For the rawStats format, if the gridWidth is not provided then the raw
+ image width is used as the default, and similarly for gridHeight. With
+ this, the following is an example of a output description that computes
+ the mean and variance across each image row:
+
+ {
+ "gridHeight": 1,
+ "format": "rawStats"
+ }
+
Args:
cap_request: The Python dict/list specifying the capture(s), which
will be converted to JSON and sent to the device.
@@ -550,7 +569,8 @@
* data: the image data as a numpy array of bytes.
* width: the width of the captured image.
* height: the height of the captured image.
- * format: image the format, in ["yuv","jpeg","raw","raw10","dng"].
+ * format: image the format, in [
+ "yuv","jpeg","raw","raw10","raw12","rawStats","dng"].
* metadata: the capture result object (Python dictionary).
"""
cmd = {}
@@ -577,9 +597,13 @@
nsurf = 1 if out_surfaces is None else len(cmd["outputSurfaces"])
if len(formats) > len(set(formats)):
raise its.error.Error('Duplicate format requested')
- if "dng" in formats and "raw" in formats or \
- "dng" in formats and "raw10" in formats or \
- "raw" in formats and "raw10" in formats:
+ raw_formats = 0;
+ raw_formats += 1 if "dng" in formats else 0
+ raw_formats += 1 if "raw" in formats else 0
+ raw_formats += 1 if "raw10" in formats else 0
+ raw_formats += 1 if "raw12" in formats else 0
+ raw_formats += 1 if "rawStats" in formats else 0
+ if raw_formats > 1:
raise its.error.Error('Different raw formats not supported')
# Detect long exposure time and set timeout accordingly
@@ -603,14 +627,16 @@
# the burst, however individual images of different formats can come
# out in any order for that capture.
nbufs = 0
- bufs = {"yuv":[], "raw":[], "raw10":[], "dng":[], "jpeg":[]}
+ bufs = {"yuv":[], "raw":[], "raw10":[], "raw12":[],
+ "rawStats":[], "dng":[], "jpeg":[]}
mds = []
widths = None
heights = None
while nbufs < ncap*nsurf or len(mds) < ncap:
jsonObj,buf = self.__read_response_from_socket()
if jsonObj['tag'] in ['jpegImage', 'yuvImage', 'rawImage', \
- 'raw10Image', 'dngImage'] and buf is not None:
+ 'raw10Image', 'raw12Image', 'rawStatsImage', 'dngImage'] \
+ and buf is not None:
fmt = jsonObj['tag'][:-5]
bufs[fmt].append(buf)
nbufs += 1
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index ea01a3e..a5ac60b 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -81,6 +81,25 @@
else:
raise its.error.Error('Invalid format %s' % (cap["format"]))
+def unpack_rawstats_capture(cap):
+ """Unpack a rawStats capture to the mean and variance images.
+
+ Args:
+ cap: A capture object as returned by its.device.do_capture.
+
+ Returns:
+ Tuple (mean_image var_image) of float-4 images, with non-normalized
+ pixel values computed from the RAW16 images on the device
+ """
+ assert(cap["format"] == "rawStats")
+ w = cap["width"]
+ h = cap["height"]
+ img = numpy.ndarray(shape=(2*h*w*4,), dtype='<f', buffer=cap["data"])
+ analysis_image = img.reshape(2,h,w,4)
+ mean_image = analysis_image[0,:,:,:].reshape(h,w,4)
+ var_image = analysis_image[1,:,:,:].reshape(h,w,4)
+ return mean_image, var_image
+
def unpack_raw10_capture(cap, props):
"""Unpack a raw-10 capture to a raw-16 capture.
@@ -604,6 +623,21 @@
variances.append(numpy.var(img[:,:,i], dtype=numpy.float64))
return variances
+def compute_image_snrs(img):
+ """Calculate the SNR (db) of each color channel in the image.
+
+ Args:
+ img: Numpy float image array, with pixel values in [0,1].
+
+ Returns:
+ A list of SNR value, one per color channel in the image.
+ """
+ means = compute_image_means(img)
+ variances = compute_image_variances(img)
+ std_devs = [math.sqrt(v) for v in variances]
+ snr = [20 * math.log10(m/s) for m,s in zip(means, std_devs)]
+ return snr
+
def write_image(img, fname, apply_gamma=False):
"""Save a float-3 numpy array image to a file.
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index 82346ec..ac384fb 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -152,24 +152,37 @@
return req
-def get_available_output_sizes(fmt, props):
+def get_available_output_sizes(fmt, props, max_size=None, match_ar_size=None):
"""Return a sorted list of available output sizes for a given format.
Args:
fmt: the output format, as a string in
["jpg", "yuv", "raw", "raw10", "raw12"].
props: the object returned from its.device.get_camera_properties().
+ max_size: (Optional) A (w,h) tuple.
+ Sizes larger than max_size (either w or h) will be discarded.
+ match_ar_size: (Optional) A (w,h) tuple.
+ Sizes not matching the aspect ratio of match_ar_size will be
+ discarded.
Returns:
A sorted list of (w,h) tuples (sorted large-to-small).
"""
- fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26, "yuv":0x23,
+ AR_TOLERANCE = 0.03
+ fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26,"yuv":0x23,
"jpg":0x100, "jpeg":0x100}
configs = props['android.scaler.streamConfigurationMap']\
['availableStreamConfigurations']
fmt_configs = [cfg for cfg in configs if cfg['format'] == fmt_codes[fmt]]
out_configs = [cfg for cfg in fmt_configs if cfg['input'] == False]
out_sizes = [(cfg['width'],cfg['height']) for cfg in out_configs]
+ if max_size:
+ out_sizes = [s for s in out_sizes if
+ s[0] <= max_size[0] and s[1] <= max_size[1]]
+ if match_ar_size:
+ ar = match_ar_size[0] / float(match_ar_size[1])
+ out_sizes = [s for s in out_sizes if
+ abs(ar - s[0] / float(s[1])) <= AR_TOLERANCE]
out_sizes.sort(reverse=True)
return out_sizes
diff --git a/apps/CameraITS/tests/inprog/test_rawstats.py b/apps/CameraITS/tests/inprog/test_rawstats.py
new file mode 100644
index 0000000..8083f0b
--- /dev/null
+++ b/apps/CameraITS/tests/inprog/test_rawstats.py
@@ -0,0 +1,48 @@
+# Copyright 2015 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.caps
+import its.device
+import its.objects
+import its.target
+import os.path
+import math
+
+def main():
+ """Test capturing some rawstats data.
+ """
+ NAME = os.path.basename(__file__).split(".")[0]
+
+ with its.device.ItsSession() as cam:
+
+ cam.do_3a(do_af=False);
+ req = its.objects.auto_capture_request()
+
+ for (gw,gh) in [(16,16)]:#,(4080,1)]:
+ cap = cam.do_capture(req,
+ {"format":"rawStats","gridWidth":gw,"gridHeight":gh})
+ mean_image, var_image = its.image.unpack_rawstats_capture(cap)
+
+ if gw > 1 and gh > 1:
+ h,w,_ = mean_image.shape
+ for ch in range(4):
+ m = mean_image[:,:,ch].reshape(h,w,1)/1023.0
+ v = var_image[:,:,ch].reshape(h,w,1)
+ its.image.write_image(m, "%s_mean_ch%d.jpg" % (NAME,ch), True)
+ its.image.write_image(v, "%s_var_ch%d.jpg" % (NAME,ch), True)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index 26c398d..89bc724 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -35,8 +35,10 @@
THRESHOLD_MAX_OUTLIER_DIFF = 0.1
THRESHOLD_MIN_LEVEL = 0.1
THRESHOLD_MAX_LEVEL = 0.9
- THRESHOLD_MAX_LEVEL_DIFF = 0.025
+ THRESHOLD_MAX_LEVEL_DIFF = 0.03
THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE = 0.05
+ THRESHOLD_ROUND_DOWN_GAIN = 0.1
+ THRESHOLD_ROUND_DOWN_EXP = 0.05
mults = []
r_means = []
@@ -50,21 +52,33 @@
its.caps.per_frame_control(props))
e,s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
+ s_e_product = s*e
expt_range = props['android.sensor.info.exposureTimeRange']
sens_range = props['android.sensor.info.sensitivityRange']
- m = 1
+ m = 1.0
while s*m < sens_range[1] and e/m > expt_range[0]:
mults.append(m)
- req = its.objects.manual_capture_request(s*m, e/m)
+ s_test = round(s*m)
+ e_test = s_e_product / s_test
+ print "Testsing s:", s_test, "e:", e_test
+ req = its.objects.manual_capture_request(s_test, e_test)
cap = cam.do_capture(req)
+ s_res = cap["metadata"]["android.sensor.sensitivity"]
+ e_res = cap["metadata"]["android.sensor.exposureTime"]
+ assert(0 <= s_test - s_res < s_test * THRESHOLD_ROUND_DOWN_GAIN)
+ assert(0 <= e_test - e_res < e_test * THRESHOLD_ROUND_DOWN_EXP)
+ s_e_product_res = s_res * e_res
+ request_result_ratio = s_e_product / s_e_product_res
+ print "Capture result s:", s_test, "e:", e_test
img = its.image.convert_capture_to_rgb_image(cap)
its.image.write_image(img, "%s_mult=%3.2f.jpg" % (NAME, m))
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb_means = its.image.compute_image_means(tile)
- r_means.append(rgb_means[0])
- g_means.append(rgb_means[1])
- b_means.append(rgb_means[2])
+ # Adjust for the difference between request and result
+ r_means.append(rgb_means[0] * request_result_ratio)
+ g_means.append(rgb_means[1] * request_result_ratio)
+ b_means.append(rgb_means[2] * request_result_ratio)
# Test 3 steps per 2x gain
m = m * pow(2, 1.0 / 3)
@@ -73,9 +87,9 @@
threshold_max_level_diff = THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE
# Draw a plot.
- pylab.plot(mults, r_means, 'r')
- pylab.plot(mults, g_means, 'g')
- pylab.plot(mults, b_means, 'b')
+ pylab.plot(mults, r_means, 'r.-')
+ pylab.plot(mults, g_means, 'g.-')
+ pylab.plot(mults, b_means, 'b.-')
pylab.ylim([0,1])
matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME))
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index 35cfc07..1072684 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -35,12 +35,13 @@
"""
NAME = os.path.basename(__file__).split(".")[0]
- RELATIVE_ERROR_TOLERANCE = 0.1
- # List of variances for R,G,B.
- variances = [[],[],[]]
+ NUM_SAMPLES_PER_MODE = 4
+ SNR_TOLERANCE = 3 # unit in db
+ # List of SNRs for R,G,B.
+ snrs = [[], [], []]
- # Reference (baseline) variance for each of R,G,B.
- ref_variance = []
+ # Reference (baseline) SNR for each of R,G,B.
+ ref_snr = []
nr_modes_reported = []
@@ -60,8 +61,8 @@
rgb_image,
"%s_low_gain.jpg" % (NAME))
rgb_tile = its.image.get_image_patch(rgb_image, 0.45, 0.45, 0.1, 0.1)
- ref_variance = its.image.compute_image_variances(rgb_tile)
- print "Ref variances:", ref_variance
+ ref_snr = its.image.compute_image_snrs(rgb_tile)
+ print "Ref SNRs:", ref_snr
e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
# NR modes 0, 1, 2, 3, 4 with high gain
@@ -70,58 +71,74 @@
if not its.caps.noise_reduction_mode(props, mode):
nr_modes_reported.append(mode)
for channel in range(3):
- variances[channel].append(0)
+ snrs[channel].append(0)
continue;
- req = its.objects.manual_capture_request(s, e)
- req["android.noiseReduction.mode"] = mode
- cap = cam.do_capture(req)
- rgb_image = its.image.convert_capture_to_rgb_image(cap)
- nr_modes_reported.append(
- cap["metadata"]["android.noiseReduction.mode"])
- its.image.write_image(
- rgb_image,
- "%s_high_gain_nr=%d.jpg" % (NAME, mode))
- rgb_tile = its.image.get_image_patch(
- rgb_image, 0.45, 0.45, 0.1, 0.1)
- rgb_vars = its.image.compute_image_variances(rgb_tile)
+ rgb_snr_list = []
+ # Capture several images to account for per frame noise variations
+ for n in range(NUM_SAMPLES_PER_MODE):
+ req = its.objects.manual_capture_request(s, e)
+ req["android.noiseReduction.mode"] = mode
+ cap = cam.do_capture(req)
+ rgb_image = its.image.convert_capture_to_rgb_image(cap)
+ if n == 0:
+ nr_modes_reported.append(
+ cap["metadata"]["android.noiseReduction.mode"])
+ its.image.write_image(
+ rgb_image,
+ "%s_high_gain_nr=%d.jpg" % (NAME, mode))
+ rgb_tile = its.image.get_image_patch(
+ rgb_image, 0.45, 0.45, 0.1, 0.1)
+ rgb_snrs = its.image.compute_image_snrs(rgb_tile)
+ rgb_snr_list.append(rgb_snrs)
+
+ r_snrs = [rgb[0] for rgb in rgb_snr_list]
+ g_snrs = [rgb[1] for rgb in rgb_snr_list]
+ b_snrs = [rgb[2] for rgb in rgb_snr_list]
+ rgb_snrs = [numpy.mean(r_snrs), numpy.mean(g_snrs), numpy.mean(b_snrs)]
+ print "NR mode", mode, "SNRs:"
+ print " R SNR:", rgb_snrs[0],\
+ "Min:", min(r_snrs), "Max:", max(r_snrs)
+ print " G SNR:", rgb_snrs[1],\
+ "Min:", min(g_snrs), "Max:", max(g_snrs)
+ print " B SNR:", rgb_snrs[2],\
+ "Min:", min(b_snrs), "Max:", max(b_snrs)
+
for chan in range(3):
- variance = rgb_vars[chan]
- variances[chan].append(variance / ref_variance[chan])
- print "Variances with NR mode [0,1,2]:", variances
+ snrs[chan].append(rgb_snrs[chan])
# Draw a plot.
for j in range(3):
- pylab.plot(range(5), variances[j], "rgb"[j])
- matplotlib.pyplot.savefig("%s_plot_variances.png" % (NAME))
+ pylab.plot(range(5), snrs[j], "rgb"[j])
+ matplotlib.pyplot.savefig("%s_plot_SNRs.png" % (NAME))
assert(nr_modes_reported == [0,1,2,3,4])
for j in range(3):
- # Smaller variance is better
+ # Larger SNR is better
# Verify OFF(0) is not better than FAST(1)
- assert(variances[j][0] >
- variances[j][1] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][1] + SNR_TOLERANCE)
# Verify FAST(1) is not better than HQ(2)
- assert(variances[j][1] >
- variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][1] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify HQ(2) is better than OFF(0)
- assert(variances[j][0] > variances[j][2])
+ assert(snrs[j][0] < snrs[j][2])
if its.caps.noise_reduction_mode(props, 3):
# Verify OFF(0) is not better than MINIMAL(3)
- assert(variances[j][0] >
- variances[j][3] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][3] + SNR_TOLERANCE)
# Verify MINIMAL(3) is not better than HQ(2)
- assert(variances[j][3] >
- variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][3] <
+ snrs[j][2] + SNR_TOLERANCE)
if its.caps.noise_reduction_mode(props, 4):
# Verify ZSL(4) is close to MINIMAL(3)
- assert(numpy.isclose(variances[j][4], variances[j][3],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][3],
+ atol=SNR_TOLERANCE))
elif its.caps.noise_reduction_mode(props, 4):
# Verify ZSL(4) is close to OFF(0)
- assert(numpy.isclose(variances[j][4], variances[j][0],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][0],
+ atol=SNR_TOLERANCE))
if __name__ == '__main__':
main()
diff --git a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
index 6c2b5c1..e176312 100644
--- a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
@@ -44,6 +44,8 @@
# Expose for the scene with min sensitivity
sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+ # Digital gains might not be visible on RAW data
+ sens_max = props['android.sensor.maxAnalogSensitivity']
sens_step = (sens_max - sens_min) / NUM_STEPS
s_ae,e_ae,_,_,_ = cam.do_3a(get_results=True)
s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
index 14c5eb0..cc0ce14 100644
--- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
@@ -42,6 +42,8 @@
# Expose for the scene with min sensitivity
sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+ # Digital gains might not be visible on RAW data
+ sens_max = props['android.sensor.maxAnalogSensitivity']
sens_step = (sens_max - sens_min) / NUM_STEPS
s_ae,e_ae,_,_,_ = cam.do_3a(get_results=True)
s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index 757dfeb..f0a6fbe 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -38,7 +38,8 @@
NAME = os.path.basename(__file__).split(".")[0]
- RELATIVE_ERROR_TOLERANCE = 0.1
+ NUM_SAMPLES_PER_MODE = 4
+ SNR_TOLERANCE = 3 # unit in db
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
@@ -60,7 +61,7 @@
for reprocess_format in reprocess_formats:
# List of variances for R, G, B.
- variances = []
+ snrs = [[], [], []]
nr_modes_reported = []
# NR mode 0 with low gain
@@ -77,71 +78,90 @@
img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
its.image.write_image(img, "%s_low_gain_fmt=jpg.jpg" % (NAME))
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
- ref_variance = its.image.compute_image_variances(tile)
- print "Ref variances:", ref_variance
+ ref_snr = its.image.compute_image_snrs(tile)
+ print "Ref SNRs:", ref_snr
+ e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
for nr_mode in range(5):
# Skip unavailable modes
if not its.caps.noise_reduction_mode(props, nr_mode):
nr_modes_reported.append(nr_mode)
- variances.append(0)
+ for channel in range(3):
+ snrs[channel].append(0)
continue
- # NR modes with high gain
- e, s = its.target.get_target_exposure_combos(cam) \
- ["maxSensitivity"]
- req = its.objects.manual_capture_request(s, e)
- req["android.noiseReduction.mode"] = nr_mode
- cap = cam.do_capture(req, out_surface, reprocess_format)
- nr_modes_reported.append(
- cap["metadata"]["android.noiseReduction.mode"])
+ rgb_snr_list = []
+ # Capture several images to account for per frame noise
+ # variations
+ for n in range(NUM_SAMPLES_PER_MODE):
+ req = its.objects.manual_capture_request(s, e)
+ req["android.noiseReduction.mode"] = nr_mode
+ cap = cam.do_capture(req, out_surface, reprocess_format)
- img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
- its.image.write_image(
- img, "%s_high_gain_nr=%d_fmt=jpg.jpg" % (NAME, nr_mode))
- tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
- # Get the variances for R, G, and B channels
- variance = its.image.compute_image_variances(tile)
- variances.append(
- [variance[chan] / ref_variance[chan] for chan in range(3)])
- print "Variances with NR mode [0,1,2,3,4]:", variances
+ img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+ if n == 0:
+ its.image.write_image(
+ img,
+ "%s_high_gain_nr=%d_fmt=jpg.jpg"
+ %(NAME, nr_mode))
+ nr_modes_reported.append(
+ cap["metadata"]["android.noiseReduction.mode"])
+
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ # Get the variances for R, G, and B channels
+ rgb_snrs = its.image.compute_image_snrs(tile)
+ rgb_snr_list.append(rgb_snrs)
+
+ r_snrs = [rgb[0] for rgb in rgb_snr_list]
+ g_snrs = [rgb[1] for rgb in rgb_snr_list]
+ b_snrs = [rgb[2] for rgb in rgb_snr_list]
+ rgb_snrs = [numpy.mean(r_snrs),
+ numpy.mean(g_snrs),
+ numpy.mean(b_snrs)]
+ print "NR mode", nr_mode, "SNRs:"
+ print " R SNR:", rgb_snrs[0],\
+ "Min:", min(r_snrs), "Max:", max(r_snrs)
+ print " G SNR:", rgb_snrs[1],\
+ "Min:", min(g_snrs), "Max:", max(g_snrs)
+ print " B SNR:", rgb_snrs[2],\
+ "Min:", min(b_snrs), "Max:", max(b_snrs)
+
+ for chan in range(3):
+ snrs[chan].append(rgb_snrs[chan])
# Draw a plot.
- for chan in range(3):
- line = []
- for nr_mode in range(5):
- line.append(variances[nr_mode][chan])
- pylab.plot(range(5), line, "rgb"[chan])
+ for channel in range(3):
+ pylab.plot(range(5), snrs[channel], "rgb"[channel])
- matplotlib.pyplot.savefig("%s_plot_%s_variances.png" %
+ matplotlib.pyplot.savefig("%s_plot_%s_SNRs.png" %
(NAME, reprocess_format))
assert(nr_modes_reported == [0,1,2,3,4])
for j in range(3):
- # Smaller variance is better
+ # Larger is better
# Verify OFF(0) is not better than FAST(1)
- assert(variances[0][j] >
- variances[1][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][1] + SNR_TOLERANCE)
# Verify FAST(1) is not better than HQ(2)
- assert(variances[1][j] >
- variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][1] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify HQ(2) is better than OFF(0)
- assert(variances[0][j] > variances[2][j])
+ assert(snrs[j][0] < snrs[j][2])
if its.caps.noise_reduction_mode(props, 3):
# Verify OFF(0) is not better than MINIMAL(3)
- assert(variances[0][j] >
- variances[3][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][3] + SNR_TOLERANCE)
# Verify MINIMAL(3) is not better than HQ(2)
- assert(variances[3][j] >
- variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][3] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify ZSL(4) is close to MINIMAL(3)
- assert(numpy.isclose(variances[4][j], variances[3][j],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][3],
+ atol=SNR_TOLERANCE))
else:
# Verify ZSL(4) is close to OFF(0)
- assert(numpy.isclose(variances[4][j], variances[0][j],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][0],
+ atol=SNR_TOLERANCE))
if __name__ == '__main__':
main()
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
index 33e7763..268b64a 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
@@ -31,6 +31,12 @@
cam.do_3a()
req = its.objects.auto_capture_request()
+ max_dng_size = \
+ its.objects.get_available_output_sizes("raw", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_dng_size)[0]
+ out_surfaces = [{"format":"dng"},
+ {"format":"yuv", "width":w, "height":h}]
cap_dng, cap_yuv = cam.do_capture(req, cam.CAP_DNG_YUV)
img = its.image.convert_capture_to_rgb_image(cap_yuv)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
index 9ce8d76..78378eb 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
@@ -27,13 +27,17 @@
THRESHOLD_MAX_RMS_DIFF = 0.01
- fmt_yuv = {"format":"yuv"}
- fmt_jpeg = {"format":"jpeg"}
-
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
its.caps.skip_unless(its.caps.compute_target_exposure(props))
+ max_jpeg_size = \
+ its.objects.get_available_output_sizes("jpeg", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_jpeg_size)[0]
+ fmt_yuv = {"format":"yuv", "width":w, "height":h}
+ fmt_jpeg = {"format":"jpeg"}
+
# Use a manual request with a linear tonemap so that the YUV and JPEG
# should look the same (once converted by the its.image module).
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
index f13801b..bfa6a28 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
@@ -38,7 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
- cap_raw, cap_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
+ max_raw_size = \
+ its.objects.get_available_output_sizes("raw", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw_size)[0]
+ out_surfaces = [{"format":"raw"},
+ {"format":"yuv", "width":w, "height":h}]
+ cap_raw, cap_yuv = cam.do_capture(req, out_surfaces)
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
index e52946d..322af10 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
@@ -38,8 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
+ max_raw10_size = \
+ its.objects.get_available_output_sizes("raw10", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw10_size)[0]
cap_raw, cap_yuv = cam.do_capture(req,
- [{"format":"raw10"}, {"format":"yuv"}])
+ [{"format":"raw10"},
+ {"format":"yuv", "width":w, "height":h}])
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
index c5c3c73..b3cca0b 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
@@ -38,8 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
+ max_raw12_size = \
+ its.objects.get_available_output_sizes("raw12", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw12_size)[0]
cap_raw, cap_yuv = cam.do_capture(req,
- [{"format":"raw12"}, {"format":"yuv"}])
+ [{"format":"raw12"},
+ {"format":"yuv", "width":w, "height":h}])
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index 73834cb..e96a9ee 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -53,22 +53,28 @@
"""
NAME = os.path.basename(__file__).split(".")[0]
+ NUM_SAMPLES = 4
req = its.objects.manual_capture_request(sensitivity, exp)
req["android.lens.focusDistance"] = fd
req["android.edge.mode"] = edge_mode
if (reprocess_format != None):
req["android.reprocess.effectiveExposureFactor"] = 1.0
- cap = cam.do_capture(req, out_surface, reprocess_format)
- img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
- its.image.write_image(img, "%s_edge=%d_reprocess_fmt_%s.jpg" %
- (NAME, edge_mode, reprocess_format))
- tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ sharpness_list = []
+ for n in range(NUM_SAMPLES):
+ cap = cam.do_capture(req, out_surface, reprocess_format)
+ img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+ if n == 0:
+ its.image.write_image(img, "%s_reprocess_fmt_%s_edge=%d.jpg" %
+ (NAME, reprocess_format, edge_mode))
+ res_edge_mode = cap["metadata"]["android.edge.mode"]
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ sharpness_list.append(its.image.compute_image_sharpness(tile))
ret = {}
- ret["edge_mode"] = cap["metadata"]["android.edge.mode"]
- ret["sharpness"] = its.image.compute_image_sharpness(tile)
+ ret["edge_mode"] = res_edge_mode
+ ret["sharpness"] = numpy.mean(sharpness_list)
return ret