spectrum2rgb.c
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:11k
源码类别:

OpenGL

开发平台:

Visual C++

  1. /* Copyright 2006, Matt Wronkiewicz
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 
  8.  *     * Redistributions of source code must retain the above copyright
  9.  *       notice, this list of conditions and the following disclaimer.
  10.  *     * Redistributions in binary form must reproduce the above copyright
  11.  *       notice, this list of conditions and the following disclaimer in
  12.  *       the documentation and/or other materials provided with the distribution.
  13.  *     * The name of Matt Wronkiewicz may be used to endorse or promote products
  14.  *       derived from this software without specific prior written permission.
  15.  * 
  16.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  20.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  21.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  22.  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  24.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  25.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <math.h>
  30. struct XYZs {
  31. float X;
  32. float Y;
  33. float Z;
  34. };
  35. struct spectrum {
  36.     float intensity;
  37.     int samples;
  38. };
  39. static struct spectrum spectrum[95];
  40. static float solar_spectrum[95];
  41. static struct XYZs cmfXYZ[] = {
  42. /*360*/ {0.000000122200f, 0.000000013398f, 0.000000535027f},
  43. /*365*/ {0.000000919270f, 0.000000100650f, 0.000004028300f},
  44. /*370*/ {0.000005958600f, 0.000000651100f, 0.000026143700f},
  45. /*375*/ {0.000033266000f, 0.000003625000f, 0.000146220000f},
  46. /*380*/ {0.000159952000f, 0.000017364000f, 0.000704776000f},
  47. /*385*/ {0.000662440000f, 0.000071560000f, 0.002927800000f},
  48. /*390*/ {0.002361600000f, 0.000253400000f, 0.010482200000f},
  49. /*395*/ {0.007242300000f, 0.000768500000f, 0.032344000000f},
  50. /*400*/ {0.019109700000f, 0.002004400000f, 0.086010900000f},
  51. /*405*/ {0.043400000000f, 0.004509000000f, 0.197120000000f},
  52. /*410*/ {0.084736000000f, 0.008756000000f, 0.389366000000f},
  53. /*415*/ {0.140638000000f, 0.014456000000f, 0.656760000000f},
  54. /*420*/ {0.204492000000f, 0.021391000000f, 0.972542000000f},
  55. /*425*/ {0.264737000000f, 0.029497000000f, 1.282500000000f},
  56. /*430*/ {0.314679000000f, 0.038676000000f, 1.553480000000f},
  57. /*435*/ {0.357719000000f, 0.049602000000f, 1.798500000000f},
  58. /*440*/ {0.383734000000f, 0.062077000000f, 1.967280000000f},
  59. /*445*/ {0.386726000000f, 0.074704000000f, 2.027300000000f},
  60. /*450*/ {0.370702000000f, 0.089456000000f, 1.994800000000f},
  61. /*455*/ {0.342957000000f, 0.106256000000f, 1.900700000000f},
  62. /*460*/ {0.302273000000f, 0.128201000000f, 1.745370000000f},
  63. /*465*/ {0.254085000000f, 0.152761000000f, 1.554900000000f},
  64. /*470*/ {0.195618000000f, 0.185190000000f, 1.317560000000f},
  65. /*475*/ {0.132349000000f, 0.219940000000f, 1.030200000000f},
  66. /*480*/ {0.080507000000f, 0.253589000000f, 0.772125000000f},
  67. /*485*/ {0.041072000000f, 0.297665000000f, 0.570600000000f},
  68. /*490*/ {0.016172000000f, 0.339133000000f, 0.415254000000f},
  69. /*495*/ {0.005132000000f, 0.395379000000f, 0.302356000000f},
  70. /*500*/ {0.003816000000f, 0.460777000000f, 0.218502000000f},
  71. /*505*/ {0.015444000000f, 0.531360000000f, 0.159249000000f},
  72. /*510*/ {0.037465000000f, 0.606741000000f, 0.112044000000f},
  73. /*515*/ {0.071358000000f, 0.685660000000f, 0.082248000000f},
  74. /*520*/ {0.117749000000f, 0.761757000000f, 0.060709000000f},
  75. /*525*/ {0.172953000000f, 0.823330000000f, 0.043050000000f},
  76. /*530*/ {0.236491000000f, 0.875211000000f, 0.030451000000f},
  77. /*535*/ {0.304213000000f, 0.923810000000f, 0.020584000000f},
  78. /*540*/ {0.376772000000f, 0.961988000000f, 0.013676000000f},
  79. /*545*/ {0.451584000000f, 0.982200000000f, 0.007918000000f},
  80. /*550*/ {0.529826000000f, 0.991761000000f, 0.003988000000f},
  81. /*555*/ {0.616053000000f, 0.999110000000f, 0.001091000000f},
  82. /*560*/ {0.705224000000f, 0.997340000000f, 0.000000000000f},
  83. /*565*/ {0.793832000000f, 0.982380000000f, 0.000000000000f},
  84. /*570*/ {0.878655000000f, 0.955552000000f, 0.000000000000f},
  85. /*575*/ {0.951162000000f, 0.915175000000f, 0.000000000000f},
  86. /*580*/ {1.014160000000f, 0.868934000000f, 0.000000000000f},
  87. /*585*/ {1.074300000000f, 0.825623000000f, 0.000000000000f},
  88. /*590*/ {1.118520000000f, 0.777405000000f, 0.000000000000f},
  89. /*595*/ {1.134300000000f, 0.720353000000f, 0.000000000000f},
  90. /*600*/ {1.123990000000f, 0.658341000000f, 0.000000000000f},
  91. /*605*/ {1.089100000000f, 0.593878000000f, 0.000000000000f},
  92. /*610*/ {1.030480000000f, 0.527963000000f, 0.000000000000f},
  93. /*615*/ {0.950740000000f, 0.461834000000f, 0.000000000000f},
  94. /*620*/ {0.856297000000f, 0.398057000000f, 0.000000000000f},
  95. /*625*/ {0.754930000000f, 0.339554000000f, 0.000000000000f},
  96. /*630*/ {0.647467000000f, 0.283493000000f, 0.000000000000f},
  97. /*635*/ {0.535110000000f, 0.228254000000f, 0.000000000000f},
  98. /*640*/ {0.431567000000f, 0.179828000000f, 0.000000000000f},
  99. /*645*/ {0.343690000000f, 0.140211000000f, 0.000000000000f},
  100. /*650*/ {0.268329000000f, 0.107633000000f, 0.000000000000f},
  101. /*655*/ {0.204300000000f, 0.081187000000f, 0.000000000000f},
  102. /*660*/ {0.152568000000f, 0.060281000000f, 0.000000000000f},
  103. /*665*/ {0.112210000000f, 0.044096000000f, 0.000000000000f},
  104. /*670*/ {0.081260600000f, 0.031800400000f, 0.000000000000f},
  105. /*675*/ {0.057930000000f, 0.022601700000f, 0.000000000000f},
  106. /*680*/ {0.040850800000f, 0.015905100000f, 0.000000000000f},
  107. /*685*/ {0.028623000000f, 0.011130300000f, 0.000000000000f},
  108. /*690*/ {0.019941300000f, 0.007748800000f, 0.000000000000f},
  109. /*695*/ {0.013842000000f, 0.005375100000f, 0.000000000000f},
  110. /*700*/ {0.009576880000f, 0.003717740000f, 0.000000000000f},
  111. /*705*/ {0.006605200000f, 0.002564560000f, 0.000000000000f},
  112. /*710*/ {0.004552630000f, 0.001768470000f, 0.000000000000f},
  113. /*715*/ {0.003144700000f, 0.001222390000f, 0.000000000000f},
  114. /*720*/ {0.002174960000f, 0.000846190000f, 0.000000000000f},
  115. /*725*/ {0.001505700000f, 0.000586440000f, 0.000000000000f},
  116. /*730*/ {0.001044760000f, 0.000407410000f, 0.000000000000f},
  117. /*735*/ {0.000727450000f, 0.000284041000f, 0.000000000000f},
  118. /*740*/ {0.000508258000f, 0.000198730000f, 0.000000000000f},
  119. /*745*/ {0.000356380000f, 0.000139550000f, 0.000000000000f},
  120. /*750*/ {0.000250969000f, 0.000098428000f, 0.000000000000f},
  121. /*755*/ {0.000177730000f, 0.000069819000f, 0.000000000000f},
  122. /*760*/ {0.000126390000f, 0.000049737000f, 0.000000000000f},
  123. /*765*/ {0.000090151000f, 0.000035540500f, 0.000000000000f},
  124. /*770*/ {0.000064525800f, 0.000025486000f, 0.000000000000f},
  125. /*775*/ {0.000046339000f, 0.000018338400f, 0.000000000000f},
  126. /*780*/ {0.000033411700f, 0.000013249000f, 0.000000000000f},
  127. /*785*/ {0.000024209000f, 0.000009619600f, 0.000000000000f},
  128. /*790*/ {0.000017611500f, 0.000007012800f, 0.000000000000f},
  129. /*795*/ {0.000012855000f, 0.000005129800f, 0.000000000000f},
  130. /*800*/ {0.000009413630f, 0.000003764730f, 0.000000000000f},
  131. /*805*/ {0.000006913000f, 0.000002770810f, 0.000000000000f},
  132. /*810*/ {0.000005093470f, 0.000002046130f, 0.000000000000f},
  133. /*815*/ {0.000003767100f, 0.000001516770f, 0.000000000000f},
  134. /*820*/ {0.000002795310f, 0.000001128090f, 0.000000000000f},
  135. /*825*/ {0.000002082000f, 0.000000842160f, 0.000000000000f},
  136. /*830*/ {0.000001553140f, 0.000000629700f, 0.000000000000f}
  137. };
  138. static float interpolate_linear_f(const float xa, const float ya,
  139. const float xb, const float yb, const float x) {
  140.     const float interval = xb - xa;
  141.     const float dx = (interval == 0)?0:(x - xa)/interval;
  142.     return ya + (yb - ya)*dx;
  143. }
  144. int main(const int argc, const char* const* const argv) {
  145.     if (argc < 3) {
  146.         fprintf(stderr, "Usage: [path to solar spectrum] [path to asteroid spectrum]n");
  147.         fprintf(stderr, "Solar spectrum must be a list in the formatn"
  148.             "t'[wavelength in nm] [intensity]'n");
  149.         fprintf(stderr, "Asteroid spectrum must be a list in the formatn"
  150.             "t'[wavelength in microns] [reflectiveness]'n");
  151.         fprintf(stderr, "All list values must be in easily digestable floating point formatn");
  152.         fprintf(stderr, "Data files from sets 2, 7, and 8 of SMASS are in the correct formatn");
  153.         return -1;
  154.     }
  155.     /* Zero out the asteroid spectrum */
  156.     int i = 0;
  157.     for (; i < 95; i++) {
  158.         spectrum[i].samples = 0;
  159.         spectrum[i].intensity = 0;
  160.     }
  161.     FILE* const input = fopen(argv[2], "r");
  162.     int first_wave = 0;
  163.     float first_i = 0;
  164.     while (1) {
  165.         char line[256];
  166.         char* read_ptr = fgets(line, 256, input);
  167.         if (read_ptr == NULL)
  168.             break;
  169.         const float wave_f = strtod(read_ptr, &read_ptr);
  170.         const int wave = wave_f > 10?wave_f:wave_f*10000;
  171.         if (wave == 0)
  172.             continue;
  173.         if (wave < 3600 || wave > 8300)
  174.             continue;
  175.         const float intensity = strtod(read_ptr, NULL);
  176.         spectrum[(wave - 3600 + 25)/50].samples++;
  177.         spectrum[(wave - 3600 + 25)/50].intensity += intensity;
  178.         if (first_wave == 0) {
  179.             first_wave = wave;
  180.             first_i = intensity;
  181.         }
  182.     }
  183.     fclose(input);
  184.     FILE* const sol_input = fopen(argv[1], "r");
  185.     if (sol_input == NULL) {
  186. fprintf(stderr, "Couldn't open solar spectrumn");
  187. return -1;
  188.     }
  189.     while (1) {
  190.         char line[256];
  191.         char* read_ptr = fgets(line, 256, sol_input);
  192.         if (read_ptr == NULL)
  193.             break;
  194.         const int wave = strtod(read_ptr, &read_ptr);
  195. if (wave == 0)
  196.     continue;
  197. if (wave > 830)
  198.     continue;
  199.         const float intensity = strtod(read_ptr, NULL);
  200.         solar_spectrum[(wave - 360)/5] = intensity;
  201.     }
  202.     fclose(sol_input);
  203.     
  204.     float X = 0;
  205.     float Y = 0;
  206.     float Z = 0;
  207.     int w = 360;
  208.     for (; w <= 830; w += 5) {
  209.         const int tblI = (w - 360)/5;
  210.         float intensity = interpolate_linear_f(0, 0, first_wave/10, first_i, w);
  211.         if (intensity > first_i) { intensity = first_i; }
  212.         if (intensity < 0) intensity = 0;
  213.         if (spectrum[tblI].samples > 0)
  214.             intensity = spectrum[tblI].intensity/spectrum[tblI].samples;
  215.         /* Convert reflective value to emissive */
  216.         intensity *= solar_spectrum[tblI];
  217.         /*printf("%d %.3fn", w, intensity);*/
  218.         /* The color perception table has been trimmed to 1/5th its original
  219.          * size. Scale the values accordingly. */
  220.         intensity *= 5;
  221.         X += cmfXYZ[tblI].X*intensity;
  222.         Y += cmfXYZ[tblI].Y*intensity;
  223.         Z += cmfXYZ[tblI].Z*intensity;
  224.     }
  225.     /* The color perception table adds up to 100 instead of 1 */
  226.     X /= 100.0f;
  227.     Y /= 100.0f;
  228.     Z /= 100.0f;
  229.     /* Convert the XYZ colors into RGB */
  230.     float r = X*3.24f - Y*1.54f - Z*0.50f;
  231.     float g = -X*0.97f + Y*1.88f + Z*0.04f;
  232.     float b = X*0.06f - Y*0.20f + Z*1.06f;
  233.     
  234.     /* Gamma correction */
  235.     /* I am not sure that this is necessary or correct. It has the effect of de-saturating
  236.      * the asteroid colors. */
  237.     r = 1.055f*pow(r, 1/2.0f) - 0.055f;
  238.     g = 1.055f*pow(g, 1/2.0f) - 0.055f;
  239.     b = 1.055f*pow(b, 1/2.0f) - 0.055f;
  240.     
  241.     /* Scale values to maximize the luminosity */
  242.     float max = r;
  243.     if (g > max) max = g;
  244.     if (b > max) max = b;
  245.     r /= max;
  246.     g /= max;
  247.     b /= max;
  248.     
  249.     printf("tColor [ %.3f %.3f %.3f ]n", r, g, b);
  250.     return 0;
  251. }