本脚本适合于压缩感知的研究者,将自己的算法与JPEG2000进行比较,批量得出结果。
具体见我的github:compressed_sensing-batch-JPEG2000-kakadu-PSNR-SSIM
压缩感知(CS)是一类图像压缩重建的算法,其流程为:
编码后保存的数据为经过熵编码的测量值y。
总压缩倍数R为:
R = c r ∗ 8 b ∗ S R=cr*\frac{8}{b}*S R=cr∗b8∗S
其中cr为测量率(原图与测量值的数据数量比例,比如压缩20倍则cr为20),b为量化比特,S为测量值y的熵编码倍数。
熵编码算法主要为算术编码和霍夫曼编码,但不同的实现方式效率有所区别,他们的最终目标都是达到香农极限,在这种情况下,压缩倍数R为:
R ′ = c r ∗ 8 e n t r o p y o f y ′ {R}'=cr*\frac{8}{entropy\;of\;{y}'} R′=cr∗entropyofy′8
其中 y ′ {y}' y′为量化后的测量值。
这是理想的情况,实际达不到这么高的压缩倍数。本脚本采用了这种方式,避免了复杂的熵编码的实现,但是使得效果偏高,需要注意。
常用的JPEG2000软件是kakadu,其使用方式见我的另一篇博文:kakadu——JPEG2000图像压缩软件的安装和使用
而kakadu只能一张一张得进行压缩和解压,如果需要统计一批图像的数据,就会很麻烦,本脚本解决这个问题。
文件目录:
orig:原图文件夹,以orig_%d.bmp命名。
represent:kakadu得到的压缩文件夹。
recon:kakadu得到的重建图文件夹,以recon_%d.bmp命名。
注:图像格式支持:bmp,jpg,tif,png等常见格式,但orig和recon文件夹内的图像格式必须是同一种。
measurement:自己的算法得出的图像的测量值文件夹,以y_%d.txt命名。
import argparse
import numpy as np
import os
import pandas as pd
import cv2
from skimage.measure import compare_ssim
from skimage.measure import compare_psnr
parser = argparse.ArgumentParser(description='total_cr')
parser.add_argument('--y_path',help='path to y dataset', default='measurements/')
parser.add_argument('--orig_path',help='path to orig image dataset', default='orig/')
parser.add_argument('--represent_path',help='path to represent of kakadu', default='represent/')
parser.add_argument('--recon_path',help='path to recon image dataset', default='recon/')
parser.add_argument('--cr',type=int,default=20)
parser.add_argument('--coe',type=int,default=24)
parser.add_argument('--image_format',help='format of the image', default='bmp')
opt = parser.parse_args()
if not os.path.exists('%s' % (opt.represent_path)):
os.makedirs('%s' % (opt.represent_path))
if not os.path.exists('%s' % (opt.recon_path)):
os.makedirs('%s' % (opt.recon_path))
def calc_ent(x):
x_value_list = set([x[i] for i in range(x.shape[0])])
ent = 0.0
for x_value in x_value_list:
p = float(x[x == x_value].shape[0]) / x.shape[0]
logp = np.log2(p)
ent -= p * logp
return ent
num_files = 0
for fn in os.listdir(opt.y_path):
num_files += 1
y_number = []
total_cr_number = []
bpp_number = []
psnr_number = []
ssim_number = []
for idx in range(num_files):
locals()['total_cr_'+str(idx)+''] = opt.cr * 8 / calc_ent(np.loadtxt('%s/y_%d.txt' %(opt.y_path,idx),dtype='int'))
locals()['bpp_'+str(idx)+''] = opt.coe / locals()['total_cr_'+str(idx)+'']
os.system('./kdu_compress -i %s/orig_%d.%s -o %s/out_%d.j2c -rate %.5f' %(opt.orig_path,idx,opt.image_format,opt.represent_path,idx,locals()['bpp_'+str(idx)+'']))
y_number.append(str(idx))
total_cr_number.append(locals()['total_cr_'+str(idx)+''])
bpp_number.append(locals()['bpp_'+str(idx)+''])
for idx in range(num_files):
os.system('./kdu_expand -i %s/out_%d.j2c -o %s/recon_%d.%s' %(opt.represent_path,idx,opt.recon_path,idx,opt.image_format))
for idx in range(num_files):
locals()['orig_'+str(idx)+''] = cv2.imread('%s/orig_%d.%s' %(opt.orig_path,idx,opt.image_format))
locals()['recon_'+str(idx)+''] = cv2.imread('%s/recon_%d.%s' %(opt.recon_path,idx,opt.image_format))
locals()['psnr_'+str(idx)+''] = compare_psnr(locals()['orig_'+str(idx)+''],locals()['recon_'+str(idx)+''])
locals()['ssim_'+str(idx)+''] = compare_ssim(locals()['orig_'+str(idx)+''],locals()['recon_'+str(idx)+''],multichannel=True)
psnr_number.append(locals()['psnr_'+str(idx)+''])
ssim_number.append(locals()['ssim_'+str(idx)+''])
dit = {'y_number':y_number, 'total_cr':total_cr_number,'bpp':bpp_number,'psnr':psnr_number,'ssim':ssim_number}
df = pd.DataFrame(dit)
df.to_csv(r'./JPEG2000_result.csv',columns=['y_number','total_cr','bpp','psnr','ssim'],index=False,sep=',')
生成汇总表格JPEG20000_results.csv:
将本脚本与我的另一篇博文:图像PSNR和SSIM批量比较,适用于图像重建
中的脚本相结合,就能方便得对比自己的算法与JPEG2000的效果。