Пример #1
0
def wavelet_compression(rgb_image: np.ndarray) -> model.CompressedImage:
    yrcrcb = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2YCrCb)
    [gray, color_1, color_2] = cv2.split(yrcrcb)

    channels = {"lum": gray, "cr": color_1, "cb": color_2}

    def channel_func(k, v: np.ndarray):
        offset = np.subtract(v.astype(np.int64), np.power(2, 8))
        transformed = transform.wavelet_split_resolutions(
            offset, settings.WAVELET, settings.WAVELET_NUM_LEVELS)
        subbands = transform.subband_view(transformed)
        if settings.WAVELET_SUBBAND_QUANTIZATION_MULTIPLIER != 0:
            subbands = qnt.subband_quantize(
                subbands,
                multiplier=settings.WAVELET_SUBBAND_QUANTIZATION_MULTIPLIER)
        r_transformed = transform.linearize_subband(subbands)
        thresholded = transform.threshold_channel_by_quality(
            r_transformed, q_factor=settings.WAVELET_QUALITY_FACTOR)

        if settings.WAVELET_THRESHOLD != 0:
            thresholded = [
                transform.threshold(part, settings.WAVELET_THRESHOLD)
                for part in thresholded
            ]
        rounded = [qnt.round_quantize(t) for t in thresholded]
        return rounded

    channels = utils.dict_map(channels, channel_func)

    return model.CompressedImage.from_dict(channels)
Пример #2
0
def wavelet_decode(hic: hic.HicImage) -> model.CompressedImage:
    utils.debug_msg("Wavelet decode")
    assert hic.hic_type == model.Compression.HIC
    payloads = hic.payloads
    utils.debug_msg("Decoding Huffman trees")
    value_huffs = {
        "lum": huffman_decode(payloads[0]),
        "cr": huffman_decode(payloads[1]),
        "cb": huffman_decode(payloads[2])
    }
    length_huffs = {
        "lum": huffman_decode(payloads[3]),
        "cr": huffman_decode(payloads[4]),
        "cb": huffman_decode(payloads[5])
    }

    utils.debug_msg("Decode RLE values")
    value_comps = {
        "lum": huffman_data_decode(payloads[6], value_huffs["lum"]),
        "cr": huffman_data_decode(payloads[7], value_huffs["cr"]),
        "cb": huffman_data_decode(payloads[8], value_huffs["cb"]),
    }
    utils.debug_msg("Decode RLE lengths")
    length_comps = {
        "lum": huffman_data_decode(payloads[9], length_huffs["lum"]),
        "cr": huffman_data_decode(payloads[10], length_huffs["cr"]),
        "cb": huffman_data_decode(payloads[11], length_huffs["cb"]),
    }
    min_shape = payloads[12].numbers
    max_shape = payloads[13].numbers

    utils.debug_msg("Unloaded all of the data")
    # ====
    rles = utils.dict_map(
        value_comps, lambda k, v: [
            RunLength(value=t[1], length=t[0])
            for t in list(zip(length_comps[k], v))
        ])
    length = wavelet_decoded_length(min_shape, max_shape)

    data = utils.dict_map(rles, lambda _, v: decode_run_length(v, length))
    shapes = wavelet_decoded_subbands_shapes(min_shape, max_shape)
    channels = utils.dict_map(
        data, lambda _, v: wavelet_decode_pull_subbands(v, shapes))
    return model.CompressedImage.from_dict(channels)
Пример #3
0
def wavelet_encode(compressed: model.CompressedImage):
    """
    In brief reading of literature, Huffman coding is still considered for wavelet image compression. There are other
    more effective (and complicated schemes) that I think are out of scope of this project which is just to introduce
    the concepts.
    """
    def collapse_subbands(k, v):
        out = [transform.zigzag(l) for l in v]
        out = utils.flatten(out)
        return out

    utils.debug_msg("Starting Wavelet encoding")
    lin_subbands = utils.dict_map(compressed.as_dict, collapse_subbands)
    utils.debug_msg("Have completed linearizing the subbands")
    rles = utils.dict_map(lin_subbands, lambda _, v: run_length_coding(v))
    utils.debug_msg("Have completed the run length encodings")

    values_huffs = utils.dict_map(
        rles, lambda _, v: huffman.HuffmanTree.construct_from_data(
            v, key_func=lambda t: t.value))
    length_huffs = utils.dict_map(
        rles, lambda _, v: huffman.HuffmanTree.construct_from_data(
            v, key_func=lambda t: t.length))
    utils.debug_msg("Huffman trees are constructed")

    def encode_huff(d):
        huffs = [t[1] for t in d.items()]
        return [huffman_encode(h) for h in huffs]

    def encode_data(d):
        huffs = [t[1] for t in d.items()]
        return [huffman_data_encode(h) for h in huffs]

    smallest = compressed.luminance_component[0].shape
    biggest = compressed.luminance_component[-1].shape

    payloads = utils.flatten([
        encode_huff(values_huffs),
        encode_huff(length_huffs),
        encode_data(values_huffs),
        encode_data(length_huffs),
        [hic.TupP(smallest[0], smallest[1]),
         hic.TupP(biggest[0], biggest[1])]
    ])
    return hic.HicImage.wavelet_image(payloads)
Пример #4
0
def wavelet_decompression(channels: model.CompressedImage) -> np.ndarray:
    def channel_func(k, v):
        subbands = transform.subband_view(v)
        if settings.WAVELET_SUBBAND_QUANTIZATION_MULTIPLIER != 0:
            subbands = qnt.subband_invert_quantize(
                subbands, settings.WAVELET_SUBBAND_QUANTIZATION_MULTIPLIER)
        li = transform.linearize_subband(subbands)
        merged = transform.wavelet_merge_resolutions(li, settings.WAVELET)
        offset = np.add(merged, np.power(2, 8)).astype(np.uint8)
        return offset

    channels = utils.dict_map(channels.as_dict, channel_func)
    yrcrcb = transform.force_merge(channels["lum"], channels["cr"],
                                   channels["cb"]).astype(np.uint8)
    return cv2.cvtColor(yrcrcb, cv2.COLOR_YCrCb2RGB)
Пример #5
0
def jpeg_decompression(d: model.CompressedImage) -> np.ndarray:
    """
    Decompress a JPEG image for viewing
    """
    def channel_fun(k, v):
        if k == "lum":
            return transform.inv_dct_channel(
                v,
                model.QTables.JPEG_LUMINANCE,
                block_size=settings.JPEG_BLOCK_SIZE)
        else:
            return transform.up_sample(
                transform.inv_dct_channel(v,
                                          model.QTables.JPEG_CHROMINANCE,
                                          block_size=settings.JPEG_BLOCK_SIZE))

    channels = utils.dict_map(d.as_dict, channel_fun)
    y = transform.force_merge(channels["lum"], channels["cr"], channels["cb"])
    return cv2.cvtColor(y, cv2.COLOR_YCrCb2RGB)
Пример #6
0
def jpeg_compression(rgb_image: np.ndarray) -> model.CompressedImage:
    """
    JPEG compression
    """
    utils.debug_msg("Starting JPEG compression")
    yrcrcb = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2YCrCb)
    [gray, color_1, color_2] = cv2.split(yrcrcb)
    channels = {"lum": gray, "cr": color_1, "cb": color_2}

    def channel_fun(k, v):
        utils.debug_msg("Process channel: " + k)
        if k == "lum":
            return transform.dct_channel(v,
                                         model.QTables.JPEG_LUMINANCE,
                                         block_size=settings.JPEG_BLOCK_SIZE)
        else:
            return transform.dct_channel(transform.down_sample(v),
                                         model.QTables.JPEG_CHROMINANCE,
                                         block_size=settings.JPEG_BLOCK_SIZE)

    channels = utils.dict_map(channels, channel_fun)
    utils.debug_msg("Transformed our channels")
    return model.CompressedImage.from_dict(channels)
Пример #7
0
def jpeg_decode(hic: hic.HicImage) -> model.CompressedImage:
    """
    Reverse jpeg_encode()
    payloads = utils.flatten([
        encode_huff(dc_huffs),
        encode_huff(ac_value_huffs),
        encode_huff(ac_length_huffs),

        encode_data(dc_huffs),
        encode_data(ac_value_huffs),
        encode_data(ac_length_huffs)
    ])
    """
    utils.debug_msg("JPEG decode")
    assert hic.hic_type == model.Compression.JPEG
    payloads = hic.payloads
    utils.debug_msg("Decoding Huffman trees")
    dc_huffs = {
        "lum": huffman_decode(payloads[0]),
        "cr": huffman_decode(payloads[1]),
        "cb": huffman_decode(payloads[2])
    }
    ac_value_huffs = {
        "lum": huffman_decode(payloads[3]),
        "cr": huffman_decode(payloads[4]),
        "cb": huffman_decode(payloads[5])
    }
    ac_length_huffs = {
        "lum": huffman_decode(payloads[6]),
        "cr": huffman_decode(payloads[7]),
        "cb": huffman_decode(payloads[8])
    }

    utils.debug_msg("Decode DC differences")
    dc_comps = {
        "lum": huffman_data_decode(payloads[9], dc_huffs["lum"]),
        "cr": huffman_data_decode(payloads[10], dc_huffs["cr"]),
        "cb": huffman_data_decode(payloads[11], dc_huffs["cb"]),
    }

    utils.debug_msg("Decode RLE values")
    ac_values = {
        "lum": huffman_data_decode(payloads[12], ac_value_huffs["lum"]),
        "cr": huffman_data_decode(payloads[13], ac_value_huffs["cr"]),
        "cb": huffman_data_decode(payloads[14], ac_value_huffs["cb"]),
    }
    utils.debug_msg("Decode RLE lengths")
    ac_lengths = {
        "lum": huffman_data_decode(payloads[15], ac_length_huffs["lum"]),
        "cr": huffman_data_decode(payloads[16], ac_length_huffs["cr"]),
        "cb": huffman_data_decode(payloads[17], ac_length_huffs["cb"]),
    }
    shapes = {
        "lum": payloads[18].numbers,
        "cr": payloads[19].numbers,
        "cb": payloads[19].numbers
    }
    utils.debug_msg("Unloaded all of the data")
    # ====

    sub_length = utils.size(settings.JPEG_BLOCK_SHAPE()) - 1
    utils.debug_msg("Calculating AC RLEs")
    ac_rle = utils.dict_map(
        ac_values, lambda k, v:
        [RunLength(t[1], t[0]) for t in list(zip(ac_lengths[k], v))])

    def ac_mat_fun(k, v):
        utils.debug_msg("Determining deficient AC matricies for: " + k)
        ac_length = utils.size(shapes[k]) - len(dc_comps[k])
        out = decode_run_length(v, ac_length)
        if k == "lum":
            s = [str(i) for i in out]
            print(" ".join(s))
        return out

    ac_mats = utils.dict_map(ac_rle, ac_mat_fun)
    ac_mats = utils.dict_map(ac_mats,
                             lambda _, v: utils.group_tuples(v, sub_length))
    dc_comps = utils.dict_map(dc_comps,
                              lambda _, v: utils.invert_differences(v))

    def merge_comps(dc_key, dc_values):
        utils.debug_msg("Merging: " + dc_key)
        tuples = ac_mats[
            dc_key]  # there are all of the AC zigzag arrays missing their DC component
        assert len(tuples) == len(dc_values)
        zipped = zip(dc_values, tuples)  # combine them to be mapped later
        lin_mats = [[t[0], *t[1]]
                    for t in zipped]  # create the linearized block
        mats = [
            transform.izigzag(np.array(m), settings.JPEG_BLOCK_SHAPE())
            for m in lin_mats
        ]
        return mats

    compressed = utils.dict_map(dc_comps, merge_comps)
    merged = utils.dict_map(
        compressed,
        lambda k, v: transform.merge_blocks(np.array(v), shapes[k]))
    return model.CompressedImage.from_dict(merged)
Пример #8
0
def jpeg_encode(compressed: model.CompressedImage) -> hic.HicImage:
    """
    Generally follow JPEG encoding. Since for the wavelet work I am don't have some standard huffman tree to work with
    I might as well be consistent between the two implementations and just encode the entire array with custom
    Huffman trees. To attempt to be honest with the implementation though, I'll still treat the DC components
    separately by doing the differences and again applying a custom Huffman. A main feature of DCT on each block is the
    meaning of the DC component.

    For RL it's also easier implementation-wise to split up the length from the value and not try to optimize and weave
    them together. Yes, the encoding will suffer bloat, but we are trying to highlight the transforms anyway.
    """
    utils.debug_msg("Starting JPEG encoding")
    dc_comps = utils.dict_map(
        compressed.as_dict, lambda _, v: differential_coding(
            transform.split_matrix(v, settings.JPEG_BLOCK_SIZE)))

    utils.debug_msg("Determined differences DC components")

    def ac_comp_fun(k, v):
        utils.debug_msg("Determining AC components for: " + k)
        splits = transform.split_matrix(v, settings.JPEG_BLOCK_SIZE)
        acs = transform.ac_components(splits)
        utils.debug_msg("Calculating RLE for: " + k)
        out = run_length_coding(acs)
        return out

    # on each transformed channel, run RLE on the AC components of each block
    ac_comps = utils.dict_map(compressed.as_dict, ac_comp_fun)

    utils.debug_msg("Determined RLEs for AC components")
    dc_huffs = utils.dict_map(
        dc_comps, lambda _, v: huffman.HuffmanTree.construct_from_data(v))
    ac_value_huffs = utils.dict_map(
        ac_comps, lambda _, v: huffman.HuffmanTree.construct_from_data(
            v, key_func=lambda s: s.value))
    ac_length_huffs = utils.dict_map(
        ac_comps, lambda _, v: huffman.HuffmanTree.construct_from_data(
            v, key_func=lambda s: s.length))

    def encode_huff(d):
        huffs = [t[1] for t in d.items()]
        return [huffman_encode(h) for h in huffs]

    def encode_data(d):
        huffs = [t[1] for t in d.items()]
        return [huffman_data_encode(h) for h in huffs]

    payloads = utils.flatten([
        encode_huff(dc_huffs),
        encode_huff(ac_value_huffs),
        encode_huff(ac_length_huffs),
        encode_data(dc_huffs),
        encode_data(ac_value_huffs),
        encode_data(ac_length_huffs),
        [
            hic.TupP(compressed.shape[0][0], compressed.shape[0][1]),
            hic.TupP(compressed.shape[1][0], compressed.shape[1][1])
        ]
    ])

    return hic.HicImage.jpeg_image(payloads)
Пример #9
0
 def test_dict_map(self):
     d = {"a": 1, "b": 2}
     out = utils.dict_map(d, lambda k, v: k + str(v))
     self.assertEqual(out, {"a": "a1", "b": "b2"})