栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

RLE行程编码python

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

RLE行程编码python

该编码的主要思路是:加载图片后通过PIL的Image库中的getpixel() 方法得到该图片的所有像素RGB颜色,将其转为二进制后开始RLE编码压缩,然后把编码结果保存到json文件中。以上是完整编码部分。而后就开始解码-将二进制转化为十进制并通过putpixel() 将十进制RGB像素转化为原图。我在这里使用的照片是bcm.jpg,大家可以按照自己的喜好加载不同的图片,并需要把加载图片和代码保存在一个文件夹中

from PIL import Image
import json,re
img=Image.open("bcm.jpg")


#part one: encode
def img_pixel(img):# obtain all pixelcolor from this picture
    lst=[]
    width,height=img.size
    for j in range(height):
        for i in range(width):
            lst.append(img.getpixel((i,j)))
    return lst

def bytes(num):# decimal to binary
    binary1=''
    result=''
    cnt=1
    if num<0 or num>int(num):
        print("error:not an integer")
    while True:
        if num%2==0:
            binary1+="0"
        else:
            binary1+="1"
        if num//2==0:
            break
        num//=2
        cnt+=1
    for i in range(cnt):
        result+=binary1[-(i+1)]
    return int(result)

到这里就已经完成了原图->十进制RGB像素列表->二进制RGB像素列表(列表中一共有310*310个元素,其实就是原图的面积多大,元素就有多少个,每个元素都是一个像素单位),其他的地方只要有相关基础就能理解的很轻松

def encode_while(lst):#RLE_compression
    encoded_items=[]
    i=0
    while i 

以上一段是RLE压缩-实现将连续重复的像素颜色值的次数进行统计,如果把这个次数记成num,就有:(num,像素颜色值)。举个简单的例子:这里有一个一位图的图片表示为:111100000111111,可以写成:(4,1),(5,0),(6,1),然后再把4,5,1转为二进制,让我们来算算编码后省了多少空间。。。省了三比特。虽然看起来很少,但是一旦位图变成了24,他就能省下很多的空间。因为位图越多,就能够在省相同数量的像素时省下更多的存储单位。但是该压缩的问题也显而易见-他不适合用来压缩字符串,因为字符串连续相同的字母出现的次数很少,像 i like programming, 除了m能写成 (2,m) 以外,其他的相对压缩前都多占用空间。

在上面,为了格式化,也让我好计算相对压缩前省下的存储空间,我把计数变量num给二进制化了

#part1 main program
lst_bin=[]#this part calculation:RGB_decimal->RGB_binary->RLE_format
lst_bin2=[]
for j in img_pixel(img):
    lst_color = []
    for i in j:
        lst_color.append(bytes(i))
    lst_bin.append(tuple(lst_color))
lst_bin2=encode_while(lst_bin) #compressed binary list

string=""#this part calc:space occupied and comparsion
string2=""
for a in lst_bin:#casting-easier to calculation
    for b in a:
        string=string+str(b)
for m in lst_bin2:
    for n in m:
        string2=string2+str(n)

def cvt(binary):#bit and bytes rate conversion
    bytes_=len(binary)//8
    bits=len(binary)%8
    return f"{bytes_} bytes {bits} bits"
op=lambda d1,d:round(len(d1)/(len(d1)+len(d)),1)*100 #space saving calculation

print(#output the space saved
    f"it takes {cvt(string)} before comp, and
 {cvt(string2)} after comp, save {op(string2,string)}% space"
)
with open("bcm_bin_code.json","w") as f:
    json.dump(lst_bin2,f)       

以上是主程序,主要是执行压缩,后面才是计算压缩后省下的空间。其中有几行看起来好像很复杂,其实就是想省行数,把他分解了来看没有什么。cvt function中我为了简化代码使用字符串运算,最后再返回一个整数值。

我在这里稍微解读一下这个主程序的第一段,因为其中的方法我下面还会用到一次。for j in img_pixel(img)按顺序输出原图的所有的像素RGB,每一个RGB像素块是一个元组,里面有三个数值分别是红值,绿值和蓝值,每次用for循环遍历元组并把每个数值都用bytes()函数给他二进制化,然后用列表lst_color来接收他们,每次遍历完后都把元组化的lst_color列表作为一个元素存入lst_bin中,然后lst_color=[]!重置列表为空,这样就又能载入另外一组被二进制化的数值了。

#part2:decode
#method:binary_code->decimal_code->original_picture
def to_dec(bin):#binary->decimal:
    R=0
    b=str(bin)
    for i in range(len(b)):
        R=R+int(b[i])*(2**(len(b)-1-i))
    return R

# part2 main program
lst_dec=[]
for q in lst_bin:#binary->RGB_deciaml
    temp=[]
    for p in q:
        temp.append(to_dec(p))
    lst_dec.append(tuple(temp))

x,y=img.size#this part generates the original_picture
img_=Image.new("RGB",(x,y))
for o in range(0,y):
    for t in range(0,x):
        img_.putpixel((t,o),lst_dec[o*x+t])
img_.show()

至此,整个压缩包括解压的程序已经展现完毕,这一段的解压的代码将RLE 二进制的列表转化为十进制RGB,并用接收两个值(像素要插入的坐标和像素数值)的putpixel()方法结合嵌套循环将像素数值还原成照片。其中那个嵌套for循环可能会令人感到些许迷惑。他其实就是把列表解成数列RGB数条,然后每一个内层循环都将一行RGB数条转换成对应的一行实实在在的图片像素色块。其中o,t是循环变量,一个是循环原图长度次也就是外层循环,一个是宽度次即内层循环。

让我们举个例子(因为虽然用抽象的术语是把事情解释清楚了,但是不直观,很难理解),这里有一张长2像素,宽3像素的图片被getpixel()方法按顺序分解成了一张RGB数值列表,可以理解成是他这个图片在横向被剪成了两条等宽的纸条然后按顺序拼接成了一条长方形,每个像素色块是一个单位。那显而易见的,列表里有2*3也就是6个像素色块。假设这个列表为:[(139,69,19),(160,82,45),(139,69,19),(160,82,45),(139,69,19),(160,82,45)] (对应的人话就是:深棕,褐色,深棕,褐色...)。为了还原图片,我们需要把它这么排列:

(139,69,19),(160,82,45),(139,69,19)

(160,82,45),(139,69,19),(160,82,45)

这不就是一个宽3像素,高2像素的图片么?当然,我们不用担心这样排列得出的结果会和原图不一致,因为原图本身就是按照这个方法被拉成一条列表的,我们只是按照顺序有黏回来而已。然后现在我们只需要确定嵌套循环次数,之后再用putpixel()方法把这里每个RGB值转化成对应颜色,就得到原图了。

那么我们开始策划:循环多少次putpixel()方法才能把这六个数值还原成六个色块呢?6次嘛!我们需要使用嵌套循环(具体原因一会儿会说明),外层循环次数对应的是两行的高度(y=2),也就是两次,每一次外层循环时都执行三次内层循环,就是宽度的次数(x=3)。循环多少次这个问题我们解决了,那我们现在还需要给putpixel()方法两个参数,让人家能找到正确的位置把正确的色块给我们贴上去,贴的位置就是(t,o)。。。那为啥呢?python 图片的坐标(0,0)设在左上角,也就是说:这个列表中第二个RGB数值(第一行第二列)的坐标应该是(0,1),第三个是(0,2),第四个(第二行第一列)是(1,0),然后是(1,1),(1,2)。看看这六个坐标(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),是不是很眼熟?对,这就是二层嵌套两个循环变量的变化值。证据确凿,坐标就是(t,o)。有了坐标,RGB颜色的选择也就轻而易举,图片色块的位置对应的RGB列表索引就分别是:0(行)*3(列)+0,0*3+1,0*3+2,1*3+0,1*3+1,1*3+2。推广以下就是:o*x+t

至此,程序讲解完毕。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983801.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号