I have another question from same program where is full code, but this question focus only single process/function of that program.
My problem is performance when creating dynamic Image kernel from list of pixels.
List contains multiple single 4 byte Integer which is grayscale of pixel.
I have tried 3 different approach, still not happy with the time what it takes.
I think my basic idea about generating matrices is wrong.
Approach 1
def getKernels(self, pixels, width):
kernels = []
pixels = [x for sublist in pixels for x in sublist] #2D list to 1D
for i in range(0,len(pixels)):
x = (i % width) #Calc pixel x-cordinate
y = math.floor(i / width) #Calc y-cordinate
try:
kernel = [pixels[(x-1)+((y-1)*width)],pixels[(x)+((y-1)*width)],pixels[(x+1)+((y-1)*width)],pixels[(x-1)+(y*width)],pixels[(x)+(y*width)],pixels[(x+1)+(y*width)],pixels[(x-1)+((y+1)*width)],pixels[(x)+((y+1)*width)],pixels[(x+1)+((y+1)*width)]]
except Exception as e:
kernel = [0] #Cannot create fullsize kernel so just make it black
kernels.append(kernel) #Add kernel to kernels list
return kernels
Function execute time 0.2249772548675537 seconds
With this project I can live with that time, but kernel generation is ugly and "hardcoded" so I cant change size of it.
Approach 2
def getKernels(self, pixels, width):
kernels = []
pixels = [x for sublist in pixels for x in sublist] #2D list to 1D
for i in range(0,len(pixels)):
tx = (i % width) #Calc pixel x-cordinate
ty = math.floor(i / width) #Calc y-cordinate
kernel = []
for y, x in self.kernelGenerator(ty,tx,3): #Pass current pixel index cordinates and size of kernel
try:
index = (x)+((y)*width) #Calc index
if index > -1 and index < len(pixels): #Check that index is in list bounds
kernel.append(pixels[index])
else: #Out of list bounds make pixel black
kernel.append(0)
except Exception as e:
raise e
kernels.append(kernel)
return kernels
def kernelGenerator(self, x, y, size):
if size % 2 == 0 or size < 3: #Because pixel has to be "center" of my kernel
print("Kernel size should be odd and greater than 2")
raise
kernel = []
for i in range(math.ceil(-size/2),math.ceil(size/2)):
for j in range(math.ceil(-size/2),math.ceil(size/2)):
kernel.append((x+i,y+j))
return kernel
Function execute time 1.236647605895996 seconds
Ok, now I can change my kernel size but costs time.
Approach 3
def getKernels(self, pixels):
kernels = []
for ty, row in enumerate(pixels): #get pixel Y-cordinate and row
for tx, px in enumerate(row): #get pixel X-cordinate and px
kernel = []
for y, x in self.kernelGenerator(ty,tx,3):
try:
kernel.append(pixels[y][x])
except Exception as e:
kernel.append(0)
kernels.append(kernel)
return kernels
def kernelGenerator(self, x, y, size):
if size % 2 == 0 or size < 3: #Because pixel has to be "center" of my kernel
print("Kernel size should be odd and greater than 2")
raise
kernel = []
for i in range(math.ceil(-size/2),math.ceil(size/2)):
for j in range(math.ceil(-size/2),math.ceil(size/2)):
kernel.append((x+i,y+j))
return kernel
Function execute time 0.8910479545593262 seconds
Approach 3 is now best. Comments got me thinking this again, still execute time is IMO too much.
Any suggestions to improve it?
pixels
is a list of rows, right? \$\endgroup\$width
is the length of each row, then? \$\endgroup\$