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