Reputation: 13
I'm attempting to create a custom image filter which takes in an image and generates an image which uses every RGB color by finding the (approximate) closest unused color. I've optimized it as much as I can think of for now, but I estimate it will still take over 40 hours to complete one (4096x4096) image as is, hoping someone else will have ideas. This is the current function which finds the (approximate) closest available color given the next pixel:
def getColor(pixelVal, colorArray):
for distance in range(256):
if distance < 10:
distanceArray = colorArray[max(pixelVal[0]-distance,0):min(pixelVal[0]+distance+1,255), max(pixelVal[1]-distance,0):min(pixelVal[1]+distance+1,255), max(pixelVal[2]-distance,0):min(pixelVal[2]+distance+1,255)]
available = distanceArray[distanceArray[..., 3] == 1]
if (len(available) > 0):
return available[0]
else:
pixelRMin = max(pixelVal[0]-distance,0)
pixelRMax = min(pixelVal[0]+distance+1,255)
pixelGMin = max(pixelVal[1]-distance,0)
pixelGMax = min(pixelVal[1]+distance+1,255)
pixelBMin = max(pixelVal[2]-distance,0)
pixelBMax = min(pixelVal[2]+distance+1,255)
array1 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMax, pixelBMin:pixelBMin+1]
available = array1[array1[..., 3] == 1]
if (len(available) > 0):
return available[0]
array2 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMax, pixelBMax-1:pixelBMax]
available = array2[array2[..., 3] == 1]
if (len(available) > 0):
return available[0]
array3 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMin+1, pixelBMin:pixelBMax]
available = array3[array3[..., 3] == 1]
if (len(available) > 0):
return available[0]
array4 = colorArray[pixelRMin:pixelRMax, pixelGMax-1:pixelGMax, pixelBMin:pixelBMax]
available = array4[array4[..., 3] == 1]
if (len(available) > 0):
return available[0]
array5 = colorArray[pixelRMin:pixelRMin+1, pixelGMin:pixelGMax, pixelBMin:pixelBMax]
available = array5[array5[..., 3] == 1]
if (len(available) > 0):
return available[0]
array6 = colorArray[pixelRMax-1:pixelRMax, pixelGMin:pixelGMax, pixelBMin:pixelBMax]
available = array6[array6[..., 3] == 1]
if (len(available) > 0):
return available[0]
It searches an expanding cube for a color that has not been used yet from a 4d array (R, G, B, and available boolean), eventually switching to only search the shell of the cube (at a distance of 10 which after some testing seems to be optimal).
Here are the results for the first 10%:
Thanks!
Edit: Full Example:
from PIL import Image
import numpy as np
import time
start = "top" #center, bottom, left, right
direction = "rows" #columns, spiral
method = "pixel" #color (pixel does each pixel in sequence, color does each distance in sequence)
def getColorArray():
colorArray = np.zeros((256, 256, 256, 4), dtype=int)
for r in range(256):
for g in range(256):
for b in range(256):
colorArray[r, g, b] = (r, g, b, 1)
return colorArray
def getColor(pixelVal, colorArray):
for distance in range(256):
if distance < 10:
distanceArray = colorArray[max(pixelVal[0]-distance,0):min(pixelVal[0]+distance+1,255), max(pixelVal[1]-distance,0):min(pixelVal[1]+distance+1,255), max(pixelVal[2]-distance,0):min(pixelVal[2]+distance+1,255)]
available = distanceArray[distanceArray[..., 3] == 1]
if (len(available) > 0):
return available[0]
else:
pixelRMin = max(pixelVal[0]-distance,0)
pixelRMax = min(pixelVal[0]+distance+1,255)
pixelGMin = max(pixelVal[1]-distance,0)
pixelGMax = min(pixelVal[1]+distance+1,255)
pixelBMin = max(pixelVal[2]-distance,0)
pixelBMax = min(pixelVal[2]+distance+1,255)
array1 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMax, pixelBMin:pixelBMin+1]
available = array1[array1[..., 3] == 1]
if (len(available) > 0):
return available[0]
array2 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMax, pixelBMax-1:pixelBMax]
available = array2[array2[..., 3] == 1]
if (len(available) > 0):
return available[0]
array3 = colorArray[pixelRMin:pixelRMax, pixelGMin:pixelGMin+1, pixelBMin:pixelBMax]
available = array3[array3[..., 3] == 1]
if (len(available) > 0):
return available[0]
array4 = colorArray[pixelRMin:pixelRMax, pixelGMax-1:pixelGMax, pixelBMin:pixelBMax]
available = array4[array4[..., 3] == 1]
if (len(available) > 0):
return available[0]
array5 = colorArray[pixelRMin:pixelRMin+1, pixelGMin:pixelGMax, pixelBMin:pixelBMax]
available = array5[array5[..., 3] == 1]
if (len(available) > 0):
return available[0]
array6 = colorArray[pixelRMax-1:pixelRMax, pixelGMin:pixelGMax, pixelBMin:pixelBMax]
available = array6[array6[..., 3] == 1]
if (len(available) > 0):
return available[0]
def genImage(inputPath, outputPath):
inputImage = Image.open(inputPath)
inputArray = np.array(inputImage)
colorArray = getColorArray()
outputArray = np.zeros_like(inputArray)
num = 0
pct = 0
start = time.time()
last = time.time()
print(len(colorArray[colorArray[..., 3] == 1]))
for i in range(inputArray.shape[0]):
for j in range(inputArray.shape[1]):
pixelVal = tuple(inputArray[i, j])
color = getColor(pixelVal, colorArray)
if (color is None):
print(pixelVal)
print(len(colorArray[colorArray[..., 3] == 1]))
outputArray[i, j] = (color[0], color[1], color[2])
colorArray[color[0], color[1], color[2]] = (color[0], color[1], color[2], 0)
if (num > 41):
pct += 1
now = time.time()
print(str(pct) + "%: " + str(round((now - start), 2)) + " seconds total, " + str(round((now - last), 2)) + " seconds for this percent")
last = now
outputImage = Image.fromarray(outputArray)
outputImage.save(outputPath)
num = 0
num += 1
outputImage = Image.fromarray(outputArray)
outputImage.save(outputPath)
inputPath = "input_image.jpg"
outputPath = "output_image.jpg"
genImage(inputPath, outputPath)
Upvotes: 0
Views: 158