Last active
November 16, 2019 19:44
-
-
Save native-m/1b84e8582578527b86d7775b3b235d4e to your computer and use it in GitHub Desktop.
JPEG Emulator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# JPEG Emulator | |
# licensed under GPLv2 license | |
# | |
# What this thing does? | |
# It emulates jpeg DCT algorithm | |
# | |
# Python 3 is required to run this code | |
# | |
# HOW TO USE: | |
# 1. install numpy, scipy, and Pillow package | |
# 2. then execute: | |
# python jpegemu.py <input image> <output image> <coef size> <clip> | |
# | |
# COMMAND LINE INTERFACE: | |
# python jpegemu.py <input image> <output image> <coef size> <clip> | |
# <input image>: image to be processed | |
# <output image>: output to the resulting image | |
# <coef mul>: The quantization coefficient multiplication factor, higher means more compression | |
# <clip>: 'clip' or 'noclip', | |
# this will limit the color value in range of [-128, 127) ('clip' option), | |
# otherwise the color will not be clipped/limited ('unclip' option) | |
import sys | |
import numpy as np | |
import math | |
from PIL import Image, ImageFilter | |
from scipy.fftpack import dctn, idctn | |
qcoef = [[16, 11, 10, 16, 24, 40, 51, 61], | |
[12, 12, 14, 19, 26, 58, 60, 55], | |
[14, 13, 16, 24, 40, 57, 69, 56], | |
[14, 17, 22, 29, 51, 87, 80, 62], | |
[18, 22, 37, 56, 68, 109, 103, 77], | |
[24, 35, 55, 64, 81, 104, 113, 92], | |
[49, 64, 78, 87, 103, 121, 120, 101], | |
[72, 92, 95, 98, 112, 100, 103, 99]] | |
def main(): | |
inputfile = sys.argv[1] | |
outputfile = sys.argv[2] | |
coefmul = int(sys.argv[3]) | |
clip = sys.argv[4] | |
if sys.argv[4] == 'clip': | |
clip = True | |
else: | |
clip = False | |
try: | |
im = Image.open(inputfile) | |
im2 = Image.new("RGB",im.size,(0,0,0)) | |
except IOError: | |
print("Cannot open file ", inputfile); | |
w, h = im.size | |
total = w/8 * h/8 | |
progress = 0 | |
coef = np.array(qcoef) * coefmul | |
for y in range(int(math.ceil(h/8))): | |
for x in range(int(math.ceil(w/8))): | |
idX = x*8 | |
idY = y*8 | |
parts = im.crop(box=(idX,idY,idX+8,idY+8)) | |
splitRGB = parts.split() | |
r = np.array(list(splitRGB[0].getdata())).reshape(8,8) - 128 | |
g = np.array(list(splitRGB[1].getdata())).reshape(8,8) - 128 | |
b = np.array(list(splitRGB[2].getdata())).reshape(8,8) - 128 | |
rdct = np.round(dctn(r,norm="ortho") / coef) * coef | |
gdct = np.round(dctn(g,norm="ortho") / coef) * coef | |
bdct = np.round(dctn(b,norm="ortho") / coef) * coef | |
if clip: | |
rdct = np.clip(idctn(rdct,norm="ortho"),-128,127) | |
gdct = np.clip(idctn(gdct,norm="ortho"),-128,127) | |
bdct = np.clip(idctn(bdct,norm="ortho"),-128,127) | |
else: | |
rdct = idctn(rdct,norm="ortho") | |
gdct = idctn(gdct,norm="ortho") | |
bdct = idctn(bdct,norm="ortho") | |
r = Image.fromarray(np.round(rdct + 128).astype(np.uint8), mode="L") | |
g = Image.fromarray(np.round(gdct + 128).astype(np.uint8), mode="L") | |
b = Image.fromarray(np.round(bdct + 128).astype(np.uint8), mode="L") | |
im2.paste(Image.merge(mode="RGB", bands=(r,g,b)), box=(idX,idY)) | |
progress += 1 | |
sys.stdout.write("\rProgress " + str(round(100 * (progress / total))) + "%") | |
sys.stdout.flush() | |
im2.save(outputfile) | |
im.close() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment