示例#1
0
def mean_std_luts(in_img, ref_img, in_mask=None, ref_mask=None, dtype=np.uint16):

    if in_mask is not None:
        in_mask = np.tile(in_mask[..., None], (1, 1, in_img.shape[2]))
        in_img = np.ma.masked_where(in_mask, in_img)

    if ref_mask is not None:
        ref_mask = np.tile(ref_mask[..., None], (1, 1, ref_img.shape[2]))
        ref_img = np.ma.masked_where(ref_mask, ref_img)

    # Need to make sure we check after masking invalid values
    # Some color targets have values out of the 12-bit range.
    _check_match_images(in_img, ref_img, dtype)

    nbands = in_img.shape[2]
    in_mean = np.array([in_img[..., i].mean() for i in range(nbands)])
    in_std = np.array([in_img[..., i].std() for i in range(nbands)])
    ref_mean = np.array([ref_img[..., i].mean() for i in range(nbands)])
    ref_std = np.array([ref_img[..., i].std() for i in range(nbands)])

    logging.info("Input image mean: {}" \
        .format(in_mean.tolist()))
    logging.info("Input image stddev: {}" \
        .format(in_std.tolist()))
    logging.info("Reference image mean: {}" \
        .format(ref_mean.tolist()))
    logging.info("Reference image stddev: {}" \
        .format(ref_std.tolist()))

    out_luts = []

    if dtype == np.uint16:
        # Assume any 16-bit images are actually 12-bit.
        minimum = 0
        maximum = 4096
    else:
        minimum = np.iinfo(dtype).min
        maximum = np.iinfo(dtype).max
    in_lut = np.arange(minimum, maximum + 1, dtype=dtype)

    # Need to rescale for 8-bit color targets...
    if ref_img.dtype != dtype:
        dmin = np.iinfo(ref_img.dtype).min
        dmax = np.iinfo(ref_img.dtype).max

        ref_mean = maximum * (ref_mean - dmin) / float(dmax - dmin)
        ref_std = maximum * ref_std / float(dmax - dmin)

    for bidx in range(3):

        if in_std[bidx] == 0:
            scale = 0
        else:
            scale = float(ref_std[bidx]) / in_std[bidx]

        offset = ref_mean[bidx] - scale * in_mean[bidx]
        lut = ci.scale_offset_lut(in_lut, scale=scale, offset=offset)
        out_luts.append(lut)

    return out_luts
def mean_std_luts(in_img, ref_img, in_mask=None, ref_mask=None, dtype=np.uint16):

    _check_match_images(in_img, ref_img, dtype)

    # Create a 3d mask from the 2d mask
    # Numpy masked arrays treat True as masked values. Opposite of OpenCV
    if in_mask is not None:
        indices = np.where(in_mask.astype(bool) == False)
        r = in_img[:, :, 0][indices]
        g = in_img[:, :, 1][indices]
        b = in_img[:, :, 2][indices]

    else:
        r = in_img[:, :, 0]
        g = in_img[:, :, 1]
        b = in_img[:, :, 2]

    in_mean = np.array([r.mean(), g.mean(), b.mean()])
    in_std = np.array([r.std(), g.std(), b.std()])

    if ref_mask is not None:
        indices = np.where(ref_mask.astype(bool) == False)
        r_ref = ref_img[:, :, 0][indices]
        g_ref = ref_img[:, :, 1][indices]
        b_ref = ref_img[:, :, 2][indices]
    else:
        r_ref = ref_img[:, :, 0]
        g_ref = ref_img[:, :, 1]
        b_ref = ref_img[:, :, 2]

    ref_mean = np.array([r_ref.mean(), g_ref.mean(), b_ref.mean()])
    ref_std = np.array([r_ref.std(), g_ref.std(), b_ref.std()])

    logging.info("Input image mean: {}".format(in_mean.tolist()))
    logging.info("Input image stddev: {}".format(in_std.tolist()))
    logging.info("Reference image mean: {}".format(ref_mean.tolist()))
    logging.info("Reference image stddev: {}".format(ref_std.tolist()))

    out_luts = []

    # minimum = np.iinfo(dtype).min
    # maximum = np.iinfo(dtype).max
    # test out 12bit
    minimum = 0
    maximum = 4096
    in_lut = np.arange(minimum, maximum + 1, dtype=dtype)

    for bidx in range(3):

        if in_std[bidx] == 0:
            scale = 0
        else:
            scale = float(ref_std[bidx]) / in_std[bidx]

        offset = ref_mean[bidx] - scale * in_mean[bidx]
        lut = ci.scale_offset_lut(in_lut, scale=scale, offset=offset)
        out_luts.append(lut)

    return out_luts
示例#3
0
    def test_scale_offset_lut(self):
        test_lut = np.array(range(10))

        # Test that the returned lut equals the entered lut if
        # no scale or offset is given
        expected = test_lut
        lut = colorimage.scale_offset_lut(test_lut)
        np.testing.assert_array_equal(lut, expected)

        # Test clipping at top values
        expected = np.array([5, 6, 7, 8, 9, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, offset=5)
        np.testing.assert_array_equal(lut, expected)

        # Test clipping at bottom values
        expected = np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4])
        lut = colorimage.scale_offset_lut(test_lut, offset=-5)
        np.testing.assert_array_equal(lut, expected)

        # Test scaling by less than one
        expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
        lut = colorimage.scale_offset_lut(test_lut, scale=0.5)
        np.testing.assert_array_equal(lut, expected)

        # Test scaling by greater than one
        expected = np.array([0, 2, 4, 6, 8, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, scale=2)
        np.testing.assert_array_equal(lut, expected)

        # Test for clipping effects
        # Results should be the same as test 1 above
        test_lut = 2 * np.array(range(10))
        expected = np.array([5, 6, 7, 8, 9, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, scale=0.5, offset=5)
        np.testing.assert_array_equal(lut, expected)
示例#4
0
    def test_scale_offset_lut(self):
        test_lut = numpy.array(range(10))

        # Test that the returned lut equals the entered lut if
        # no scale or offset is given
        expected = test_lut
        lut = colorimage.scale_offset_lut(test_lut)
        numpy.testing.assert_array_equal(lut, expected)

        # Test clipping at top values
        expected = numpy.array([5, 6, 7, 8, 9, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, offset=5)
        numpy.testing.assert_array_equal(lut, expected)

        # Test clipping at bottom values
        expected = numpy.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4])
        lut = colorimage.scale_offset_lut(test_lut, offset=-5)
        numpy.testing.assert_array_equal(lut, expected)

        # Test scaling by less than one
        expected = numpy.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
        lut = colorimage.scale_offset_lut(test_lut, scale=0.5)
        numpy.testing.assert_array_equal(lut, expected)

        # Test scaling by greater than one
        expected = numpy.array([0, 2, 4, 6, 8, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, scale=2)
        numpy.testing.assert_array_equal(lut, expected)

        # Test for clipping effects
        # Results should be the same as test 1 above
        test_lut = 2 * numpy.array(range(10))
        expected = numpy.array([5, 6, 7, 8, 9, 9, 9, 9, 9, 9])
        lut = colorimage.scale_offset_lut(test_lut, scale=0.5, offset=5)
        numpy.testing.assert_array_equal(lut, expected)
def mean_std_luts(in_img, ref_img, in_mask=None, ref_mask=None):
    _check_match_images(in_img, ref_img)

    # Create a 3d mask from the 2d mask
    # Numpy masked arrays treat True as masked values. Opposite of OpenCV
    in_mask = np.dstack(3 * [np.logical_not(in_mask.astype(bool))])
    ref_mask = np.dstack(3 * [np.logical_not(ref_mask.astype(bool))])

    height1, width1, count1 = in_img.shape
    height2, width2, count2 = ref_img.shape

    in_img = np.ma.MaskedArray(in_img, in_mask).reshape(
        (height1 * width1, count1))
    ref_img = np.ma.MaskedArray(ref_img, ref_mask).reshape(
        (height2 * width2, count2))

    in_mean = in_img.mean(axis=0).data
    in_std = in_img.std(axis=0).data
    ref_mean = ref_img.mean(axis=0).data
    ref_std = ref_img.std(axis=0).data

    logging.info("Input image mean: {}" \
        .format(in_mean.tolist()))
    logging.info("Input image stddev: {}" \
        .format(in_std.tolist()))
    logging.info("Reference image mean: {}" \
        .format(ref_mean.tolist()))
    logging.info("Reference image stddev: {}" \
        .format(ref_std.tolist()))

    out_luts = []
    in_lut = np.array(range(0, 256), dtype=np.uint8)

    for bidx in range(count1):

        if in_std[bidx] == 0:
            scale = 0
        else:
            scale = float(ref_std[bidx]) / in_std[bidx]

        offset = ref_mean[bidx] - scale * in_mean[bidx]
        lut = ci.scale_offset_lut(in_lut, scale=scale, offset=offset)
        out_luts.append(lut)

    return out_luts
def mean_std_luts(in_img, ref_img, in_mask=None, ref_mask=None):
    _check_match_images(in_img, ref_img)
    
    # Create a 3d mask from the 2d mask
    # Numpy masked arrays treat True as masked values. Opposite of OpenCV
    in_mask = np.dstack(3 * [np.logical_not(in_mask.astype(bool))])
    ref_mask = np.dstack(3 * [np.logical_not(ref_mask.astype(bool))])
    
    height1, width1, count1 = in_img.shape
    height2, width2, count2 = ref_img.shape
    
    in_img = np.ma.MaskedArray(in_img, in_mask).reshape((height1 * width1, count1))
    ref_img = np.ma.MaskedArray(ref_img, ref_mask).reshape((height2 * width2, count2))
    
    in_mean = in_img.mean(axis=0).data
    in_std = in_img.std(axis=0).data
    ref_mean = ref_img.mean(axis=0).data
    ref_std = ref_img.std(axis=0).data

    logging.info("Input image mean: {}" \
        .format(in_mean.tolist()))
    logging.info("Input image stddev: {}" \
        .format(in_std.tolist()))
    logging.info("Reference image mean: {}" \
        .format(ref_mean.tolist()))
    logging.info("Reference image stddev: {}" \
        .format(ref_std.tolist()))
    
    out_luts = []
    in_lut = np.array(range(0, 256), dtype=np.uint8)

    for bidx in range(count1):

        if in_std[bidx] == 0:
            scale = 0
        else:
            scale = float(ref_std[bidx]) / in_std[bidx]

        offset = ref_mean[bidx] - scale * in_mean[bidx]
        lut = ci.scale_offset_lut(in_lut, scale=scale, offset=offset)
        out_luts.append(lut)

    return out_luts
def mean_std_luts(in_img, ref_img, in_mask=None, ref_mask=None, dtype=np.uint16):
    """
    Create a look up table to linearly scale the colors of the input image to
    the reference image based on their relative means and standard deviations.

    :param in_img:
        Input image to be scaled as a 3D (height x width x nbands) numpy array.
    :param ref_img:
        Reference image to base the scaling on as a 3D numpy array.
    :param in_mask:
        2D boolean mask to be applied to the input image. True values will not
        be included in the color scaling calculation.
    :param ref_mask:
        2D boolean mask to be applied to the reference image. True values will
        not be included in the color scaling calculation.
    :param dtype:
        Numpy data type used to represent the output LUT
    :return look up table:
    """

    if in_mask is not None:
        in_mask = np.tile(in_mask[..., None], (1, 1, in_img.shape[2]))
        in_img = np.ma.masked_where(in_mask, in_img)

    if ref_mask is not None:
        ref_mask = np.tile(ref_mask[..., None], (1, 1, ref_img.shape[2]))
        ref_img = np.ma.masked_where(ref_mask, ref_img)

    # Need to make sure we check after masking invalid values
    # Some color targets have values out of the 12-bit range.
    _check_match_images(in_img, ref_img, dtype)

    nbands = in_img.shape[2]
    in_mean = np.array([in_img[..., i].mean() for i in range(nbands)])
    in_std = np.array([in_img[..., i].std() for i in range(nbands)])
    ref_mean = np.array([ref_img[..., i].mean() for i in range(nbands)])
    ref_std = np.array([ref_img[..., i].std() for i in range(nbands)])

    logging.info("Input image mean: {}" \
        .format(in_mean.tolist()))
    logging.info("Input image stddev: {}" \
        .format(in_std.tolist()))
    logging.info("Reference image mean: {}" \
        .format(ref_mean.tolist()))
    logging.info("Reference image stddev: {}" \
        .format(ref_std.tolist()))

    out_luts = []

    if dtype == np.uint16:
        # Assume any 16-bit images are actually 12-bit.
        minimum = 0
        maximum = 4096
    else:
        minimum = np.iinfo(dtype).min
        maximum = np.iinfo(dtype).max
    in_lut = np.arange(minimum, maximum + 1, dtype=dtype)

    # Need to rescale for 8-bit color targets...
    if ref_img.dtype != dtype:
        dmin = np.iinfo(ref_img.dtype).min
        dmax = np.iinfo(ref_img.dtype).max

        ref_mean = maximum * (ref_mean - dmin) / float(dmax - dmin)
        ref_std = maximum * ref_std / float(dmax - dmin)

    for bidx in range(3):

        if in_std[bidx] == 0:
            scale = 0
        else:
            scale = float(ref_std[bidx]) / in_std[bidx]

        offset = ref_mean[bidx] - scale * in_mean[bidx]
        lut = ci.scale_offset_lut(in_lut, scale=scale, offset=offset)
        out_luts.append(lut)

    return out_luts