• API
• FAQ
• Tools
• Archive
SHARE
TWEET

# RGBtoMSX_python

a guest Mar 31st, 2019 25 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
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.
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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy.

Top