Advertisement
Guest User

RGBtoMSX_python

a guest
Mar 31st, 2019
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.23 KB | None | 0 0
  1. '''
  2. ----------------------------------------------------------------------------
  3. RGB Image to MSX Converter
  4.  
  5. Original Graphic routine To convert RGB images To MSX1 video,
  6. made in BlitzBasic by Leandro Correia (www.leandrocorreia.com)
  7.  
  8. python 2.7 converted by MsxKun (uses PIL library)
  9. ----------------------------------------------------------------------------
  10. '''
  11.  
  12. #from os.path import basename, splitext, dirname, abspath
  13.  
  14. import sys
  15. import math
  16.  
  17. from PIL import Image, ImageDraw
  18.  
  19. '''
  20. ----------------------------------------------------------------------------
  21. Calculate Distance Function
  22. ----------------------------------------------------------------------------
  23.  
  24. Convert two RGB color values into Lab and uses the CIEDE2000 formula to calculate
  25. the distance between them.
  26. This function first converts RGBs to XYZ and then to Lab.
  27.  
  28. This is not optimized, but I did my best to make it readable.
  29. In some rare cases there are some weird colors, so MAYBE there's a small bug in
  30. the implementation.
  31. Or it could be improved since RGB To Lab is Not a direct conversion.
  32.  
  33. Note: As we're using PIL, maybe we can do this (need to check):
  34.  
  35. The following example converts an RGB image (linearly calibrated according to
  36. ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
  37.  
  38. rgb2xyz = (
  39.    0.412453, 0.357580, 0.180423, 0,
  40.    0.212671, 0.715160, 0.072169, 0,
  41.    0.019334, 0.119193, 0.950227, 0 )
  42. out = im.convert("RGB", rgb2xyz)
  43.  
  44. '''
  45.  
  46. def calcdist2000(r1, g1, b1, r2, g2, b2):
  47.  
  48.     ''' Converting RGB values into XYZ - color 1'''
  49.  
  50.     r = r1/255.0
  51.     g = g1/255.0
  52.     b = b1/255.0  
  53.    
  54.     r = ((r+0.055)/1.055)**2.4 if (r > 0.04045) else r/12.92
  55.     g = ((g+0.055)/1.055)**2.4 if (g > 0.04045) else g/12.92
  56.     b = ((b+0.055)/1.055)**2.4 if (b > 0.04045) else b/12.92
  57.    
  58.     r = r*100.0
  59.     g = g*100.0
  60.     b = b*100.0
  61.    
  62.     x = r*0.4124 + g*0.3576 + b*0.1805
  63.     y = r*0.2126 + g*0.7152 + b*0.0722
  64.     z = r*0.0193 + g*0.1192 + b*0.9505
  65.  
  66.     x = x/95.047
  67.     y = y/100.000
  68.     z = z/108.883
  69.  
  70.     x = x**(1.0/3.0) if (x > 0.008856) else (7.787*x) + (16.0/116.0)
  71.     y = y**(1.0/3.0) if (y > 0.008856) else (7.787*y) + (16.0/116.0)
  72.     z = z**(1.0/3.0) if (z > 0.008856) else (7.787*z) + (16.0/116.0)
  73.  
  74.     ''' Converts XYZ to Lab... '''
  75.  
  76.     l1 = (116*y)-16.0
  77.     a1 = 500.0*(x-y)
  78.     b1 = 200.0*(y-z)
  79.  
  80.     ''' Converting RGB values into XYZ - color 2'''
  81.  
  82.     r = r2/255.0
  83.     g = g2/255.0
  84.     b = b2/255.0
  85.    
  86.     r = ((r+0.055)/1.055)**2.4 if (r > 0.04045) else r/12.92
  87.     g = ((g+0.055)/1.055)**2.4 if (g > 0.04045) else g/12.92
  88.     b = ((b+0.055)/1.055)**2.4 if (b > 0.04045) else b/12.92
  89.  
  90.     r = r*100.0
  91.     g = g*100.0
  92.     b = b*100.0
  93.  
  94.     x = r*0.4124 + g*0.3576 + b*0.1805
  95.     y = r*0.2126 + g*0.7152 + b*0.0722
  96.     z = r*0.0193 + g*0.1192 + b*0.9505
  97.    
  98.     x = x/95.047
  99.     y = y/100.000
  100.     z = z/108.883
  101.    
  102.     x = x**(1.0/3.0) if (x > 0.008856) else (7.787*x) + (16.0/116.0)
  103.     y = y**(1.0/3.0) if (y > 0.008856) else (7.787*y) + (16.0/116.0)
  104.     z = z**(1.0/3.0) if (z > 0.008856) else (7.787*z) + (16.0/116.0)
  105.  
  106.     ''' Converts XYZ to Lab... '''
  107.  
  108.     l2 = (116*y)-16.0
  109.     a2 = 500.0*(x-y)
  110.     b2 = 200.0*(y-z)
  111.  
  112.     ''' ...and then calculates distance between Lab colors, using the CIEDE2000 formula. '''
  113.  
  114.     dl = l2-l1
  115.     hl = l1+dl*0.5
  116.     sqb1 = b1*b1
  117.     sqb2 = b2*b2
  118.     c1 = math.sqrt(a1*a1+sqb1)
  119.     c2 = math.sqrt(a2*a2+sqb2)
  120.     hc7 = ((c1+c2)*0.5)**7
  121.     trc = math.sqrt(hc7/(hc7+6103515625.0))
  122.     t2 = 1.5-trc*0.5
  123.     ap1 = a1*t2
  124.     ap2 = a2*t2
  125.     c1 = math.sqrt(ap1*ap1+sqb1)
  126.     c2 = math.sqrt(ap2*ap2+sqb2)
  127.     dc = c2-c1
  128.     hc = c1+dc*0.5
  129.     hc7 = hc**7.0
  130.     trc = math.sqrt(hc7/(hc7+6103515625.0))
  131.     h1 = math.atan2(b1,ap1)
  132.     if (h1 < 0):
  133.         h1 = h1+math.pi*2.0
  134.     h2 = math.atan2(b2,ap2)
  135.     if (h2 < 0):
  136.          h2 = h2+math.pi*2.0
  137.     hdiff = h2-h1
  138.     hh = h1+h2
  139.  
  140.     if (math.fabs(hdiff) > math.pi):
  141.         hh = hh + math.pi*2
  142.         if (h2 <= h1):
  143.             hdiff = hdiff + math.pi*2.0
  144.     else:
  145.         hdiff = hdiff-math.pi*2.0
  146.    
  147.     hh = hh*0.5
  148.     t2 = 1-0.17*math.cos(hh-math.pi/6)+0.24*math.cos(hh*2)
  149.     t2 = t2+0.32*math.cos(hh*3+math.pi/30.0)
  150.     t2 = t2-0.2*math.cos(hh*4-math.pi*63/180.0)
  151.     dh = 2*math.sqrt(c1*c2)*math.sin(hdiff*0.5)
  152.     sqhl = (hl-50)*(hl-50)
  153.     fl = dl/(1+(0.015*sqhl/squaretable[20+int(sqhl)])) # here sqr lookup table is used!
  154.     #fl = dl/(1+(0.015*sqhl/math.sqrt(20.0+sqhl))) # here not using sqr lookup table
  155.     fc = dc/(hc*0.045+1.0)
  156.     fh = dh/(t2*hc*0.015+1.0)
  157.     dt = 30*math.exp(-(36.0*hh-55.0*math.pi**2.0)/(25.0*math.pi*math.pi))
  158.     r = 0-2*trc*math.sin(2.0*dt*math.pi/180.0)
  159.  
  160.     return math.sqrt(fl*fl+fc*fc+fh*fh+r*fc*fh)
  161.    
  162. '''
  163. ----------------------------------------------------------------------------
  164. Main Code
  165. ----------------------------------------------------------------------------
  166. '''
  167.  
  168. ''' Image to be loaded and converted '''
  169.  
  170. #inputfile=str(sys.argv[1])
  171.  
  172. inputfile = "gameover.png"
  173. outputfile = "gameover.sc2"
  174. previewfile = "gameover_converted.bmp"
  175.  
  176. input_im = Image.open(inputfile)            # Can be many different formats.
  177. pix = input_im.load()
  178. input_im.show()
  179.  
  180. output_im = Image.new('RGB', (256,192), color = 'white')
  181. draw = ImageDraw.Draw(output_im)
  182.  
  183. '''
  184. Color tolerance for dithering (from 0 to 100).
  185. Higher values mean dithering between colors that are not similar,
  186. which results in better color accuracy but ugly squares on degradees.
  187. 0 means no dithering
  188. '''
  189.  
  190. tolerance = 100
  191.  
  192. ''' Data of the MSX palette RGB values '''
  193.  
  194. palette = [0,0,0,0,0,0,36,219,36,109,255,109,36,36,255,73,109,255,182,36,36,73,219,
  195.             255,255,36,36,255,109,109,219,219,36,219,219,146,36,146,36,219,73,182,182,
  196.             182,182,255,255,255]
  197.  
  198. msxr = palette[0::3]
  199. msxg = palette[1::3]
  200. msxb = palette[2::3]
  201.  
  202. color = [0,0,0]
  203.  
  204. octetr = [0] *8
  205. octetg = [0] *8
  206. octetb = [0] *8
  207.  
  208. octetfinal = [0] *8
  209. octetvalue = [0] *8
  210.  
  211. toner = [0] *5
  212. toneg = [0] *5
  213. toneb = [0] *5
  214. distcolor = [0] *5
  215.  
  216. ''' Lookup table to make squareroots quicker... '''
  217.  
  218. squaretable = [0] *9999999
  219.  
  220. for i in range(9999999):
  221.     squaretable[i]=math.sqrt(i)
  222.  
  223. ''' Loop '''
  224.  
  225. imgh = 192
  226. imgw = 256
  227. y = 0
  228. x = 0
  229.  
  230. while y < 192:
  231.    
  232.     bestdistance = 99999999
  233.  
  234.     ''' Get the RGB values of 8 pixels of the original image '''
  235.  
  236.     for i in range(8)
  237.  
  238.         rgba = pix[x+i,y]       # Get the RGBA Value of the a pixel of an image
  239.         octetr[i] = rgba[0]
  240.         octetg[i] = rgba[1]
  241.         octetb[i] = rgba[2]
  242.  
  243.     ''' Brute force starts. Program tests all 15 x 15 MSX color combinations.
  244.         For each pixel octet it'll have to compare the original pixel colors with
  245.         three diffent colors: two MSX colors and a mixed RGB of both. '''
  246.  
  247.     cor1 = 0
  248.     cor2 = 0
  249.  
  250.     for cor1 in range(1,16):
  251.         for cor2 in range(cor1,16):
  252.  
  253.             dist = 0
  254.  
  255.             ''' First MSX color of the octet '''
  256.  
  257.             toner[0] = msxr [cor1]
  258.             toneg[0] = msxg [cor1]
  259.             toneb[0] = msxb [cor1]
  260.  
  261.             ''' Second MSX color of the octet '''
  262.  
  263.             toner[2] = msxr [cor2]
  264.             toneg[2] = msxg [cor2]
  265.             toneb[2] = msxb [cor2]
  266.  
  267.             ''' A mix of both MSX colors RGB values. Since MSX cannot mix colors, later
  268.                 if this color is chosen it'll be substituted by a 2x2 dithering pattern. '''
  269.  
  270.             toner[1] = (msxr[cor1] + msxr[cor2]) / 2
  271.             toneg[1] = (msxg[cor1] + msxg[cor2]) / 2
  272.             toneb[1] = (msxb[cor1] + msxb[cor2]) / 2
  273.  
  274.             cd = calcdist2000(msxr[cor1],msxg[cor1],msxb[cor1],msxr[cor2],msxg[cor2],msxb[cor2])
  275.  
  276.             ''' If colors are not too distant, octect can be either dithered or not '''
  277.  
  278.             if (cd <= tolerance):
  279.  
  280.                 ''' dithered '''
  281.  
  282.                 for i in range(8):
  283.                    
  284.                     for j in range(3):
  285.                         distcolor[j] = calcdist2000(toner[j],toneg[j],toneb[j],octetr[i],octetg[i],octetb[i])
  286.  
  287.                     finaldist = distcolor[0]
  288.                     octetvalue[i] = 0
  289.  
  290.                     for j in range(3):
  291.                         if (distcolor[j] < finaldist):
  292.                             finaldist = distcolor[j]
  293.                             octetvalue[i] = j
  294.  
  295.                     dist = dist + finaldist
  296.                    
  297.                     if (dist > bestdistance):
  298.                         break
  299.  
  300.             else:
  301.  
  302.                 ''' not dithered '''
  303.  
  304.                 for i in range(8):
  305.  
  306.                     finaldista = calcdist2000(toner[0],toneg[0],toneb[0],octetr[i],octetg[i],octetb[i])
  307.                     finaldistb = calcdist2000(toner[2],toneg[2],toneb[2],octetr[i],octetg[i],octetb[i])
  308.  
  309.                     if (finaldista < finaldistb):
  310.                         octetvalue[i] = 0
  311.                         finaldist = finaldista
  312.                     else:
  313.                         octetvalue[i] = 2
  314.                         finaldist = finaldistb
  315.  
  316.                     dist = dist + finaldist
  317.  
  318.                     if (dist > bestdistance):
  319.                         break
  320.  
  321.             if (dist < bestdistance):
  322.  
  323.                 bestdistance = dist
  324.                 bestcor1 = cor1
  325.                 bestcor2 = cor2
  326.                 for i in range (8):
  327.                     octetfinal[i] = octetvalue[i]
  328.  
  329.             if (bestdistance == 0):
  330.                 break
  331.  
  332.         if (bestdistance == 0):
  333.                 break
  334.  
  335.     byte = 0
  336.  
  337.     for i in range(8):
  338.  
  339.         if (octetfinal[i] == 0):
  340.             color = [msxr[bestcor1],msxg[bestcor1],msxb[bestcor1]]
  341.            
  342.         elif (octetfinal[i] == 1):
  343.             if ((y % 2) == (i % 2)):
  344.                 color = [msxr[bestcor2],msxg[bestcor2],msxb[bestcor2]]
  345.                 byte = byte + 2 ** (7-i)
  346.             else:
  347.                 color = [msxr[bestcor1],msxg[bestcor1],msxb[bestcor1]]
  348.                
  349.         elif (octetfinal[i] == 2):
  350.             color = [msxr[bestcor2],msxg[bestcor2],msxb[bestcor2]]
  351.             byte = byte + 2 ** (7 - i)
  352.  
  353.         draw.point((x + i, y), fill=(color[0],color[1],color[2]))
  354.  
  355.     y = y + 1
  356.  
  357.     if ((y % 8) == 0):
  358.  
  359.         y = y - 8
  360.         x = x + 8
  361.  
  362.     if (x > 255):
  363.         x = 0
  364.         y = y + 8
  365.  
  366.     # This would be the place for you to write the bytes in the final MSX screen file.
  367.     #output.append(byte) # ???
  368.  
  369. ''' Shows output image '''
  370.  
  371. output_im.show()       
  372. output_im.save(previewfile,"BMP")
  373.  
  374. ''' Save File SC2 '''
  375.  
  376. # To Do
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement