Пример #1
0
def ac_components(blocks: np.ndarray):
    """
    Return the AC components for blocks (JPEG)
    """
    block_list = blocks.tolist()
    zigs = [zigzag(m)[1:] for m in block_list]
    return utils.flatten(zigs)
Пример #2
0
def threshold_channel_by_quality(parts: List[np.ndarray], q_factor=1):
    """
    Actually apply the threshold after calculating the value. We take an array in parts since most likely
    our call is from the Wavelet compression where we have a series of images from the filter bank.
    """
    imgs = [utils.img_as_list(img) for img in parts]
    vals = utils.flatten(imgs)
    val = qz.quality_threshold_value(vals, q_factor)
    return [threshold(i, val) for i in parts]
Пример #3
0
def decode_run_length(rles: List[RunLength], length: int):
    arr = []
    for (i, d) in enumerate(rles):
        arr.append(d.segment)
    arr = utils.flatten(arr)
    # arr = utils.flatten([d.segment for d in rles])

    if rles[-1].is_trailing:
        fill = length - len(arr)
        arr += ([0] * fill)

    return arr
Пример #4
0
def run_length_coding(arr: np.ndarray, max_len=0xF) -> List[RunLength]:
    """
    Come up with the run length encoding for a matrix
    """
    def _break_up_rle(code, max_len):
        l = code["zeros"]
        div = l // max_len
        full = {
            "zeros": max_len -
            1,  # minus 1 because we get another for free from the value
            "value": 0
        }
        return ([full] * div) + [{
            "zeros": l - (div * max_len),
            "value": code["value"]
        }]

    def reduction(agg, next):
        if "value" in agg[-1]:
            agg.append({"zeros": 0})

        if next == 0:
            agg[-1]["zeros"] += 1
            return agg

        if "value" not in agg[-1]:
            agg[-1]["value"] = next

        return agg

    utils.debug_msg("Going to determine RLE for %d size array" % len(arr))
    rl = functools.reduce(reduction, arr, [{"zeros": 0}])
    utils.debug_msg("%d long RLE created" % len(rl))
    # If the last element has no value then it was 0! That is a special tuple, (0,0)
    if "value" not in rl[-1]:
        rl[-1] = {"zeros": 0, "value": 0}

    # the goal of RLE in the case of compression is to contain the first symbol (length, size) within a byte
    # so if the length is too long, then we need to break it up
    if max_len is not None:
        utils.debug_msg("Breaking up RLE lengths that are larger than %d" %
                        max_len)
        rl = [_break_up_rle(code, max_len) for code in rl]
        rl = utils.flatten(rl)

    utils.debug_msg("Make RLE objects")
    return [RunLength.from_dict(r) for r in rl]
Пример #5
0
 def test_pull_subbands(self):
     expected = [
         np.array(range(4)).reshape((2, 2)),
         np.array(range(4, 8)).reshape((2, 2)),
         np.array(range(8, 12)).reshape((2, 2)),
         np.array(range(12, 16)).reshape((2, 2)),
         np.array(range(16, 32)).reshape((4, 4)),
         np.array(range(32, 48)).reshape((4, 4)),
         np.array(range(48, 64)).reshape((4, 4))
     ]
     data = np.array(utils.flatten([transform.zigzag(m) for m in expected]))
     shapes = [(2, 2), (4, 4)]
     out = codec.wavelet_decode_pull_subbands(data, shapes)
     self.assertEqual(len(expected), len(out))
     z = zip(expected, out)
     for e in z:
         self.assertTrue(np.array_equal(e[0], e[1]))
Пример #6
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)
Пример #7
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)
Пример #8
0
 def collapse_subbands(k, v):
     out = [transform.zigzag(l) for l in v]
     out = utils.flatten(out)
     return out
Пример #9
0
 def test_flatten(self):
     self.assertEqual(utils.flatten([[1, 2], [3, 4]]), [1, 2, 3, 4])