最近老师布置了要求实现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.htm
https://web.archive.org/web/20020628195336/http://www.netnam.vn/unescocourse/computervision/104.htmhttps://zh.wikipedia.org/wiki/MH%E7%BC%96%E7%A0%81
https://zh.wikipedia.org/wiki/MH%E7%BC%96%E7%A0%81