COLOR PALETTE FROM IMAGE (OLD)
This is an old version for a python learning experiment. You can see the new version/tool here.
This was an experiment trying to create a color palette from an image, it was made just for fun and as an exercise trying to solve that problem using Python. I used two Blocky Nodes combined to mix base and complementary/saturated color. The Blocky node creates a pixelated effect, I store those pixel values in an array and then create a new image (ramp) with the colors sorted by luminance (I used this equation to calculate the luminance: lumaValue = redSample*0.2126 + greenSample*0.7152 + blueSample*0.0722). The result was interesting, I didn’t group the operations so the whole process is visible, however it is not updated automatically as the python code stores the colors when run. The GitHub code is here as I couldn’t embed it anymore in Squarespace XD.
There’s a variable called blockySize in the code that controls the number of colors (it’s not the number of colors, but the size of the blocky, a smaller size will create more colors and a larger number will create less colors), now is set to the 15% of the image width, you can change this value to have more or less colors but WARNING, it can be heavy to process. It is not a perfect approach as pixelation (Blocky) blends the colors, however I’m happy with the results as it can be a fast approach to get a color palette.
The images used to illustrate how the tool is working were taken from Google. The first one is an awesome illustration by Wei Wang, the second one is a concept art by Juan Diego Leon, and the last image is from Edvige Faini.
#GenerateColorPaletteFromImage#AUTHOR: Juan Francisco Cevallos C.#DESCRIPTION: This is just an experiment to try to create a color palette from an image.#This script takes the selected node and using a Blocky Node creates a color palette.#v001 - September 2019#setVariablesimport mathindexArray = []colorArray = []lumaArray = []a = nuke.selectedNode()width = a.width()height = a.height()print widthprint height#BlockySize = Percentage of the WidthblockySize = int(float(width)*0.15)#cellNumberreformatX = math.ceil (float(width) / float(blockySize))reformatY = math.ceil (float(height) / float(blockySize))print reformatXprint reformatY#finalBlur (if used)blurSize = round (width*0.15)#nodesCreationshuRed = nuke.createNode("Shuffle")shuRed.knob("red").setValue("red1")shuRed.knob("green").setValue(0)shuRed.knob("blue").setValue(0)shuGreen = nuke.createNode("Shuffle")shuGreen.knob("red").setValue(0)shuGreen.knob("green").setValue("green1")shuGreen.knob("blue").setValue(0)shuGreen.setInput(0,a)shuBlue = nuke.createNode("Shuffle")shuBlue.knob("red").setValue(0)shuBlue.knob("green").setValue(0)shuBlue.knob("blue").setValue("blue1")shuBlue.setInput(0,a)mChannels = nuke.createNode("Merge2")mChannels.knob("operation").setValue("average")mChannels.setInput(0,shuRed)mChannels.setInput(1,shuGreen)mChannels.setInput(3,shuBlue)bFrom = nuke.createNode('Blur')bFrom.knob("size").setValue(20)bFrom.setInput(0,a)mFrom = nuke.createNode("Merge2")mFrom.knob("operation").setValue("from")mFrom.setInput(1,bFrom)mFrom.setInput(0,mChannels)gFrom = nuke.createNode("Grade")gFrom.knob("gamma").setValue(5)gOriginal = nuke.createNode("Grade")gOriginal.knob("multiply").setValue(2)gOriginal.knob("gamma").setValue(0.5)gOriginal.setInput(0,a)satOriginal = nuke.createNode("Saturation")satOriginal.knob("saturation").setValue(9)satOriginal.knob("mode").setValue("Average")keyFrom = nuke.createNode("Keyer")keyFrom.knob("range").setValue((0,0.0001,1,1))keyFrom.setInput(0,gFrom)mOriginal = nuke.createNode("Merge2")mOriginal.setInput(0,gFrom)mOriginal.setInput(1,satOriginal)mOriginal.setInput(2,keyFrom)#createBlockyComplementarybComp = nuke.createNode('Blocky')bComp.knob("size").setValue(blockySize)#createBlockyb = nuke.createNode('Blocky')b.knob("size").setValue(blockySize)b.setInput(0,a)#mergeBothBlockysmBlocky = nuke.createNode("Merge2")mBlocky.knob("operation").setValue("plus")mBlocky.setInput(0,b)mBlocky.setInput(1,bComp)#small CC to contrastgra = nuke.createNode('Grade')gra.knob("multiply").setValue(1.35)gra.knob("gamma").setValue(0.75)crop = nuke.createNode('Crop')#divide in cells for each colorref = nuke.createNode('Reformat')ref.knob("type").setValue(1)ref.knob("box_fixed").setValue(1)ref.knob("box_width").setValue(reformatX)ref.knob("box_height").setValue(reformatY)ref.knob("resize").setValue("fit")ref.knob("filter").setValue(0)#sample all cells to store colorsfor y in range (int(reformatY)): for x in range (int(reformatX)): colorOriginal = [] indexOriginal = [] redSample = ref.sample('red',x,y) greenSample = ref.sample('green',x,y) blueSample = ref.sample('blue',x,y) indexOriginal = [x,y] colorOriginal = [redSample,greenSample,blueSample] print colorOriginal indexArray.append(indexOriginal) colorArray.append(colorOriginal) lumaValue = redSample*0.2126 + greenSample*0.7152 + blueSample*0.0722 lumaArray.append(lumaValue)#kill all the colorsmult = nuke.createNode('Multiply')mult.knob("channels").setValue("rgb")mult.knob("value").setValue(0)print lumaArraysortedLuma = sorted ( range (len(lumaArray)), key = lambda k: lumaArray[k])print sortedLuma#create a long for each colorrefNew = nuke.createNode('Reformat')refNew.knob("type").setValue(1)refNew.knob("box_fixed").setValue(1)refNew.knob("box_width").setValue(reformatX*reformatY)refNew.knob("box_height").setValue(1)refNew.knob("filter").setValue(0)#expression group pixel by pixelexpr_group = nuke.nodes.Group()expr_group.begin()input_group = nuke.nodes.Input()exprArray = []for i in range (len(lumaArray)): print "el item " + str(i) + " de luminancia." indice = lumaArray[i] print "tiene el valor: " + str(indice) indiceDeseado = int(sortedLuma[i]) colorDeseado = colorArray[indiceDeseado] print "le corresponde el indice de color: " + str(indiceDeseado) print "y deberia tener este color: " + str(colorDeseado) pixel_to_change = [i,0] pixel_rgb_value = colorDeseado expr = nuke.createNode('Expression') expr['expr0'].setValue('x=={0} && y=={1} ? {2}:0'.format(pixel_to_change[0],pixel_to_change[1],round(pixel_rgb_value[0],5) )) expr['expr1'].setValue('x=={0} && y=={1} ? {2}:0'.format(pixel_to_change[0],pixel_to_change[1],round(pixel_rgb_value[1],5) )) expr['expr2'].setValue('x=={0} && y=={1} ? {2}:0'.format(pixel_to_change[0],pixel_to_change[1],round(pixel_rgb_value[2],5) )) expr.knob("selected").setValue(True) expr.setInput(0,input_group) exprArray.append(expr.knob("name").getValue())merge = nuke.createNode('Merge2')for i in exprArray: print i numero = exprArray.index(i) if numero >=2: numero = numero + 1 print numero merge.setInput(numero,nuke.toNode(i))merge.knob("operation").setValue("plus")expr_output = nuke.nodes.Output()expr_output.setInput(0,merge)expr_group.end()expr_group.setInput(0, refNew)#Make the image big again based in width and heightrefNew.knob("selected").setValue(False)expr_group.knob("selected").setValue(True)refo = nuke.createNode('Reformat')refo.knob("resize").setValue("distort")refo.knob("filter").setValue(0)nuke.connectViewer(1,a)nuke.connectViewer(0,refo)
