Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Programmed by Juan Carlos Kuri Pinto
- # based on the fractal image compressor found in this link:
- # https://github.com/kennberg/fractal-compression
- import numpy as np
- import scipy.misc as smp
- import copy as c
- import math as m
- # GRAPHICS FUNCTIONS
- def createScreen(width,height):
- return np.zeros((width,height,3),dtype=np.uint8)
- def createPixel(intensity):
- return [intensity,intensity,intensity]
- def drawImage(screen,image,ox,oy):
- for x in range(image.shape[0]):
- for y in range(image.shape[1]):
- screen[int(ox+x),int(oy+y)]=createPixel(image[x,y])
- def drawImageScaled(screen,image,ox,oy,factor,t):
- (width,height)=image.shape
- for x in range(width):
- for y in range(height):
- gray=image[x,y]
- (x2,y2)=transformCoords(t,width,height,x,y)
- dx=ox+x2*factor
- dy=oy+y2*factor
- for fx in range(factor):
- for fy in range(factor):
- screen[dx+fx,dy+fy]=createPixel(gray)
- # IMAGE EXAMPLES
- batmanText=[
- " ",
- " ",
- " ",
- "WWWW W WWW W W W W W",
- " W W W W W WW WW W W WW W",
- " W W W W W WW WW W W WW W",
- " WWW W W W W W W W W W WW",
- " W W WWWWW W W W W WWWWW W WW",
- " W W W W W W W W W W W",
- "WWWW W W W W W W W W W",
- " ",
- " ",
- " ",
- " WWWWWW ",
- " WWWWWWWWWWWWWW ",
- " WW WWW WW WWW WW ",
- " WW WWWW WWWW WW ",
- " WW WWWW WWWW WW ",
- " W WWW WWW W ",
- " W W ",
- " W W ",
- " W W ",
- " W W ",
- " W WWW WW WW WWW W ",
- " WW WWWWWWW WWWWWWW WW ",
- " WW WWWWWW WWWWWW WW ",
- " WWWWWWWW WWWWWWWW ",
- " WWWWWWWWWWWWWW ",
- " WWWWWW ",
- " ",
- " ",
- " "]
- squareSpiralText=[
- " ",
- " WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ",
- " W ",
- " WWWWWWWWWWWWWWWWWWWWWWWWWWWW W ",
- " W W W ",
- " W WWWWWWWWWWWWWWWWWWWWWWWW W W ",
- " W W W W W ",
- " W W WWWWWWWWWWWWWWWWWWWW W W W ",
- " W W W W W W W ",
- " W W W WWWWWWWWWWWWWWWW W W W W ",
- " W W W W W W W W W ",
- " W W W W WWWWWWWWWWWW W W W W W ",
- " W W W W W W W W W W W ",
- " W W W W W WWWWWWWW W W W W W W ",
- " W W W W W W W W W W W W W ",
- " W W W W W W WWWW W W W W W W W ",
- " W W W W W W W W W W W W W W W ",
- " W W W W W W W W W W W W W W ",
- " W W W W W W WWWWWW W W W W W W ",
- " W W W W W W W W W W W W ",
- " W W W W W WWWWWWWWWW W W W W W ",
- " W W W W W W W W W W ",
- " W W W W WWWWWWWWWWWWWW W W W W ",
- " W W W W W W W W ",
- " W W W WWWWWWWWWWWWWWWWWW W W W ",
- " W W W W W W ",
- " W W WWWWWWWWWWWWWWWWWWWWWW W W ",
- " W W W W ",
- " W WWWWWWWWWWWWWWWWWWWWWWWWWW W ",
- " W W ",
- " WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ",
- " "]
- def getImageFromText(text,width,height,spaceColor,color):
- shape=(width,height)
- image=np.zeros(shape,dtype=np.uint8)
- for x in range(width):
- for y in range(height):
- image[x,y]=spaceColor if text[y][x]==' ' else color
- return image
- # TRANSFORMATIONS
- transforms=[]
- transforms.append((False,False,False))
- transforms.append((False,False,True))
- transforms.append((False,True,False))
- transforms.append((False,True,True))
- transforms.append((True,False,False))
- transforms.append((True,False,True))
- transforms.append((True,True,False))
- transforms.append((True,True,True))
- def transformCoords(t,width,height,x,y):
- if t[1]: x=width-1-x
- if t[2]: y=height-1-y
- return (y,x) if t[0] else (x,y)
- class Transform:
- def __init__(self,sx,sy,dx,dy,t,grayFactor,grayOffset,error):
- self.sx=sx
- self.sy=sy
- self.dx=dx
- self.dy=dy
- self.t=t
- self.grayFactor=grayFactor
- self.grayOffset=grayOffset
- self.error=error
- def __str__(self):
- s=''
- s+='sx='+str(self.sx)+' sy='+str(self.sy)
- s+=' dx='+str(self.dx)+' dy='+str(self.dy)
- s+=' t='+str(self.t)+' grayFactor='+str(self.grayFactor)
- s+=' grayOffset='+str(self.grayOffset)+' error='+str(self.error)
- return s
- def getDistance(self):
- difX=self.dx-2*self.sx
- difY=self.dy-2*self.sy
- return m.sqrt(difX*difX+difY*difY)
- # ENCODER
- def square(x):
- return x*x
- def areImageDimensionsPowersOf2(shape):
- return shape[0]!=shape[1] or shape[0]!=getGreaterOrEqualPowerOf2(shape[0])
- def getGreaterOrEqualPowerOf2(x):
- bitmask=1
- while x>bitmask: bitmask<<=1
- return bitmask
- def createZeroImage(size):
- shape=(size,size)
- return np.zeros(shape,dtype=np.uint8)
- class Encoder:
- def __init__(self,image1,image2,blockSize):
- self.image1=image1
- self.image2=image2
- self.blockSize=blockSize
- self.calculateMaxCoordinate()
- self.nBlocks=int(self.size/self.blockSize)
- self.dValues=[i*blockSize for i in range(self.nBlocks)]
- self.sValues=[i*blockSize for i in range(int(self.nBlocks/2))]
- self.ppImage1=self.downSampleImage(self.applyPowerOf2Padding(image1))
- self.ppImage2=self.applyPowerOf2Padding(image2)
- def calculateMaxCoordinate(self):
- mc=max([self.image1.shape[0],self.image1.shape[1],self.image2.shape[0],self.image2.shape[1]])
- self.size=getGreaterOrEqualPowerOf2(mc)
- def applyPowerOf2Padding(self,image):
- (width,height)=image.shape
- paddedImage=createZeroImage(self.size)
- for x in range(self.size):
- for y in range(self.size):
- paddedImage[x,y]=255 if x>=width or y>=height else image[x,y]
- return paddedImage
- def downSampleImage(self,paddedImage):
- self.halfSize=int(self.size/2)
- dsImage=createZeroImage(self.halfSize)
- for x in range(self.halfSize):
- for y in range(self.halfSize):
- pixel=0
- pixel+=paddedImage[x*2 ,y*2 ]
- pixel+=paddedImage[x*2+1,y*2 ]
- pixel+=paddedImage[x*2 ,y*2+1]
- pixel+=paddedImage[x*2+1,y*2+1]
- pixel*=0.25
- dsImage[x,y]=pixel # int(pixel)
- return dsImage
- def getBlock(self,image,ox,oy,blockSize,t):
- block=createZeroImage(blockSize)
- if t==0:
- for x in range(blockSize):
- for y in range(blockSize):
- block[x,y]=image[ox+x,oy+y]
- else:
- transform=transforms[t]
- for x in range(blockSize):
- for y in range(blockSize):
- (x2,y2)=transformCoords(transform,blockSize,blockSize,x,y)
- block[x2,y2]=image[ox+x,oy+y]
- return block
- def findFractalCodes(self):
- self.fractalCodes=dict()
- for dx in self.dValues:
- for dy in self.dValues:
- block2=self.getBlock(self.ppImage2,dx,dy,self.blockSize,0)
- average2=self.getAveragePixelOfBlock(block2)
- bestTransform=self.findFractalCode(dx,dy,block2,average2)
- self.fractalCodes[(dx,dy)]=bestTransform
- if(bestTransform.error==0): print('PERFECT TRANSFORM: '+str(bestTransform))
- else: print(bestTransform)
- def findFractalCode(self,dx,dy,block2,average2):
- bestTransform=None
- for sx in self.sValues:
- for sy in self.sValues:
- for t in range(8):
- block1=self.getBlock(self.ppImage1,sx,sy,self.blockSize,t)
- average1=self.getAveragePixelOfBlock(block1)
- grayFactor=self.getGrayFactorOfBlocks(block1,block2,average1,average2)
- grayOffset=average2-grayFactor*average1
- error=self.getErrorOfBlocks(block1,block2,average1,average2,grayFactor)
- transform=Transform(sx,sy,dx,dy,t,grayFactor,grayOffset,error)
- if bestTransform==None or transform.error<bestTransform.error or (transform.error==bestTransform.error and transform.getDistance()<bestTransform.getDistance()):
- bestTransform=transform
- return bestTransform
- def getAveragePixelOfBlock(self,block):
- s=0.0
- for x in range(self.blockSize):
- for y in range(self.blockSize):
- s+=block[x,y]
- return s/(self.blockSize*self.blockSize)
- def getGrayFactorOfBlocks(self,block1,block2,average1,average2):
- (top,bottom)=(0.0,0.0)
- for x in range(self.blockSize):
- for y in range(self.blockSize):
- dif1=block1[x,y]-average1
- dif2=block2[x,y]-average2
- top+=dif2*dif1
- bottom+=dif1*dif1
- if bottom==0: return 0.0
- return top/bottom
- def getErrorOfBlocks(self,block1,block2,average1,average2,grayFactor):
- error=0.0
- for x in range(self.blockSize):
- for y in range(self.blockSize):
- dif1=block1[x,y]-average1
- dif2=block2[x,y]-average2
- dif=grayFactor*dif1-dif2
- error+=dif*dif
- return error/(self.blockSize*self.blockSize)
- def applyTransformations(self,image):
- if not areImageDimensionsPowersOf2(image.shape):
- image=self.applyPowerOf2Padding(image)
- dsImage=self.downSampleImage(image)
- newImage=self.applyPowerOf2Padding(image)
- for dx in self.dValues:
- for dy in self.dValues:
- transform=self.fractalCodes[(dx,dy)]
- sBlock=self.getBlock(dsImage,transform.sx,transform.sy,self.blockSize,transform.t)
- for x in range(self.blockSize):
- for y in range(self.blockSize):
- pixel=transform.grayFactor*sBlock[x,y]+transform.grayOffset
- if pixel<0: pixel=0
- if pixel>255: pixel=255
- newImage[dx+x,dy+y]=pixel # int(pixel)
- return newImage
- def applyTransformationsNTimes(self,image,n):
- for i in range(n):
- image=self.applyTransformations(image)
- return image
- # MAIN FUNCTIONS
- blockSize=2
- drawingScale=3
- imageSize=32
- littleSpace=10
- def coord(n):
- return littleSpace+(imageSize+littleSpace)*drawingScale*n
- def draw(image1,image2,start):
- screen=createScreen(1000,300)
- encoder=Encoder(image1,image2,blockSize)
- encoder.findFractalCodes()
- drawImageScaled(screen,image1,coord(0),coord(0),drawingScale,transforms[0])
- drawImageScaled(screen,encoder.ppImage1,coord(1),coord(0),drawingScale,transforms[0])
- drawImageScaled(screen,encoder.ppImage2,coord(2),coord(0),drawingScale,transforms[0])
- for n in range(8):
- drawImageScaled(screen,encoder.applyTransformationsNTimes(start,n),coord(n),coord(1),drawingScale,transforms[0])
- img=smp.toimage(screen.transpose())
- img.show()
- def main():
- squareSpiral=getImageFromText(squareSpiralText,imageSize,imageSize,255,0)
- batman=getImageFromText(batmanText,imageSize,imageSize,0,255)
- zero=createZeroImage(imageSize)
- draw(batman,batman,squareSpiral)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement