MH\MR编码实现(图像压缩)

最近老师布置了要求实现MH\MR编码,但是比较奇怪的是,在网络上上关于这方面的资料很少,而且基本是介绍方法,没有对具体的编码进行介绍。(先挖个坑,上传编码上去,以后再具体介绍,代码中会有详细的注释,有些操作为了算法的速度,我进行了简化实现)

 MH编码

开头的码表解释一下,上面的码表有问题,因为哈夫曼编码是前缀码,而上面的编码中,有些编码居然是其他编码的前缀,这就很离谱,而且维基和百度上的一些资源基本都有问题,我通过检验是否为前缀码的,找出不是前缀码的编码,参考这些文献,最终得到了下面的码表,大家可以直接复制拿来用哦!!!

(没有使用EOL这个机制,不同行直接用数组存了)(如果需要用EOL也很简单,编码的时候,直接将他们编为一行即可,然后中间加入EOL;解码的时候拿EOL分割即可,或者加一个判断条件)

# 旧码表
# # 结尾码
# MH_BAI_63 = ["00110101","000111","0111","1000","1011","1100","1110","1111","10011","10100","00111","01000","001000","000011","110100","110101","101010","101011","0100111","0001100","0001000","001011","0000011","0000100","0101000","0101011","0010011","0100100","0011000","00000010","00000011","00011010","00011011","00010010","00010011","00010100","00010101","00010110","00010111","00101000","00101001","00101010","00101011","00101100","00101101","00000100","00000101","00001010","00001011","01010010","01010011","01010100","01010101","00100100","00100101","01011000","01011001","01011010","01011011","01001010","01001011","00110010","00110011","00110100"]
# MH_BLACK_63 = ["0000110111","010","11","10","011","0011","0010","00011","000101","000100","0000100","0000101","0000111","00000100","00000111","000011000","0000010111","0000011000","0000001000","00001100111","00001101000","00001101100","00000110111","00000101000","00000010111","00000011000","000011001010","000011001011","000011001100","000011001101","000001101000","000001101001","000001101010","000001101011","000011010010","000011010011","000011010100","000011010101","000011010110","000011010111","000001101100","000001101101","000011011010","000011011011","000001010100","000001010101","000001010110","000001010111","000001100100","000001100101","000001010010","000001010011","000000100100","000000110111","000000111000","000000100111","000000101000","000001011000","000001011001","000000101011","000000101100","000001011010","000001100110","000001100111"]
# # 组合基于码
# MH_BAI_128 = ["11011","10010","010111","0110111","00110110","00110111","01100100","01100101","01101000","01100111","011001100","011001101","011010010","011010011","011010100","011010101","011010110","011010111","011011000","011011001","011011010","011011011","010011000","010011001","010011010","011000","010011011"]
# MH_BLACK_128 = ["0000001111","000011001000","000011001001","000001011011","000000110011","000000110100","000000110101","0000001101100","0000001101101","0000001001010","0000001001011","0000001001100","0000001001101","0000001110010","000000111001","0000001110100","0000001110101","0000001110110","0000001110111","0000001010010","0000001010011","0000001010100","0000001010101","0000001011010","0000001011011","0000001100100","0000001100101"]

# 新码表
MH_BAI_63 = ['00110101', '000111', '0111', '1000', '1011', '1100', '1110', '1111', '10011', '10100', '00111', '01000', '001000', '000011', '110100', '110101', '101010', '101011', '0100111', '0001100', '0001000', '0010111', '0000011', '0000100', '0101000', '0101011', '0010011', '0100100', '0011000', '00000010', '00000011', '00011010', '00011011', '00010010', '00010011', '00010100', '00010101', '00010110', '00010111', '00101000', '00101001', '00101010', '00101011', '00101100', '00101101', '00000100', '00000101', '00001010', '00001011', '01010010', '01010011', '01010100', '01010101', '00100100', '00100101', '01011000', '01011001', '01011010', '01011011', '01001010', '01001011', '00110010', '00110011', '00110100']
MH_BLACK_63 = ['0000110111', '010', '11', '10', '011', '0011', '0010', '00011', '000101', '000100', '0000100', '0000101', '0000111', '00000100', '00000111', '000011000', '0000010111', '0000011000', '0000001000', '00001100111', '00001101000', '00001101100', '00000110111', '00000101000', '00000010111', '00000011000', '000011001010', '000011001011', '000011001100', '000011001101', '000001101000', '000001101001', '000001101010', '000001101011', '000011010010', '000011010011', '000011010100', '000011010101', '000011010110', '000011010111', '000001101100', '000001101101', '000011011010', '000011011011', '000001010100', '000001010101', '000001010110', '000001010111', '000001100100', '000001100101', '000001010010', '000001010011', '000000100100', '000000110111', '000000111000', '000000100111', '000000101000', '000001011000', '000001011001', '000000101011', '000000101100', '000001011010', '000001100110', '000001100111']
MH_BAI_128 = ['11011', '10010', '010111', '0110111', '00110110', '00110111', '01100100', '01100101', '01101000', '01100111', '011001100', '011001101', '011010010', '101010011', '011010100', '011010101', '011010110', '011010111', '011011000', '011011001', '011011010', '011011011', '010011000', '010011001', '010011010', '011000', '010011011']
MH_BLACK_128 = ['0000001111', '00011001000', '000011001001', '000001011011', '000000110011', '000000110100', '000000110101', '0000001101100', '0000001101101', '0000001001010', '0000001001011', '0000001001100', '0000001001101', '0000001110010', '0000001110011', '0000001110100', '0000001110101', '0000001110110', '0000001110111', '0000001010010', '0000001010011', '0000001010100', '0000001010101', '0000001011010', '0000001011011', '0000001100100', '0000001100101']



EOL = "000000000001"
# 第一个为64对应的数,以此类推,最后一个代表eol

# 编码
def MH(inpu):
    temp = '0'  #通常白游程开始 ,用于记忆所扫描的相同字符
    tempnum = 0     #记忆当前扫描序列的首字符位置
    code = ''       #存取编码结果
    if inpu[0] == '1':
        # 若开头为1,则为黑游程开始,需要在前面输出黑游程对应为0的码
        # print(MH_BLACK_63[0], end='')
        code += MH_BLACK_63[0]
        temp = '1'

    for num in range(len(inpu)):

        if inpu[num] == temp:
            # 如果当前字符和之前字符相同,则搜寻下一个字符,直到字符不同
            continue

        if num-tempnum < 64:
            # 相同字符格式小于64个情况下
            if temp == '1':
                # 如果为黑游程
                # print(MH_BLACK_63[num-tempnum], end='')
                code += MH_BLACK_63[num-tempnum]
            else:
                # 如果为白游程
                # print(MH_BAI_63[num-tempnum], end='')
                code += MH_BAI_63[num-tempnum]
        else:
            # 在相同字符大于64情况下,需要加组合基于码
            rank = int((num - tempnum)/64) - 1
            if temp == '1':
                # print(MH_BLACK_128[rank], end='')
                code += MH_BLACK_128[rank]
                # print(MH_BLACK_63[(num - tempnum) % 64], end='')
                code += MH_BLACK_63[(num - tempnum) % 64]
            else:
                # print(MH_BAI_128[rank], end='')
                code += MH_BAI_128[rank]
                # print(MH_BAI_63[(num - tempnum) % 64], end='')
                code += MH_BAI_63[(num - tempnum) % 64]
        # 更新信息
        temp = inpu[num]
        tempnum = num

    # 输出最后一串
    if num-tempnum + 1 < 64:

        if temp == '1':
            # print(MH_BLACK_63[num-tempnum+1], end='')
            code += MH_BLACK_63[num-tempnum+1]
        else:
            # print(MH_BAI_63[num-tempnum+1], end='')
            code += MH_BAI_63[num-tempnum+1]
    else:
        rank = int((num - tempnum+1)/64) - 1
        if temp == '1':
            # print(MH_BLACK_128[rank], end='')
            code += MH_BLACK_128[rank]
            # print(MH_BLACK_63[(num - tempnum+1) % 64], end='')
            code += MH_BLACK_63[(num - tempnum+1) % 64]
        else:
            # print(MH_BAI_128[rank], end='')
            code += MH_BAI_128[rank]
            # print(MH_BAI_63[(num - tempnum+1) % 64], end='')
            code += MH_BAI_63[(num - tempnum+1) % 64]
    return code


def Search(src, MH):
    # 用于判断数组中是否包含给定的字符串
    if src in MH:
        # return True
        return MH.index(src)
    else:
        return False

def output(number, char, code_trans):
    # 用于输出记录解码结果
    for i in range(number):
        # print(char, end='')
        code_trans += char
    return code_trans

def SearchAll(src, temp):
    # 用于判断在数组中是否有相同的字符出现
    a = 0
    if temp == '1':
        if src in MH_BLACK_63:
            a += 1
        if src in MH_BLACK_128:
            a += 1
    else:
        if src in MH_BAI_63:
            a += 1
        if src in MH_BAI_128:
            a += 1
    if a == 0:
        return True
    else:
        return False


# 解码
def MH_trans(code):
    code_trans = ''     # 记忆解码结果
    temp = '0'          # 记忆当前所扫描的游程类型
    tempnum = 0         # 记忆当前扫描序列的首字符位置
    if code[0:10] == MH_BLACK_63[0]:
        # 即黑游程为开始
        temp = '1'
        tempnum = 10
    for num in range(len(code)):
        if num < tempnum:
            # 即此时为黑游程开始,则前10个字符代表结尾码中黑游程对应的长度为0的码,可以直接忽略
            continue
        if SearchAll(code[tempnum:num], temp):
            continue
        if temp == '1':
            # 判断是否存在组合基于码,如果存在,则先输出组合基于码对应的解码,再继续遍历寻找结尾码并输出。否则直接输出结尾码
            if code[tempnum:num] in MH_BLACK_128:
                youchen_128 = Search(code[tempnum:num], MH_BLACK_128)
                code_trans = output(youchen_128 * 64 + 64, '1', code_trans)
                temp = '1'
                tempnum = num
            else:
                youchen_64 = Search(code[tempnum:num], MH_BLACK_63)
                code_trans = output(youchen_64, '1', code_trans)
                temp = '0'
                tempnum = num
        else:
            # 判断是否存在组合基于码,如果存在,则先输出组合基于码对应的解码,再继续遍历寻找结尾码并输出。否则直接输出结尾码
            if code[tempnum:num] in MH_BAI_128:
                youchen_128 = Search(code[tempnum:num], MH_BAI_128)
                code_trans = output(youchen_128 * 64 + 64, '0', code_trans)
                temp = '0'
                tempnum = num
            else:
                youchen_64 = Search(code[tempnum:num], MH_BAI_63)
                code_trans = output(youchen_64, '0', code_trans)
                temp = '1'
                tempnum = num

    #用于输出解码最后的结果,由于for循环的限制,无法对最后的字符串进行解码,故再对最后的字串需要解码一次
    num += 1
    if temp == '1':
        # 黑游程,编码中,由于是组合基于码+结尾码,或者直接为结尾码,故最后的码必定为结尾码,只需对结尾码进行生成即可
        youchen_64 = Search(code[tempnum:num], MH_BLACK_63)
        code_trans = output(youchen_64, '1', code_trans)

    else:
        # 白游程,编码中,由于是组合基于码+结尾码,或者直接为结尾码,故最后的码必定为结尾码,只需对结尾码进行生成即可

        youchen_64 = Search(code[tempnum:num], MH_BAI_63)
        # print(youchen_64)
        code_trans = output(youchen_64, '0', code_trans)

    return code_trans


def makejpg (binary):
    strjpg = []
    for i in range(binary.shape[0]):
        strjpg.append('')
        for j in range(binary.shape[0]):
            if binary[i][j] >= 200:
                strjpg[i] += '1'
            else:
                strjpg[i] += '0'

    # strjpg中,分别存取图像中的每一行数据
    code = []
    for i in range(binary.shape[0]):
        code.append(MH(strjpg[i]))

    code_trans = []
    for i in range(binary.shape[0]):
        code_trans.append(MH_trans(code[i]))
        if len(code_trans[i]) != 256:
            print(str(i)+':'+str(len(code_trans[i])))
    # print(strjpg[228])
    # print(code[228])
    # print(code_trans[99])
    # print(MH(code_trans[99]))
    binary_trans = []
    for i in range(binary.shape[0]):
        temp = []
        # print(i)
        for j in range(len(code_trans[i])):
            # print(j)
            if code_trans[i][j] == '1':
                temp.append(255)
            else:
                temp.append(0)
        binary_trans.append(temp)

    return code, code_trans, binary_trans



def MH_trans_in_MR(inpu, youchen, boolshouwei):
    # 用于在MR解码中的MH解码,此处解码较为特殊,每次只解一种字符,并且需要验证判断是否大于64位。
    # 同时,如果检索到组合基于码,还需要继续检索结尾码,并且该处属于同义词MH解码
    # 因此,要先判断是否存在组合基于码,如果存在,则需要继续搜索剩余的结尾码
    # 第二个返回值代表是否匹配到序列,第三个返回值代表是否需要继续搜索结尾码-
    code_trans = ''
    if youchen == '0':

        if inpu in MH_BAI_128:
            return output(MH_BAI_128.index(inpu) * 64 + 64, youchen, code_trans), True, True, False

        if inpu in MH_BAI_63:
            return output(MH_BAI_63.index(inpu), youchen, code_trans), True, False, False

    if youchen == '1':
        # 当其为黑游程开始时,由于MH编码的特性,在黑游程开始前会加入一串字符MH_BLACK_63[0]表示黑游程开始,但这串字符并无意义,故需要去掉
        # 这里可以考虑,当其搜到到MH_BLACK_63[0]时,需要继续进行一次搜索,但是当只有64个1像素时,此时依然后会搜索到MH_BLACK_63[0],并且不需要继续搜索,
        # 因此,这里只能通过增加返回值,来表示是最前面的MH_BLACK_63[0]还是最后的MH_BLACK_63[0]默认为TRUE,只有经过128位的查找之后才会变为FALSE
        if inpu in MH_BLACK_128:
            return output(MH_BLACK_128.index(inpu) * 64 + 64, youchen, code_trans), True, True, False

        if inpu in MH_BLACK_63:
            if boolshouwei == True:
                if inpu == MH_BLACK_63[0]:
                    return output(MH_BLACK_63.index(inpu), youchen, code_trans), True, True, False
            return output(MH_BLACK_63.index(inpu), youchen, code_trans), True, False, False

    return 0, False, 0, boolshouwei




# print(makejpg())

# if __name__ == "main":
#     # 测试
#     # inpu = input('输入传输的内容:(0代表白游程,1代表黑游程,从白游程开始) ')
#
#     # 测试用例1
#     # inpu =''
#     # for i in range(110):
#     #     inpu += '0'
#     # inpu +='101010101'
#     # for i in range(200):
#     #     inpu += '1'
#
#     # 测试用例2
#     # inpu = '11001011010001001110001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000'
#     inpu = '11100'
#     code = MH(inpu)
#     print(code)
#     code_trans = MH_trans(code)
#     print(code_trans)








检验前缀码的方式:(还有更新数组,这样直接复制就行)

# 更新码表

MH_BAI_63 = ["00110101","000111","0111","1000","1011","1100","1110","1111","10011","10100","00111","01000","001000","000011","110100","110101","101010","101011","0100111","0001100","0001000","001011","0000011","0000100","0101000","0101011","0010011","0100100","0011000","00000010","00000011","00011010","00011011","00010010","00010011","00010100","00010101","00010110","00010111","00101000","00101001","00101010","00101011","00101100","00101101","00000100","00000101","00001010","00001011","01010010","01010011","01010100","01010101","00100100","00100101","01011000","01011001","01011010","01011011","01001010","01001011","00110010","00110011","00110100"]
MH_BLACK_63 = ["0000110111","010","11","10","011","0011","0010","00011","000101","000100","0000100","0000101","0000111","00000100","00000111","000011000","0000010111","0000011000","0000001000","00001100111","00001101000","00001101100","00000110111","00000101000","00000010111","00000011000","000011001010","000011001011","000011001100","000011001101","000001101000","000001101001","000001101010","000001101011","000011010010","000011010011","000011010100","000011010101","000011010110","000011010111","000001101100","000001101101","000011011010","000011011011","000001010100","000001010101","000001010110","000001010111","000001100100","000001100101","000001010010","000001010011","000000100100","000000110111","000000111000","000000100111","000000101000","000001011000","000001011001","000000101011","000000101100","000001011010","000001100110","000001100111"]
# 组合基于码
MH_BAI_128 = ["11011","10010","010111","0110111","00110110","00110111","01100100","01100101","01101000","01100111","011001100","011001101","011010010","011010011","011010100","011010101","011010110","011010111","011011000","011011001","011011010","011011011","010011000","010011001","010011010","011000","010011011"]
MH_BLACK_128 = ["0000001111","000011001000","000011001001","000001011011","000000110011","000000110100","000000110101","0000001101100","0000001101101","0000001001010","0000001001011","0000001001100","0000001001101","0000001110010","000000111001","0000001110100","0000001110101","0000001110110","0000001110111","0000001010010","0000001010011","0000001010100","0000001010101","0000001011010","0000001011011","0000001100100","0000001100101"]
# TRL = ['00110101', '000111', '0111', '1000', '1011', '1100', '1110', '1111', '10011', '10100', '00111', '01000', '001000', '000011', '110100', '110101', '101010', '101011', '0100111', '0001100', '0001000', '001011', '0000011', '0000100', '0101000', '0101011', '0010011', '0100100', '0011000', '00000010', '00000011', '00011010', '00011011', '00010010', '00010011', '00010100', '00010101', '00010110', '00010111', '00101000', '00101001', '00101010', '00101011', '00101100', '00101101', '00000100', '00000101', '00001010', '00001011', '01010010', '01010011', '01010100', '01010101', '00100100', '00100101', '01011000', '01011001', '01011010', '01011011', '01001010', '01001011', '00110010', '00110011', '00110100']
MH_BAI_63[21] = '0010111'
MH_BAI_63[37] = '00010110'
MH_BAI_63[62] = '00110011'
MH_BAI_128[13] = '101010011'
MH_BLACK_128[0] = '0000001111'
MH_BLACK_128[1] = '00011001000'
MH_BLACK_128[14] = '0000001110011'

print('MH_BAI_63 = '+str(MH_BAI_63))
print('MH_BLACK_63 = '+str(MH_BLACK_63))
print('MH_BAI_128 = '+str(MH_BAI_128))
print('MH_BLACK_128 = '+str(MH_BLACK_128))


# 检验是否为前缀码
def jianyanqianzhui(MH):
    for i in range(len(MH)):
        src = MH[i]
        # 验证src是否是MH[i]的前缀
        for j in range(len(MH)):
            if i != j:
                if MH[j][:len(src)] == src:
                    print(str(i)+':'+src+','+str(j)+':'+MH[j])
print('MH_BAI_63')
jianyanqianzhui(MH_BAI_63)
print('MH_BAI_128')
jianyanqianzhui(MH_BAI_128)
print('MH_BLACK_63')
jianyanqianzhui(MH_BLACK_63)
print('MH_BLACK_128')
jianyanqianzhui(MH_BLACK_128)

MR编码:


from MH import MH, MH_trans, SearchAll, MH_trans_in_MR
# 上面两个函数分别是指 MH编码 和 MH解码

def bianma(a0, a1, a2, b1, b2, inpu2, code):
    # 通过各个元素的位置,输出编码以及a0的位置
    if a1 > b2:
        # print('0001', end=' ')
        code += '0001'
        return b2, code
    else:
        a1b1 = a1 - b1
        if a1b1 == 0:
            # print('1', end=' ')
            code += '1'
            return a1, code
        elif a1b1 == 1:
            # print('011', end=' ')
            code += '011'
            return a1, code
        elif a1b1 == 2:
            # print('000011', end=' ')
            code += '000011'
            return a1, code
        elif a1b1 == 3:
            # print('0000011', end=' ')
            code += '0000011'
            return a1, code
        elif a1b1 == -1:
            # print('010', end=' ')
            code += '010'
            return a1, code
        elif a1b1 == -2:
            # print('000010', end=' ')
            code += '000010'
            return a1, code
        elif a1b1 == -3:
            # print('0000010', end=' ')
            code += '0000010'
            return a1, code
        else:
            # 此时对应a1b1之间的距离大于3
            # print('001' + MH(inpu2[a0:a1]) + MH(inpu2[a1:a2]), end=' ')

            # 此时,如果以白游程开始,并且判定为水平模时,由于a0为-1位置,则获取不到该元素,a0实际代表白游程。故这里修改为当a0为-1是,前一段编码为0+0到a1位置的元素进行编码
            if a0 == -1:
                code += '001' + MH('0'+inpu2[:a1]) + MH(inpu2[a1:a2])
            else:
                code += '001' + MH(inpu2[a0:a1]) + MH(inpu2[a1:a2])
            return a2, code

def search(inpu, a1):
    # 在inpu序列中,找与a1的下一个迁移像素a2,a2与a1颜色相反
    # 迁移元素必须是由黑变白或者由白变黑的第一个元素
    if a1 == -1:
        # 即对应第一个为白元素的情况下,才会执行这句
        a1 = 0

    if a1 == len(inpu):
        return len(inpu)

    a2 = len(inpu)

    temp = inpu[a1]
    # print('search开始' + ',a1:' + str(a1)  + ',temp:' + temp)
    for i in range(a1, len(inpu)):
        if inpu[i] != temp:
            # print('i:'+str(i)+',a1:' + str(a1) + ', inpu[i]:' + inpu[i]+',temp:'+temp)
            a2 = i
            break

    return a2

def searchcankao(inpu1, inpu2, a1):
    # inpu1代表参考行
    # inpu2代表编码行
    if a1 == len(inpu2):
        return len(inpu2)
    a2 = len(inpu1)
    temp = inpu2[a1]

    for i in range(a1+1, len(inpu1)):
        # 由于迁移元素表示由黑变白或由白变黑的第一个元素,因此不能单纯的从a1开始只找与a1不同的元素
        # 这里可以考虑从a1-1出发遍历,如果某元素与a1对应的元素不同,且与其上一个元素也不同,则可以认定为迁移元素
        # 即先看上一个元素和当前元素颜色是否不同,若不同再看a1对应的颜色和当前元素颜色是否不同
        if inpu1[i-1] != inpu1[i]:
            if temp != inpu1[i]:
                a2 = i
                break
    return a2






# 通常扫描行第一个元素为白游程,若为黑游程则让a0为第一个元素之前

# inpu1 代表参考行
# inpu2 代表编码行
def MR(inpu1,inpu2):
    a0 = -1          # a0是假想的白元素,将a0置于第一个元素之前
    code = ''
    if inpu2[0] == '1':
        # 即第一个为黑游程的情况下
        a1 = 0
        a2 = search(inpu2, a1)
        i = 0
        for i in range(len(inpu1)):
            if inpu1[i] == '1':
                break
        b1 = i
        # 防止参考行均为0情况下,找不到b1的位置
        b2 = search(inpu1, b1)
        # print('a0:' + str(a0) + ',a1:' + str(a1) + ',a2:' + str(a2) + ',b1:' + str(b1) + ',b2:' + str(b2))
        a0, code = bianma(a0, a1, a2, b1, b2, inpu2, code)
    else:
        # 即对应第一个为白元素的情况下
        a1 = search(inpu2, a0)
        a2 = search(inpu2, a1)
        i = 0
        for i in range(len(inpu1)):
            if inpu1[i] == '1':
                break
        b1 = i
        # 防止参考行均为0情况下,找不到b1的位置
        b2 = search(inpu1, b1)
        # print('a0:' + str(a0) + ',a1:' + str(a1) + ',a2:' + str(a2) + ',b1:' + str(b1) + ',b2:' + str(b2))
        a0, code = bianma(a0, a1, a2, b1, b2, inpu2, code)
    while 1:

        if a0 == len(inpu2):
            # 结束编码行编码
            break
        # 更新过程
        a1 = search(inpu2, a0)
        a2 = search(inpu2, a1)
        b1 = searchcankao(inpu1, inpu2, a0)
        # print('b1b2开始')
        b2 = search(inpu1, b1)
        # print('a0:' + str(a0) + ',a1:' + str(a1) + ',a2:' + str(a2) + ',b1:' + str(b1) + ',b2:' + str(b2))
        a0, code = bianma(a0, a1, a2, b1, b2, inpu2, code)
    return code
    # code 代表编码行的编码









def output(num, youchen):
    # num代表输出的数量,youchen代表当前输出是0还是1
    code_trans = ''
    for i in range(num):
        code_trans += youchen
    return code_trans

def searchcode(inpu1, src, a0, b1, b2, code_trans, youchen):
    # inpu1代表参考行,src代表当前选取的子序列,
    # 返回值:
    # code_trans代表复原的码,第二个代表游程是否改变,第三个代表是否搜索完毕
    # 通过搜索码字,确定a1、a2的位置
    if src == '1':
        # 对应a1等于b1的情况,
        code_trans += output(b1 - a0, youchen)
        return code_trans, True, True
    elif src == '011':
        code_trans += output(b1 + 1 - a0, youchen)
        return code_trans, True, True
    elif src == '000011':
        code_trans += output(b1 + 2 - a0, youchen)

        return code_trans, True, True
    elif src == '0000011':
        code_trans += output(b1 + 3 - a0, youchen)
        return code_trans, True, True
    elif src == '010':
        code_trans += output(b1 - 1 - a0, youchen)
        return code_trans, True, True
    elif src == '000010':
        code_trans += output(b1 - 2 - a0, youchen)
        return code_trans, True, True
    elif src == '0000010':
        code_trans += output(b1 - 3 - a0, youchen)
        return code_trans, True, True
    elif src == '0001':
        code_trans += output(b2 - a0, youchen)
        #这是游程不发生转变
        return code_trans, False, True
    else:
        return code_trans, False, False
    # 对于水平模的情况,直接在父函数中判别


def bianmaa1b1(a1,b1):
    # 初步判断
    code = ''
    a1b1 = a1 - b1
    if a1b1 == 0:
        # print('1', end=' ')
        code += '1'
        return code
    elif a1b1 == -1:
        # print('010', end=' ')
        code += '010'
        return code
    elif a1b1 == -2:
        # print('000010', end=' ')
        code += '000010'
        return code
    elif a1b1 == -3:
        # print('0000010', end=' ')
        code += '0000010'
        return code
    else:
        # 此时对应a1b1之间的距离大于3
        # print('001' + MH(inpu2[a0:a1]) + MH(inpu2[a1:a2]), end=' ')
        code += '001'
        return code

def youchen_change(youchen):
    # 该youchen函数
    if youchen == '0':
        return '1'
    else:
        return '0'

def searchyouchen(inpu, a0, youchen):
    # 得到inpu下一个迁移像素的位置,该迁移像素与youchen的颜色相反
    b1 = len(inpu)
    for i in range(a0+1, len(inpu)):
        if inpu[i-1] != inpu[i]:
            if inpu[i] != youchen:
                b1 = i
                break
    return b1

# 解码




def MR_trans(inpu1,code):
    # 通过搜索码字,确定a1、a2的位置,结合a0的位置,从而确定0,1的个数
    # 解码中,需要记录当前a0的位置(即以及解码好了的的字符的长度),b1、b2的位置由ao的位置获得
    # 首先要判断,该行是由白游程开始还是黑游程开始,具体的判断方法是:通过读取前面的码字,判断编码的模式,从而得到a1和b1的相对位置关系,而由参考行可以得到b1的位置,从而测定得到a1的位置
    #   若a1的位置为0,代表由黑游程开始,若a1位置不为0,代表由白游程开始。
    #   反向考虑,当且仅当a1位置为0时,为黑游程开始,基于此,可以简化运算,即得到b1的位置后,假定a1的位置为0,那么对于其相对位置关系可以得到的模式以及对应的码字,再判断改行码字前面与其是否匹配,
    #   若匹配,则为黑游程开始,若不匹配,则必定为白游程开始。
    #   在该假设的前提下,a1<=b1,则可以将其判断的模式范围缩小
    youchen = '0'
    tempnum = 0  # 记忆当前判断码字的初始位置
    code_trans = ''
    a0 = -1
    i = 0
    for i in range(len(inpu1)):
        if inpu1[i] == '1':
            break
    b1 = i
    b2 = search(inpu1, b1)
    # a1 = 0
    # a1b1 = bianmaa1b1(a1, b1)
    # if code[0:len(a1b1)] == a1b1:
    #     # 即此时对应为开始为黑游程的情况
    #     youchen = '1'
    #     print('qwe')

    i = 1
    while a0 < len(inpu1):

        # print(src)
        src = code[tempnum:i]
        # print('src:'+src+',a0:'+str(a0)+',a0:'+str(a0)+',b1:'+str(b1)+',b2:'+str(b2)+',code_trans:'+str(code_trans) + ',youchen:'+str(youchen))
        code_trans, boolyouchen, boolsuccess = searchcode(inpu1, src, a0, b1, b2, code_trans, youchen)
        if boolsuccess == False :
            if src == '001':
                # 此时代表为水平模,需要进行两次MH编码
                # 由于这里MH编码不是简单的MH解码,需要是固定白或者黑游程确定
                # 第一次搜索
                j = i + 2
                # print(i)
                while 1:
                    srcmh = code[i: j]
                    # print(str(srcmh)+','+youchen)
                    boolshouwei = True
                    out, bool1, bool2, boolshouwei = MH_trans_in_MR(srcmh, youchen, boolshouwei)
                    # 第二个返回值代表是否匹配到序列,第三个返回值代表是否需要继续搜索结尾码
                    if not bool1:
                        j += 1
                        continue
                    else:
                        # 此时代表成功搜索到字符
                        code_trans += out
                        if bool2:
                            # 此时代表需要继续搜索结尾码
                            i = j
                            j = i + 2
                            continue
                        else:
                            break

                # 第二次搜索
                i = j
                j = i + 2
                while 1:
                    srcmh = code[i: j]
                    # print(srcmh+','+youchen_change(youchen))
                    boolshouwei = True
                    out, bool1, bool2, boolshouwei = MH_trans_in_MR(srcmh, youchen_change(youchen), boolshouwei)
                    # 第二个返回值代表是否匹配到序列,第三个返回值代表是否需要继续搜索结尾码
                    if not bool1:
                        j += 1
                        continue
                    else:
                        # 此时代表成功搜索到字符
                        code_trans += out
                        if bool2:
                            # 此时代表需要继续搜索结尾码
                            i = j
                            j = i + 2
                            continue
                        else:
                            break

                tempnum = j
                i = tempnum + 1
                a0 = len(code_trans) - 1
                b1 = searchyouchen(inpu1, a0, youchen)
                b2 = search(inpu1, b1)
                continue
            else:
                # 此时对应当前码字未搜索到需要的码
                i = i + 1
                a0 = len(code_trans) - 1
                continue
        else:
            # 此时对应搜索编码成功的情况
            if boolyouchen == True:
                # 此时游程发生改变
                youchen = youchen_change(youchen)
            a0 = len(code_trans)-1
            b1 = searchyouchen(inpu1, a0, youchen)
            b2 = search(inpu1, b1)
            tempnum = i
            i = i + 1
            # print(a0)

    return code_trans[1:]


def makejpgMR(binary):
    strjpg = []
    for i in range(binary.shape[0]):
        strjpg.append('')
        for j in range(binary.shape[0]):
            if binary[i][j] >= 200:
                strjpg[i] += '1'
            else:
                strjpg[i] += '0'

    # strjpg中,分别存取图像中的每一行数据
    code = []
    code.append(MH(strjpg[0]))      # 第一行进行MH编码
    for i in range(1, binary.shape[0]):
        code.append(MR(strjpg[i-1], strjpg[i]))         # 以i-1行为参考编i行


    code_trans = []
    code_trans.append(MH_trans(code[0]))        # 第一行进行MH解码
    for i in range(1, binary.shape[0]):
        code_trans.append(MR_trans(code_trans[i-1], code[i]))        # 以前一行解出来的码为参考行,对下一行进行解码
        if code_trans[i] != strjpg[i]:
            print(str(i) + ':' + str(len(code_trans[i])))
            print(strjpg[i-1])
            print(strjpg[i])
            print(code[i])
            print(code_trans[i])
    binary_trans = []
    for i in range(binary.shape[0]):
        temp = []
        # print(i)
        for j in range(len(code_trans[i])):
            # print(j)
            if code_trans[i][j] == '1':
                temp.append(255)
            else:
                temp.append(0)
        binary_trans.append(temp)

    return code, code_trans, binary_trans


# if __name__ == "main":
#     # inpu1 = '001011101001010000'  # 参考行
#     # inpu2 = '000101101011010000'  # 编码行
inpu1 = ''  # 参考行
inpu2 = ''  # 编码行
inpu1 = '0000000000000011000000000000011000000000000000000000000000011100000000011000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000110000000000000000000000000000000'  # 参考行
inpu2 = '0000000000000011000000000000011000000000000000000000000000011000000000011100001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101000111000000000000000000110000000000000000000000000000000'  # 编码行
# code = MR(inpu1, inpu2)
# print(code)
#
# print(MR_trans(inpu1, code))

测试文件(图像测试)


from MH import MH, MH_trans, makejpg
from MR import MR, MR_trans, makejpgMR
import cv2
import numpy as np

# 读取图片
# # def change2binary(img):
#     img = cv2.imread("lina.jpg")
#     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#     blocksize = 11
#     C = -40
#     binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blocksize, C)
#     cv2.imshow('binary', binary)
# cv2.imwrite('linabinary.jpg',binary)


def getlen(binary):
    sum = 0
    for i in range(len(binary)):
        sum += len(binary[i])
    return sum


binary = cv2.imread('lina.jpg', cv2.IMREAD_GRAYSCALE)
# binary = cv2.imread('linabinary.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('binary', binary)
# code代表编码,binary_trans代表恢复后的图像

print('原图像编码所占空间:'+str(getlen(binary)))

# MH
codeMH, code_transMH, binary_transMH = makejpg(binary)
binary_transMH = np.array(binary_transMH, np.uint8)
cv2.imshow('MH', binary_transMH)
print('MH编码所占空间:'+str(getlen(codeMH))+'压缩比'+str(getlen(binary)/getlen(codeMH)))

# MR
codeMR, code_transMR, binary_transMR = makejpgMR(binary)
binary_transMR = np.array(binary_transMR, np.uint8)
cv2.imshow('MR', binary_transMR)
print('MR编码所占空间:'+str(getlen(codeMR))+'压缩比'+str(getlen(binary)/getlen(codeMR)))

cv2.waitKey(0)

测试结果:


原图像

 

MH编码后在解码恢复后的图像

MR编码后在解码恢复后的图像

参考资料:

老师的PPT!!!

[1] 李薇,王胜兵,艾小川. MR码编码与译码算法研究及仿真实验[J]. 计算机与数字工程,2010,38(11):55-57,64. DOI:10.3969/j.issn.1672-9722.2010.11.015.

[2] 李薇,沈静,艾小川. MR编码在传真图像编码中的仿真应用[J]. 计算机与数字工程,2010,38(2):121-123. DOI:10.3969/j.issn.1672-9722.2010.02.034.

二维编码MR编码方式 - 豆丁网二维编码MRhttps://www.docin.com/p-7880995.html游程编码及MH编码 - 百度文库https://wenku.baidu.com/view/b78636fdc0c708a1284ac850ad02de80d5d8065b.htmlhttps://web.archive.org/web/20020628195336/http://www.netnam.vn/unescocourse/computervision/104.htmhttps://web.archive.org/web/20020628195336/http://www.netnam.vn/unescocourse/computervision/104.htmhttps://zh.wikipedia.org/wiki/MH%E7%BC%96%E7%A0%81https://zh.wikipedia.org/wiki/MH%E7%BC%96%E7%A0%81

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

logiclj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值