图像可变游程之混乱代码
图像可变游程之混乱编码
这里,对我的自画像代码作一个简要解释。自画像代码实际上是一个解码器。包括两个部分:
- 图像的可变游程编码(varied length coding)
- 混乱编码(obfuscated coding)
最关键部分就是那个码表了。这里介绍如何生成一个可变游程之混乱编码后码表。
可变游程编码(VLC)
实际上,我的自画像采用了一个简单的游程编码。其基本原理如下:
- 采用最简单的二值图像游程编码,只需要交替数0,1的个数
- 偶数字节表示0的长度,奇数字节表示1的长度
- 采用ASCII码的字符表示长度,那么实际字节非原始长度编码,而是可显示字符加上0或1的长度所对应的字符
混乱编码
上一节介绍了VLC编码方法,但是有一个问题,每个字节表示的长度是有限的(由于可选用的可显示字符有限)。我们假设其为M。以一个0长度为L(L〉M)的编码为例,由于VLC奇偶分别编码的原因,由于L超过M,所以要先编一个长度为M的偶数字符,然后编一个长度为0的奇数字符,然后再编一个长度为(L-M)的偶数字符。
值得注意的是,表示长度为0的字符,可以从多个字符中随机选择,这就是混乱编码的由来。
参考代码
可以简单用如下编码器生成一个二值bmp图像的可变游程之混乱编码后的字符表了。
int gen_bmp_2bit_vlc_tbl(char *img, FILE *fp) {
int i, j, k;
int idx;
int cnt_bit_flag; // 0: count bit 0 run-length; 1: count bit 1 run-length
int force_cnt_bit_flag;
int bits_1, bits_0;
int max_run_length;
unsigned char c[16];
// at first, count bit 0
cnt_bit_flag = 0;
bits_0 = 0;
bits_1 = 0;
max_run_length = 0;
force_cnt_bit_flag = FORCE_DONE;
idx = 0;
for (i=0; i<H; i++) {
fseek(fp, -(i+1)*W/8, SEEK_END);
fread(&c, sizeof(unsigned char), W/8, fp);
for (j=0; j<W/8; j++) {
for (k = 0; k < 8; k++) {
if (force_cnt_bit_flag == FORCE_0) {
cnt_bit_flag = 0;
assert(bits_1 > 0);
printf("%c", img[idx++] = bits_1 + MIN_ASCII);
if (bits_1 > max_run_length)
max_run_length = bits_1;
bits_1 = 0;
force_cnt_bit_flag = FORCE_DONE;
bits_0 = 0;
}
else if (force_cnt_bit_flag == FORCE_1) {
cnt_bit_flag = 1;
assert(bits_0 > 0);
printf("%c", img[idx++] = bits_0 + MIN_ASCII);
if (bits_0 > max_run_length)
max_run_length = bits_0;
bits_0 = 0;
force_cnt_bit_flag = FORCE_DONE;
bits_1 = 0;
}
if (c[j] & 0x80) {
if (cnt_bit_flag == 0) {
cnt_bit_flag = 1;
if (bits_0 <= 0)
printf("%c", img[idx++] = (rand() % (MIN_ASCII - OBF_ASCII + 1) + OBF_ASCII));
else
printf("%c", img[idx++] = bits_0 + MIN_ASCII);
if (bits_0 > max_run_length)
max_run_length = bits_0;
bits_0 = 0;
}
bits_1++;
if (bits_1 >= MAX_RUN_LENGTH) {
// force change
force_cnt_bit_flag = FORCE_0;
}
}
else {
if (cnt_bit_flag == 1) {
cnt_bit_flag = 0;
if (bits_1 <= 0)
printf("%c", img[idx++] = (rand() % (MIN_ASCII - OBF_ASCII + 1) + OBF_ASCII));
else
printf("%c", img[idx++] = bits_1+MIN_ASCII);
if (bits_1 > max_run_length)
max_run_length = bits_1;
bits_1 = 0;
}
bits_0++;
if (bits_0 >= MAX_RUN_LENGTH) {
// force change
force_cnt_bit_flag = 1;
}
}
c[j] = c[j] << 1;
}
}
}
// force the last out
if (bits_0 != 0) {
printf("%c\n", img[idx++] = bits_0 + MIN_ASCII);
if (bits_0 > max_run_length)
max_run_length = bits_0;
bits_0 = 0;
}
else if (bits_1 != 0) {
printf("%c\n", img[idx++] = bits_1 + MIN_ASCII);
if (bits_1 > max_run_length)
max_run_length = bits_1;
bits_1 = 0;
}
return idx;
}