Loading

palette-converter_v9.py

  1. import math
  2. import time
  3. import datetime
  4. import os
  5. from os import remove
  6. from PIL import Image
  7. from multiprocessing import Process
  8.  
  9. #starting message
  10. print("-"*79)
  11. print("Starting...")
  12.  
  13. #path definition
  14. diskPath = "C:/Users/Pavel/Downloads/scripts/"#"E:/_BRIX/_BRIX-repository/scripts/"
  15. inputFolder = diskPath + "input/"
  16. outputFolder = diskPath + "output/"
  17.  
  18. #printing path just to check
  19. print("inputFolder is " + inputFolder)
  20. print("outputFolder is " + outputFolder)
  21.  
  22. #started time
  23. tt = time.time()
  24. startedTime = datetime.datetime.fromtimestamp(tt).strftime('%H:%M:%S')
  25.  
  26.  
  27.  
  28. #open palette image
  29. palette = Image.open(inputFolder + "openttd-palette-dos.png")
  30. print("Opening and loading palette: " + "openttd-palette-dos.png")  
  31.  
  32. p=[]
  33.  
  34. for b in range(0,palette.height):
  35.   for a in range(0, palette.width):
  36.     p.append(palette.getpixel((a,b)))
  37.    
  38. print('Palette loaded.')
  39.  
  40. # ----------------------------------------------------------------------------------------------------------------
  41. # ----------------------------------------------------------------------------------------------------------------
  42. # ----------------------------------------------------------------------------------------------------------------
  43.  
  44.  
  45. def rgb2palette(input_image, x_start, x_end):
  46.   #open input image
  47.   i = Image.open(inputFolder + input_image + ".png")
  48.   print("Opening: " + input_image + ".png")  
  49.  
  50.   #create new empty image for output
  51.   imageOutput = Image.new("RGBA", (i.width,i.height), color=(0,0,0,0))
  52.  
  53.   for y in range (0, i.height):
  54.     #timeStamp
  55.     ts = time.time()
  56.     timeStamp = datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S')
  57.     #print(timeStamp + " - " + input_image + " row {}".format(y))
  58.     for x in range (x_start, x_end):
  59.       print(timeStamp + " - " + input_image + " row {}".format(x))
  60.       #defining winner variables
  61.       winnerDistance = 100000000
  62.       winnerID = 0
  63.      
  64.       #loading pixel from image and separating RGBA
  65.       pixelNumber = x + (y * i.width)
  66.       pix = i.getpixel((x,y))
  67.       pixRed = pix[0]
  68.       pixGreen = pix[1]
  69.       pixBlue = pix[2]
  70.       pixAlpha = pix[3]
  71.            
  72.       #check Alpha in pixel, and output alpha/color offset
  73.       if pixAlpha < 128:
  74.         finalAlpha = 0
  75.         colorOffset = 0
  76.       if pixAlpha >= 128 and pixAlpha < 178:
  77.         finalAlpha = 255
  78.         colorOffset = 1
  79.       if pixAlpha >= 178 and pixAlpha < 230:
  80.         finalAlpha = 255
  81.         colorOffset = 2
  82.       if pixAlpha >= 230:
  83.         finalAlpha = 255
  84.         colorOffset = 0
  85.      
  86.       #if alpha above 50%, do colour comparing to palette
  87.       if pixAlpha >= 128:
  88.         for z, (r1, g1, b1, ca) in enumerate(p):
  89.           #dr = pixRed - cr
  90.           #dg = pixGreen - cg
  91.           #db = pixBlue - cb
  92.           #distance = dr*dr + dg*dg + db*db
  93.           l1 = (r1*299 + g1*587 + b1*114) / 255000
  94.           l2 = (pixRed*299 + pixGreen*587 + pixBlue*114) / 255000
  95.           dL = l1-l2
  96.           dR = (r1-pixRed)/255
  97.           dG = (g1-pixGreen)/255
  98.           dB = (b1-pixBlue)/255
  99.           distance = (dR*dR*0.299 + dG*dG*0.587 + dB*dB*0.114)*0.75 + dL*dL
  100.          
  101.           if distance < winnerDistance:
  102.             winnerDistance = distance
  103.             winnerID = z
  104.    
  105.       #compare input RGB channels and output highest value
  106.       if pixRed >= pixGreen and pixRed >= pixBlue:
  107.         highestValue = pixRed
  108.       if pixGreen >= pixRed and pixGreen >= pixBlue:
  109.         highestValue = pixGreen
  110.       if pixBlue >= pixRed and pixBlue >= pixGreen:
  111.         highestValue = pixBlue    
  112.       # set color offset +/- based on colour value
  113.       if highestValue < 128:
  114.         negation = -1
  115.         colorOffset = colorOffset * negation
  116.       #print("colorOffset is ... " + str(colorOffset) )
  117.      
  118.       #final color changed by colorOffset
  119.       finalColor = p[winnerID - colorOffset]
  120.      
  121.       finalR = finalColor[0]
  122.       finalG = finalColor[1]
  123.       finalB = finalColor[2]
  124.       #finalAlpha taken from the if output above palette colour comparing
  125.      
  126.       #put the final pixel into the output picture
  127.       imageOutput.putpixel((x,y),(finalR,finalG,finalB,finalAlpha))
  128.       #print("Pixel " + str(pixelNumber) + ": R= " + str(finalR) + ", G= " + str(finalG) + ", B= " + str(finalB) + ", A= "  + str(finalAlpha)   )
  129.          
  130.      
  131.   os.makedirs(outputFolder, exist_ok = True)
  132.   imageOutput.save(outputFolder + input_image[-5:] + "_8bpp.png") #assumes _#### frame number format (removes last 5 characters)
  133.  
  134.   #finished time
  135.   tx = time.time()
  136.   finishedTime = datetime.datetime.fromtimestamp(tx).strftime('%H:%M:%S')
  137.  
  138.   print("Started:  " + startedTime)
  139.   print("Finished: " + finishedTime)
  140.  
  141.  
  142.      
  143.      
  144. def run():
  145.   # ----------------------------------------------------------------------------------------------------------------
  146.   #VARIABLES
  147.   # ----------------------------------------------------------------------------------------------------------------
  148.   job_list = [
  149.       'test0'
  150.       #'BRIDGES_0000',
  151.       #'LAND_OUTPUT_0000'
  152.       ]
  153.   # ----------------------------------------------------------------------------------------------------------------
  154.   thread_count = 4
  155.   # ----------------------------------------------------------------------------------------------------------------
  156.   # ----------------------------------------------------------------------------------------------------------------
  157.   # ----------------------------------------------------------------------------------------------------------------
  158.  
  159.   for job in job_list:
  160.     all_jobs = []
  161.     job_chunks = []
  162.     q = []
  163.  
  164.     extra = 0
  165.     chunk_image = Image.open(inputFolder + job + ".png")
  166.     chunk_average_size = math.floor(chunk_image.width/thread_count)
  167.     chunk_modulo_size = chunk_image.width % thread_count
  168.     for thread in range(0, thread_count):
  169.       start = chunk_average_size * thread
  170.       end = (chunk_average_size * (thread+1)) -1
  171.  
  172.       start += extra
  173.       if thread < chunk_modulo_size:  
  174.         extra += 1
  175.       end += extra
  176.  
  177.       start_and_end = [job, start, end]
  178.      
  179.       job_chunks.append(start_and_end)
  180.  
  181.       q.append( Process(target = rgb2palette, args= (job,start,end)) )
  182.    
  183.     #for ch in range(0, chunk_modulo_size):
  184.     #  job_chunks[ch] += 1
  185.     all_jobs.append(job_chunks)
  186.  
  187.     printList_thread = []
  188.     printList_start = []
  189.     printList_end = []
  190.  
  191.     for a_job in all_jobs:
  192.       print('-'*32)#
  193.       thread_id = 0
  194.       for b_thread in a_job:
  195.         if thread_id == 0:
  196.           printList_thread.append(b_thread[0])
  197.           thread_id += 1
  198.           print('Job: ' + str(b_thread[0]))#
  199.           print(' '*10 + 'Start, ' + 'End')#
  200.         printList_start.append(b_thread[1])
  201.         printList_end.append(b_thread[2])
  202.         print('Thread ' + str(thread_id) + ': ' + str(b_thread[1]) + ', ' + str(b_thread[2]))#
  203.    
  204.     print(all_jobs)
  205.    
  206.     # ----------------------------------------------------------------------------------------------------------------
  207.     # PROCESS
  208.     # ----------------------------------------------------------------------------------------------------------------
  209.    
  210.     for process in range(thread_count):
  211.       print('Process count' + str(process))
  212.       q[process].start()
  213.     for process in range(thread_count):
  214.       q[process].join()
  215.      
  216.  
  217.   #for a_text in printList_thread:
  218.   #  print('Job:' + str(a_text))
  219.   #  for b_text in printList_start:
  220.   #   #list_id = 0
  221.   #   print('Thread:' + str(b_text))
  222.      
  223.  
  224. import traceback
  225.  
  226. try:
  227.  
  228.   run()
  229.    
  230.  
  231. except Exception as e:
  232.  
  233.   traceback.print_exc()
  234.  
  235. input("Press enter to continue...")

Comments