算术解码 算法实现

数字图像处理 冈萨雷斯 第三版 8.18题
算术解码 算法实现_第1张图片一个简单的解题脚本(Python)

import warnings
import numpy as np


def arith_decode(code_map, encoded_num):
    assert 0 < encoded_num < 1, f"encoded_num:{encoded_num} not in (0,1)"

    codes = [''] + list(code_map.keys())
    acc_values = np.cumsum([0.] + list(code_map.values()))

    def init_idxes():
        nonlocal lower_idx, mid_idx, upper_idx
        mid_idx = len(codes) >> 1
        lower_idx = 0
        upper_idx = len(codes) - 1

    lower_idx, mid_idx, upper_idx = 0, 0, 0
    init_idxes()

    decode_idxes = np.empty(0xff, dtype=np.int8)
    # Binary search
    for decode_idx in range(0xff):
        while upper_idx - lower_idx > 1:
            if acc_values[mid_idx] < encoded_num <= acc_values[upper_idx]:
                lower_idx = mid_idx
                mid_idx = (mid_idx + upper_idx) >> 1
            elif acc_values[lower_idx] <= encoded_num <= acc_values[mid_idx]:
                upper_idx = mid_idx
                mid_idx = (mid_idx + lower_idx) >> 1
            else:
                raise RuntimeError(
                    f"encoded_num:{encoded_num} not in ({acc_values[lower_idx]},{acc_values[upper_idx]})")

        decode_idxes[decode_idx] = upper_idx
        if codes[upper_idx] == '!':
            # Reach the end
            decode_idxes = decode_idxes[:decode_idx + 1]
            break

        # Shrink the range
        acc_values = (acc_values - acc_values[0]) / (acc_values[-1] - acc_values[0]) * (
            acc_values[upper_idx] - acc_values[lower_idx]) + acc_values[lower_idx]

        # Check the range
        min_gap = 1e-15 * (len(codes) - 1)
        if acc_values[-1] - acc_values[0] < min_gap:
            warnings.warn(
                f"acc_vec[-1] - acc_vec[0] = {acc_vec[-1] - acc_vec[0]} is smaller than {min_gap}", RuntimeWarning)
            decode_idxes = decode_idxes[:decode_idx + 1]
            break

        init_idxes()

    decode_res = ''.join([codes[idx] for idx in decode_idxes])
    return decode_res


if __name__ == '__main__':
    code_map = {'a': .2, 'e': .3, 'i': .1, 'o': .2, 'u': .1, '!': .1}
    encoded_num = 0.32256

    print(arith_decode(code_map, encoded_num))

运行结果:eeoe!

你可能感兴趣的:(Python,python,算法)