Advertisement
jckuri

FractalCompressor.py

Apr 14th, 2017
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.48 KB | None | 0 0
  1. # Programmed by Juan Carlos Kuri Pinto
  2. # based on the fractal image compressor found in this link:
  3. # https://github.com/kennberg/fractal-compression
  4.  
  5. import numpy as np
  6. import scipy.misc as smp
  7. import copy as c
  8. import math as m
  9.  
  10. # GRAPHICS FUNCTIONS
  11.  
  12. def createScreen(width,height):
  13.  return np.zeros((width,height,3),dtype=np.uint8)
  14.  
  15. def createPixel(intensity):
  16.  return [intensity,intensity,intensity]
  17.  
  18. def drawImage(screen,image,ox,oy):
  19.  for x in range(image.shape[0]):
  20.   for y in range(image.shape[1]):
  21.    screen[int(ox+x),int(oy+y)]=createPixel(image[x,y])
  22.    
  23. def drawImageScaled(screen,image,ox,oy,factor,t):
  24.  (width,height)=image.shape
  25.  for x in range(width):
  26.   for y in range(height):
  27.    gray=image[x,y]
  28.    (x2,y2)=transformCoords(t,width,height,x,y)
  29.    dx=ox+x2*factor
  30.    dy=oy+y2*factor
  31.    for fx in range(factor):
  32.     for fy in range(factor):
  33.      screen[dx+fx,dy+fy]=createPixel(gray)
  34.  
  35. # IMAGE EXAMPLES
  36.  
  37. batmanText=[
  38.  "                                ",
  39.  "                                ",
  40.  "                                ",
  41.  "WWWW    W   WWW W   W   W   W  W",
  42.  " W  W  W W   W  WW WW  W W  WW W",
  43.  " W  W W   W  W  WW WW W   W WW W",
  44.  " WWW  W   W  W  W W W W   W W WW",
  45.  " W  W WWWWW  W  W W W WWWWW W WW",
  46.  " W  W W   W  W  W   W W   W W  W",
  47.  "WWWW  W   W  W  W   W W   W W  W",
  48.  "                                ",
  49.  "                                ",
  50.  "                                ",
  51.  "             WWWWWW             ",
  52.  "         WWWWWWWWWWWWWW         ",
  53.  "       WW  WWW WW WWW  WW       ",
  54.  "     WW   WWWW    WWWW   WW     ",
  55.  "    WW    WWWW    WWWW    WW    ",
  56.  "    W      WWW    WWW      W    ",
  57.  "   W                        W   ",  
  58.  "   W                        W   ",
  59.  "   W                        W   ",
  60.  "   W                        W   ",
  61.  "    W   WWW WW    WW WWW   W    ",
  62.  "    WW  WWWWWWW  WWWWWWW  WW    ",
  63.  "     WW  WWWWWW  WWWWWW  WW     ",
  64.  "       WWWWWWWW  WWWWWWWW       ",
  65.  "         WWWWWWWWWWWWWW         ",
  66.  "             WWWWWW             ",
  67.  "                                ",
  68.  "                                ",
  69.  "                                "]
  70.  
  71. squareSpiralText=[
  72.  "                                ",
  73.  " WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ",
  74.  "                              W ",
  75.  " WWWWWWWWWWWWWWWWWWWWWWWWWWWW W ",
  76.  " W                          W W ",
  77.  " W WWWWWWWWWWWWWWWWWWWWWWWW W W ",
  78.  " W W                      W W W ",
  79.  " W W WWWWWWWWWWWWWWWWWWWW W W W ",
  80.  " W W W                  W W W W ",
  81.  " W W W WWWWWWWWWWWWWWWW W W W W ",
  82.  " W W W W              W W W W W ",
  83.  " W W W W WWWWWWWWWWWW W W W W W ",
  84.  " W W W W W          W W W W W W ",
  85.  " W W W W W WWWWWWWW W W W W W W ",
  86.  " W W W W W W      W W W W W W W ",
  87.  " W W W W W W WWWW W W W W W W W ",
  88.  " W W W W W W W  W W W W W W W W ",
  89.  " W W W W W W W    W W W W W W W ",
  90.  " W W W W W W WWWWWW W W W W W W ",
  91.  " W W W W W W        W W W W W W ",
  92.  " W W W W W WWWWWWWWWW W W W W W ",
  93.  " W W W W W            W W W W W ",
  94.  " W W W W WWWWWWWWWWWWWW W W W W ",
  95.  " W W W W                W W W W ",
  96.  " W W W WWWWWWWWWWWWWWWWWW W W W ",
  97.  " W W W                    W W W ",
  98.  " W W WWWWWWWWWWWWWWWWWWWWWW W W ",
  99.  " W W                        W W ",
  100.  " W WWWWWWWWWWWWWWWWWWWWWWWWWW W ",
  101.  " W                            W ",
  102.  " WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ",
  103.  "                                "]
  104.  
  105. def getImageFromText(text,width,height,spaceColor,color):
  106.  shape=(width,height)
  107.  image=np.zeros(shape,dtype=np.uint8)
  108.  for x in range(width):
  109.   for y in range(height):
  110.    image[x,y]=spaceColor if text[y][x]==' ' else color
  111.  return image
  112.  
  113. # TRANSFORMATIONS
  114.  
  115. transforms=[]
  116. transforms.append((False,False,False))
  117. transforms.append((False,False,True))
  118. transforms.append((False,True,False))
  119. transforms.append((False,True,True))
  120. transforms.append((True,False,False))
  121. transforms.append((True,False,True))
  122. transforms.append((True,True,False))
  123. transforms.append((True,True,True))
  124.  
  125. def transformCoords(t,width,height,x,y):
  126.  if t[1]: x=width-1-x
  127.  if t[2]: y=height-1-y
  128.  return (y,x) if t[0] else (x,y)
  129.  
  130. class Transform:
  131.  
  132.  def __init__(self,sx,sy,dx,dy,t,grayFactor,grayOffset,error):
  133.   self.sx=sx
  134.   self.sy=sy
  135.   self.dx=dx
  136.   self.dy=dy
  137.   self.t=t
  138.   self.grayFactor=grayFactor
  139.   self.grayOffset=grayOffset
  140.   self.error=error
  141.  
  142.  def __str__(self):
  143.   s=''
  144.   s+='sx='+str(self.sx)+' sy='+str(self.sy)
  145.   s+=' dx='+str(self.dx)+' dy='+str(self.dy)
  146.   s+=' t='+str(self.t)+' grayFactor='+str(self.grayFactor)
  147.   s+=' grayOffset='+str(self.grayOffset)+' error='+str(self.error)
  148.   return s
  149.  
  150.  def getDistance(self):
  151.   difX=self.dx-2*self.sx
  152.   difY=self.dy-2*self.sy
  153.   return m.sqrt(difX*difX+difY*difY)
  154.  
  155. # ENCODER
  156.  
  157. def square(x):
  158.  return x*x
  159.  
  160. def areImageDimensionsPowersOf2(shape):
  161.  return shape[0]!=shape[1] or shape[0]!=getGreaterOrEqualPowerOf2(shape[0])
  162.  
  163. def getGreaterOrEqualPowerOf2(x):
  164.  bitmask=1
  165.  while x>bitmask: bitmask<<=1
  166.  return bitmask
  167.  
  168. def createZeroImage(size):
  169.  shape=(size,size)
  170.  return np.zeros(shape,dtype=np.uint8)
  171.  
  172. class Encoder:
  173.  
  174.  def __init__(self,image1,image2,blockSize):
  175.   self.image1=image1
  176.   self.image2=image2
  177.   self.blockSize=blockSize
  178.   self.calculateMaxCoordinate()
  179.   self.nBlocks=int(self.size/self.blockSize)
  180.   self.dValues=[i*blockSize for i in range(self.nBlocks)]
  181.   self.sValues=[i*blockSize for i in range(int(self.nBlocks/2))]
  182.   self.ppImage1=self.downSampleImage(self.applyPowerOf2Padding(image1))
  183.   self.ppImage2=self.applyPowerOf2Padding(image2)
  184.  
  185.  def calculateMaxCoordinate(self):  
  186.   mc=max([self.image1.shape[0],self.image1.shape[1],self.image2.shape[0],self.image2.shape[1]])
  187.   self.size=getGreaterOrEqualPowerOf2(mc)
  188.  
  189.  def applyPowerOf2Padding(self,image):
  190.   (width,height)=image.shape
  191.   paddedImage=createZeroImage(self.size)
  192.   for x in range(self.size):
  193.    for y in range(self.size):
  194.     paddedImage[x,y]=255 if x>=width or y>=height else image[x,y]
  195.   return paddedImage
  196.  
  197.  def downSampleImage(self,paddedImage):
  198.   self.halfSize=int(self.size/2)
  199.   dsImage=createZeroImage(self.halfSize)
  200.   for x in range(self.halfSize):
  201.    for y in range(self.halfSize):
  202.     pixel=0
  203.     pixel+=paddedImage[x*2  ,y*2  ]
  204.     pixel+=paddedImage[x*2+1,y*2  ]
  205.     pixel+=paddedImage[x*2  ,y*2+1]
  206.     pixel+=paddedImage[x*2+1,y*2+1]
  207.     pixel*=0.25
  208.     dsImage[x,y]=pixel # int(pixel)
  209.   return dsImage
  210.  
  211.  def getBlock(self,image,ox,oy,blockSize,t):
  212.   block=createZeroImage(blockSize)
  213.   if t==0:
  214.    for x in range(blockSize):
  215.     for y in range(blockSize):
  216.      block[x,y]=image[ox+x,oy+y]
  217.   else:
  218.    transform=transforms[t]
  219.    for x in range(blockSize):
  220.     for y in range(blockSize):
  221.      (x2,y2)=transformCoords(transform,blockSize,blockSize,x,y)
  222.      block[x2,y2]=image[ox+x,oy+y]
  223.   return block
  224.  
  225.  def findFractalCodes(self):
  226.   self.fractalCodes=dict()
  227.   for dx in self.dValues:
  228.    for dy in self.dValues:
  229.     block2=self.getBlock(self.ppImage2,dx,dy,self.blockSize,0)
  230.     average2=self.getAveragePixelOfBlock(block2)
  231.     bestTransform=self.findFractalCode(dx,dy,block2,average2)
  232.     self.fractalCodes[(dx,dy)]=bestTransform
  233.     if(bestTransform.error==0): print('PERFECT TRANSFORM: '+str(bestTransform))
  234.     else: print(bestTransform)
  235.        
  236.  def findFractalCode(self,dx,dy,block2,average2):
  237.   bestTransform=None
  238.   for sx in self.sValues:
  239.    for sy in self.sValues:
  240.     for t in range(8):
  241.      block1=self.getBlock(self.ppImage1,sx,sy,self.blockSize,t)
  242.      average1=self.getAveragePixelOfBlock(block1)
  243.      grayFactor=self.getGrayFactorOfBlocks(block1,block2,average1,average2)
  244.      grayOffset=average2-grayFactor*average1
  245.      error=self.getErrorOfBlocks(block1,block2,average1,average2,grayFactor)
  246.      transform=Transform(sx,sy,dx,dy,t,grayFactor,grayOffset,error)
  247.      if bestTransform==None or transform.error<bestTransform.error or (transform.error==bestTransform.error and transform.getDistance()<bestTransform.getDistance()):
  248.       bestTransform=transform
  249.   return bestTransform
  250.      
  251.  def getAveragePixelOfBlock(self,block):
  252.   s=0.0
  253.   for x in range(self.blockSize):
  254.    for y in range(self.blockSize):
  255.     s+=block[x,y]
  256.   return s/(self.blockSize*self.blockSize)
  257.    
  258.  def getGrayFactorOfBlocks(self,block1,block2,average1,average2):
  259.   (top,bottom)=(0.0,0.0)
  260.   for x in range(self.blockSize):
  261.    for y in range(self.blockSize):
  262.     dif1=block1[x,y]-average1
  263.     dif2=block2[x,y]-average2
  264.     top+=dif2*dif1
  265.     bottom+=dif1*dif1
  266.   if bottom==0: return 0.0
  267.   return top/bottom
  268.  
  269.  def getErrorOfBlocks(self,block1,block2,average1,average2,grayFactor):
  270.   error=0.0
  271.   for x in range(self.blockSize):
  272.    for y in range(self.blockSize):
  273.     dif1=block1[x,y]-average1
  274.     dif2=block2[x,y]-average2
  275.     dif=grayFactor*dif1-dif2
  276.     error+=dif*dif
  277.   return error/(self.blockSize*self.blockSize)
  278.  
  279.  def applyTransformations(self,image):
  280.   if not areImageDimensionsPowersOf2(image.shape):
  281.    image=self.applyPowerOf2Padding(image)
  282.   dsImage=self.downSampleImage(image)
  283.   newImage=self.applyPowerOf2Padding(image)
  284.   for dx in self.dValues:
  285.    for dy in self.dValues:
  286.     transform=self.fractalCodes[(dx,dy)]
  287.     sBlock=self.getBlock(dsImage,transform.sx,transform.sy,self.blockSize,transform.t)
  288.     for x in range(self.blockSize):
  289.      for y in range(self.blockSize):
  290.       pixel=transform.grayFactor*sBlock[x,y]+transform.grayOffset
  291.       if pixel<0: pixel=0
  292.       if pixel>255: pixel=255
  293.       newImage[dx+x,dy+y]=pixel # int(pixel)
  294.   return newImage
  295.      
  296.  def applyTransformationsNTimes(self,image,n):
  297.   for i in range(n):
  298.    image=self.applyTransformations(image)
  299.   return image
  300.  
  301. # MAIN FUNCTIONS
  302.  
  303. blockSize=2
  304. drawingScale=3
  305. imageSize=32
  306. littleSpace=10
  307.  
  308. def coord(n):
  309.  return littleSpace+(imageSize+littleSpace)*drawingScale*n
  310.  
  311. def draw(image1,image2,start):
  312.  screen=createScreen(1000,300)
  313.  encoder=Encoder(image1,image2,blockSize)
  314.  encoder.findFractalCodes()
  315.  drawImageScaled(screen,image1,coord(0),coord(0),drawingScale,transforms[0])
  316.  drawImageScaled(screen,encoder.ppImage1,coord(1),coord(0),drawingScale,transforms[0])
  317.  drawImageScaled(screen,encoder.ppImage2,coord(2),coord(0),drawingScale,transforms[0])
  318.  for n in range(8):
  319.   drawImageScaled(screen,encoder.applyTransformationsNTimes(start,n),coord(n),coord(1),drawingScale,transforms[0])
  320.  img=smp.toimage(screen.transpose())
  321.  img.show()
  322.  
  323. def main():
  324.  squareSpiral=getImageFromText(squareSpiralText,imageSize,imageSize,255,0)
  325.  batman=getImageFromText(batmanText,imageSize,imageSize,0,255)
  326.  zero=createZeroImage(imageSize)
  327.  draw(batman,batman,squareSpiral)
  328.  
  329. if __name__ == "__main__":
  330.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement