আরজিবিতে হালকা ফ্রিকোয়েন্সি রূপান্তর করবেন?


119

আরজিবি মানকে হালকা ফ্রিকোয়েন্সি রূপান্তর করার কোনও সূত্র কি কেউ জানেন?


2
পদার্থবিদ্যা এবং প্রোগ্রামিংয়ের ক্ষেত্রে খুব প্রযুক্তিগত প্রশ্নসমূহ +1 1
হোটনিক

উত্তর:


44

পুরো রূপান্তর প্রক্রিয়াটির এখানে বিশদ ব্যাখ্যা: http://www.fourmilab.ch/documents/specrend/ । উত্স কোড অন্তর্ভুক্ত!


5
এবং ফোরমিলাব নিবন্ধটি গুরুত্বপূর্ণ বিষয়টিকে তুলে ধরেছে যে কিছু রঙ আরজিবিতে উপস্থাপনযোগ্য নয় (উজ্জ্বল কমলা একটি ভাল উদাহরণ হিসাবে) কারণ আপনি তিনটি প্রাথমিক রঙ একসাথে আলোর রংকে "তৈরি" করতে পারবেন না, আমাদের পদার্থবিজ্ঞানের শিক্ষকরা আমাদের যা যা বলেছিলেন ( ভাল আমার ছিল)। খুব খারাপ, তবে বাস্তবে সাধারণত মারাত্মক হয় না।
ফ্রান্সিস ডেভী

1
এটি ছাড়াও: এন.ইউইকিপিডিয়া.আর / উইকি / এসআরজিবি এসআরজিবি স্ট্যান্ডার্ডকে বহুলভাবে গ্রহণ করার আগে নিবন্ধটি লেখা হয়েছিল। এছাড়াও ফ্রেজ, যা সিআইই মানে 1931 টেবিল কাগজ উৎস সহগামী পাওয়া ব্যবহার করা উচিত এবং সিআইই 1964 "গণনাগুলি 2 ° মান colorimetric পর্যবেক্ষক অনুমান" নোট
GrayFace

কোডটি কীভাবে ব্যবহার করতে হয় তার কয়েকটি উদাহরণ প্রদান করে ভাল লাগবে। এটি আর্গুমেন্ট হিসাবে ফাংশন প্রয়োজন, রঙ এবং এই জাতীয় জিনিস গণনা করতে তাপমাত্রা ব্যবহার করে। কী মুছতে হবে এবং কীভাবে তা কাজে লাগাতে হবে তা পরিবর্তন করে জেনে কেউ খুশি হবেন।
টোমা জ্যাটো - মনিকা

2
এটি লক্ষণীয় যে সমস্ত সম্ভাব্য দৃশ্যমান তরঙ্গদৈর্ঘ্যের কেবলমাত্র একটি ছোট উপসেটটি আরজিবি রঙের জায়গাতে হুবহু উপস্থাপন করা যেতে পারে। রূপান্তর প্রক্রিয়াটি বেশ জটিল এবং অস্পষ্ট। দেখুন physics.stackexchange.com/a/94446/5089 এবং physics.stackexchange.com/a/419628/5089
ভায়োলেট জিরাফ

28

অলস লোকের জন্য (আমার মতো), এখানে @ ব্যবহারকারীর 151323 এর উত্তরে পাওয়া কোডটির জাভা প্রয়োগ করা হয়েছে (এটি স্পেকট্রা ল্যাব রিপোর্টে পাস্কেল কোড থেকে কেবল একটি সহজ অনুবাদ ):

static private final double Gamma = 0.80;
static private final double IntensityMax = 255;

/**
 * Taken from Earl F. Glynn's web page:
 * <a href="http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm">Spectra Lab Report</a>
 */
public static int[] waveLengthToRGB(double Wavelength) {
    double factor;
    double Red, Green, Blue;

    if((Wavelength >= 380) && (Wavelength < 440)) {
        Red = -(Wavelength - 440) / (440 - 380);
        Green = 0.0;
        Blue = 1.0;
    } else if((Wavelength >= 440) && (Wavelength < 490)) {
        Red = 0.0;
        Green = (Wavelength - 440) / (490 - 440);
        Blue = 1.0;
    } else if((Wavelength >= 490) && (Wavelength < 510)) {
        Red = 0.0;
        Green = 1.0;
        Blue = -(Wavelength - 510) / (510 - 490);
    } else if((Wavelength >= 510) && (Wavelength < 580)) {
        Red = (Wavelength - 510) / (580 - 510);
        Green = 1.0;
        Blue = 0.0;
    } else if((Wavelength >= 580) && (Wavelength < 645)) {
        Red = 1.0;
        Green = -(Wavelength - 645) / (645 - 580);
        Blue = 0.0;
    } else if((Wavelength >= 645) && (Wavelength < 781)) {
        Red = 1.0;
        Green = 0.0;
        Blue = 0.0;
    } else {
        Red = 0.0;
        Green = 0.0;
        Blue = 0.0;
    }

    // Let the intensity fall off near the vision limits

    if((Wavelength >= 380) && (Wavelength < 420)) {
        factor = 0.3 + 0.7 * (Wavelength - 380) / (420 - 380);
    } else if((Wavelength >= 420) && (Wavelength < 701)) {
        factor = 1.0;
    } else if((Wavelength >= 701) && (Wavelength < 781)) {
        factor = 0.3 + 0.7 * (780 - Wavelength) / (780 - 700);
    } else {
        factor = 0.0;
    }


    int[] rgb = new int[3];

    // Don't want 0^x = 1 for x <> 0
    rgb[0] = Red == 0.0 ? 0 : (int)Math.round(IntensityMax * Math.pow(Red * factor, Gamma));
    rgb[1] = Green == 0.0 ? 0 : (int)Math.round(IntensityMax * Math.pow(Green * factor, Gamma));
    rgb[2] = Blue == 0.0 ? 0 : (int)Math.round(IntensityMax * Math.pow(Blue * factor, Gamma));

    return rgb;
}

3
আপনার কোডটিতে একটি বাগ আছে বলে মনে হচ্ছে। তরঙ্গদৈর্ঘ্য উদাহরণস্বরূপ যদি 439.5 হয় তবে আপনার ফাংশনটি কালো রঙে ফিরে আসে। সাইটের মূল কোডটি পূর্ণসংখ্যা নিয়ে কাজ করছিল, আমি বিশ্বাস করি (আমি পাস্কালটি মোটেই জানি না)। আমি পরিবর্তন Wavelength<=439করতে পরামর্শ দিই Wavelength<440
হাসেদেব

2
তুমি ঠিক বলছো! এটি আমাকে দেখানোর জন্য আপনাকে ধন্যবাদ :) ইতিমধ্যে সংশোধন করা হয়েছে।
তারেক

এটি কি কিছু ফ্রিকোয়েন্সিতে বার বার আরএফবি প্রত্যাশা করে? (লাল): 652 - আরজিবি (255, 0, 0) | 660 - আরজিবি (255, 0, 0) | 692 - আরজিবি (255, 0, 0) | 700 - আরজিবি (255, 0, 0) | ...
রদ্রিগো বোরবা

14

সাধারণ ধারণা:

  1. ব্যবহারের CEI রঙ ম্যাচিং ফাংশন রূপান্তর তরঙ্গদৈর্ঘ্য থেকে XYZ রঙ
  2. এক্সওয়াইজেডকে আরজিবিতে রূপান্তর করুন
  3. স্বাক্ষরবিহীন বাইট পরিসরে ফিট করার জন্য উপাদানগুলিকে [0..1] এ ক্লিপ করুন এবং 255 দিয়ে গুণ করুন।

পদক্ষেপ 1 এবং 2 পৃথক হতে পারে।

টেবিল হিসাবে বা বিশ্লেষণী অনুমান হিসাবে (@ তারেক এবং @ হাওচেন জির পরামর্শ দেওয়া) হিসাবে উপলভ্য বেশ কয়েকটি রঙের মিল রয়েছে functions আপনার যদি মসৃণ পূর্ববর্তী ফলাফলের প্রয়োজন হয় তবে টেবিলগুলি সেরা।

কোনও একক আরজিবি রঙের স্থান নেই। একাধিক রূপান্তর ম্যাট্রিক্স এবং বিভিন্ন ধরণের গামা সংশোধন ব্যবহৃত হতে পারে।

নীচে আমি সম্প্রতি প্রকাশিত সি # কোডটি দিচ্ছি। এটি "CIE 1964 স্ট্যান্ডার্ড পর্যবেক্ষক" টেবিল এবং এসআরজিবি ম্যাট্রিক্স + গামা সংশোধনের উপরে লিনিয়ার ইন্টারপোলেশন ব্যবহার করে ।

static class RgbCalculator {

    const int
         LEN_MIN = 380,
         LEN_MAX = 780,
         LEN_STEP = 5;

    static readonly double[]
        X = {
                0.000160, 0.000662, 0.002362, 0.007242, 0.019110, 0.043400, 0.084736, 0.140638, 0.204492, 0.264737,
                0.314679, 0.357719, 0.383734, 0.386726, 0.370702, 0.342957, 0.302273, 0.254085, 0.195618, 0.132349,
                0.080507, 0.041072, 0.016172, 0.005132, 0.003816, 0.015444, 0.037465, 0.071358, 0.117749, 0.172953,
                0.236491, 0.304213, 0.376772, 0.451584, 0.529826, 0.616053, 0.705224, 0.793832, 0.878655, 0.951162,
                1.014160, 1.074300, 1.118520, 1.134300, 1.123990, 1.089100, 1.030480, 0.950740, 0.856297, 0.754930,
                0.647467, 0.535110, 0.431567, 0.343690, 0.268329, 0.204300, 0.152568, 0.112210, 0.081261, 0.057930,
                0.040851, 0.028623, 0.019941, 0.013842, 0.009577, 0.006605, 0.004553, 0.003145, 0.002175, 0.001506,
                0.001045, 0.000727, 0.000508, 0.000356, 0.000251, 0.000178, 0.000126, 0.000090, 0.000065, 0.000046,
                0.000033
            },

        Y = {
                0.000017, 0.000072, 0.000253, 0.000769, 0.002004, 0.004509, 0.008756, 0.014456, 0.021391, 0.029497,
                0.038676, 0.049602, 0.062077, 0.074704, 0.089456, 0.106256, 0.128201, 0.152761, 0.185190, 0.219940,
                0.253589, 0.297665, 0.339133, 0.395379, 0.460777, 0.531360, 0.606741, 0.685660, 0.761757, 0.823330,
                0.875211, 0.923810, 0.961988, 0.982200, 0.991761, 0.999110, 0.997340, 0.982380, 0.955552, 0.915175,
                0.868934, 0.825623, 0.777405, 0.720353, 0.658341, 0.593878, 0.527963, 0.461834, 0.398057, 0.339554,
                0.283493, 0.228254, 0.179828, 0.140211, 0.107633, 0.081187, 0.060281, 0.044096, 0.031800, 0.022602,
                0.015905, 0.011130, 0.007749, 0.005375, 0.003718, 0.002565, 0.001768, 0.001222, 0.000846, 0.000586,
                0.000407, 0.000284, 0.000199, 0.000140, 0.000098, 0.000070, 0.000050, 0.000036, 0.000025, 0.000018,
                0.000013
            },

        Z = {
                0.000705, 0.002928, 0.010482, 0.032344, 0.086011, 0.197120, 0.389366, 0.656760, 0.972542, 1.282500,
                1.553480, 1.798500, 1.967280, 2.027300, 1.994800, 1.900700, 1.745370, 1.554900, 1.317560, 1.030200,
                0.772125, 0.570060, 0.415254, 0.302356, 0.218502, 0.159249, 0.112044, 0.082248, 0.060709, 0.043050,
                0.030451, 0.020584, 0.013676, 0.007918, 0.003988, 0.001091, 0.000000, 0.000000, 0.000000, 0.000000,
                0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
                0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
                0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
                0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
                0.000000
            };

    static readonly double[]
        MATRIX_SRGB_D65 = {
             3.2404542, -1.5371385, -0.4985314,
            -0.9692660,  1.8760108,  0.0415560,
             0.0556434, -0.2040259,  1.0572252
        };

    public static byte[] Calc(double len) {
        if(len < LEN_MIN || len > LEN_MAX)
            return new byte[3];

        len -= LEN_MIN;
        var index = (int)Math.Floor(len / LEN_STEP);
        var offset = len - LEN_STEP * index;

        var x = Interpolate(X, index, offset);
        var y = Interpolate(Y, index, offset);
        var z = Interpolate(Z, index, offset);

        var m = MATRIX_SRGB_D65;

        var r = m[0] * x + m[1] * y + m[2] * z;
        var g = m[3] * x + m[4] * y + m[5] * z;
        var b = m[6] * x + m[7] * y + m[8] * z;

        r = Clip(GammaCorrect_sRGB(r));
        g = Clip(GammaCorrect_sRGB(g));
        b = Clip(GammaCorrect_sRGB(b));

        return new[] { 
            (byte)(255 * r),
            (byte)(255 * g),
            (byte)(255 * b)
        };
    }

    static double Interpolate(double[] values, int index, double offset) {
        if(offset == 0)
            return values[index];

        var x0 = index * LEN_STEP;
        var x1 = x0 + LEN_STEP;
        var y0 = values[index];
        var y1 = values[1 + index];

        return y0 + offset * (y1 - y0) / (x1 - x0);
    }

    static double GammaCorrect_sRGB(double c) {
        if(c <= 0.0031308)
            return 12.92 * c;

        var a = 0.055;
        return (1 + a) * Math.Pow(c, 1 / 2.4) - a;
    }

    static double Clip(double c) {
        if(c < 0)
            return 0;
        if(c > 1)
            return 1;
        return c;
    }
}

400-700 এনএম পরিসরের জন্য ফলাফল:

এখানে চিত্র বর্ণনা লিখুন


এটি আমার কাছে সত্যই আকর্ষণীয়। আমার কাছে একটি সাধারণ প্রতিক্রিয়া জানাতে এই জাতীয় কিছু ব্যবহার করার ধারণা রয়েছে তবে অন্য তিনটি ধরণের শঙ্কুগুলির মধ্যে যে কোনও চতুর্থ শঙ্কু রয়েছে যা একটি চতুর্থ শঙ্কু রয়েছে এমন টিট্রাক্রোমেটের প্রতিক্রিয়া অনুকরণ করার জন্য ডাব্লুএক্সএইজেড প্রতিক্রিয়া ব্যবহার করি। এটি আমাকে উত্সের চিত্রগুলি নিতে এবং তারা যে পার্থক্য দেখে তা অনুমান করতে পারে। এনবি তারা নতুন রঙ দেখতে পায় না, এটি সেই আলোগুলি মিশ্রিত হয় (সমষ্টি), উদাহরণস্বরূপ, একটি নির্দিষ্ট হলুদকে আমাদের বেশিরভাগের জন্য একটি নির্দিষ্ট ফ্রিকোয়েন্সিটির হলুদ হিসাবে সমান মনে হয়, তবে তাদের জন্য, আলো মিশ্রিত হবে না মোটেও হলুদ
ফোর্গান 1

অবশ্যই, একটি নির্দিষ্ট আরজিবি রঙের জন্য, এটি অনেক উপায়ে পৌঁছে দেওয়া যেত। একটি পাতার সবুজ সবুজ ছাড়াও ফিল্টারিং থেকে বেরিয়ে আসতে পারে বা সবুজকে ছাঁটাই করা যেতে পারে তবে ন্যানো বৈশিষ্ট্যগুলি নীল এবং হলুদকে সবুজ রঙের সাথে প্রতিবিম্বিত করতে এবং একইরকম দেখাতে পারে। আলোকের পরিবর্তে একটি চিত্র দেওয়া হয়েছে, আমি কি আলাদা করতে পারি?
ফোর্গান 1

10

যদিও এটি একটি পুরানো প্রশ্ন এবং ইতিমধ্যে মুষ্টিমেয় ভাল উত্তর পেয়েছে, যখন আমি আমার অ্যাপ্লিকেশনটিতে এই জাতীয় রূপান্তর কার্যকারিতা বাস্তবায়নের চেষ্টা করেছি তখনই আমি এখানে ইতিমধ্যে তালিকাভুক্ত আলগোরিদিমগুলি নিয়ে সন্তুষ্ট নই এবং আমার নিজের গবেষণাও করেছিল, যা আমাকে কিছু ভাল ফলাফল দিয়েছে। সুতরাং আমি একটি নতুন উত্তর পোস্ট করতে যাচ্ছি।

কিছু গবেষণার পরে আমি এই কাগজটি জুড়ে এসেছি, সিআইই এক্সওয়াইজেড কালার ম্যাচিং ফাংশনগুলির সরল বিশ্লেষণমূলক অনুমানগুলি এবং আমার অ্যাপ্লিকেশনটিতে প্রবর্তিত মাল্টি-লোব পিসওয়াস গাউসিয়ান ফিট অ্যালগরিদম গ্রহণ করার চেষ্টা করেছি। কাগজটি কেবলমাত্র একটি তরঙ্গদৈর্ঘ্যকে সম্পর্কিত XYZ মানগুলিতে রূপান্তরিত করার জন্য ফাংশনগুলি বর্ণনা করেছিল , তাই আমি এসআরজিবি রঙের জায়গায় XYZ কে আরজিবিতে রূপান্তর করতে একটি ফাংশন প্রয়োগ করেছি এবং সেগুলি সংযুক্ত করেছি। ফলাফল চমত্কার এবং ভাগ করে নেওয়ার মতো:

/**
 * Convert a wavelength in the visible light spectrum to a RGB color value that is suitable to be displayed on a
 * monitor
 *
 * @param wavelength wavelength in nm
 * @return RGB color encoded in int. each color is represented with 8 bits and has a layout of
 * 00000000RRRRRRRRGGGGGGGGBBBBBBBB where MSB is at the leftmost
 */
public static int wavelengthToRGB(double wavelength){
    double[] xyz = cie1931WavelengthToXYZFit(wavelength);
    double[] rgb = srgbXYZ2RGB(xyz);

    int c = 0;
    c |= (((int) (rgb[0] * 0xFF)) & 0xFF) << 16;
    c |= (((int) (rgb[1] * 0xFF)) & 0xFF) << 8;
    c |= (((int) (rgb[2] * 0xFF)) & 0xFF) << 0;

    return c;
}

/**
 * Convert XYZ to RGB in the sRGB color space
 * <p>
 * The conversion matrix and color component transfer function is taken from http://www.color.org/srgb.pdf, which
 * follows the International Electrotechnical Commission standard IEC 61966-2-1 "Multimedia systems and equipment -
 * Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB"
 *
 * @param xyz XYZ values in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
 * @return RGB values in a double array, in the order of R, G, B. each value in the range of [0.0, 1.0]
 */
public static double[] srgbXYZ2RGB(double[] xyz) {
    double x = xyz[0];
    double y = xyz[1];
    double z = xyz[2];

    double rl =  3.2406255 * x + -1.537208  * y + -0.4986286 * z;
    double gl = -0.9689307 * x +  1.8757561 * y +  0.0415175 * z;
    double bl =  0.0557101 * x + -0.2040211 * y +  1.0569959 * z;

    return new double[] {
            srgbXYZ2RGBPostprocess(rl),
            srgbXYZ2RGBPostprocess(gl),
            srgbXYZ2RGBPostprocess(bl)
    };
}

/**
 * helper function for {@link #srgbXYZ2RGB(double[])}
 */
private static double srgbXYZ2RGBPostprocess(double c) {
    // clip if c is out of range
    c = c > 1 ? 1 : (c < 0 ? 0 : c);

    // apply the color component transfer function
    c = c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1. / 2.4) - 0.055;

    return c;
}

/**
 * A multi-lobe, piecewise Gaussian fit of CIE 1931 XYZ Color Matching Functions by Wyman el al. from Nvidia. The
 * code here is adopted from the Listing 1 of the paper authored by Wyman et al.
 * <p>
 * Reference: Chris Wyman, Peter-Pike Sloan, and Peter Shirley, Simple Analytic Approximations to the CIE XYZ Color
 * Matching Functions, Journal of Computer Graphics Techniques (JCGT), vol. 2, no. 2, 1-11, 2013.
 *
 * @param wavelength wavelength in nm
 * @return XYZ in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
 */
public static double[] cie1931WavelengthToXYZFit(double wavelength) {
    double wave = wavelength;

    double x;
    {
        double t1 = (wave - 442.0) * ((wave < 442.0) ? 0.0624 : 0.0374);
        double t2 = (wave - 599.8) * ((wave < 599.8) ? 0.0264 : 0.0323);
        double t3 = (wave - 501.1) * ((wave < 501.1) ? 0.0490 : 0.0382);

        x =   0.362 * Math.exp(-0.5 * t1 * t1)
            + 1.056 * Math.exp(-0.5 * t2 * t2)
            - 0.065 * Math.exp(-0.5 * t3 * t3);
    }

    double y;
    {
        double t1 = (wave - 568.8) * ((wave < 568.8) ? 0.0213 : 0.0247);
        double t2 = (wave - 530.9) * ((wave < 530.9) ? 0.0613 : 0.0322);

        y =   0.821 * Math.exp(-0.5 * t1 * t1)
            + 0.286 * Math.exp(-0.5 * t2 * t2);
    }

    double z;
    {
        double t1 = (wave - 437.0) * ((wave < 437.0) ? 0.0845 : 0.0278);
        double t2 = (wave - 459.0) * ((wave < 459.0) ? 0.0385 : 0.0725);

        z =   1.217 * Math.exp(-0.5 * t1 * t1)
            + 0.681 * Math.exp(-0.5 * t2 * t2);
    }

    return new double[] { x, y, z };
}

আমার কোডটি জাভা 8 তে লেখা আছে, তবে এটি জাভা এবং অন্যান্য ভাষার কম সংস্করণে পোর্ট করা শক্ত হওয়া উচিত নয়।


1
@ ব্যাডাক, আপনি ঠিক বলেছেন: গণনা করা মানগুলিতে আরও কিছু পরিবর্তন আনার এটি একটি অভিনব উপায়। আমি ঠিক মনে করতে পারি না, তবে আমি মনে করি এটি প্রথমে গামা সংশোধন প্রয়োগ করে, তারপরে পরিসরের মানগুলি বাদ দেয়। হতে পারে আমার এটি আলাদা পদ্ধতিতে করা উচিত ছিল, তবে আমি কোডটি লেখার সময় ভাগ করে নেওয়ার কথা ভাবছিলাম না, এবং এটি একটি খেলনা প্রকল্প ছিল যেখানে আমার এই রূপান্তরটির প্রয়োজন হয়েছিল।
হাওচেন জি

1
@ ব্যাডাক আমি এই প্রকল্পটি আমার কাছে রূপান্তরিত করার দরকার হয়েছিল এবং জাভা 8 লম্বা না ব্যবহার করে এই অংশটি পুনরায় লিখেছিলাম যাতে কোডটি আরও স্পষ্ট। transferডাবল ইউনারিওপ্রেটার কী করছে সে সম্পর্কে আমি ভুল করে মনে পড়েছিলাম (সুতরাং আমার আগের মন্তব্যে ব্যাখ্যাটি সঠিক নয়), সুতরাং দয়া করে নতুন কোডটি পরীক্ষা করে দেখুন।
হাওচেন জে

1
@ ব্যাডাক আমি আনন্দিত যে কোডটি আপনাকে সহায়তা করে। এবং যদি আপনি কিছু আপত্তি না করেন, আপনি কি দয়া করে এটি উত্সাহিত করতে পারেন যাতে এটি সম্ভবত আরও বেশি লোককে সহায়তা করতে পারে?
হাওচেন জি

1
@ ব্যাডাক ম্যাথ.প্যাও (সি, ১ / ২.৪) = সি ^ (১ / ২.৪), অর্থাৎ সি / ১ / ২.৪ এর শক্তি বাড়ান; 1.মাত্র 1 তবে প্রকারটি এর doubleপরিবর্তে হবেint
হাওচেন Xie

3
@ রাস্লান যেহেতু এই অ্যালগরিদম সিআইই মানক পর্যবেক্ষকের বিশ্লেষণযোগ্য ফিট (যা "সুনির্দিষ্ট" মডেল হিসাবে বিবেচনা করা যেতে পারে), ত্রুটি রয়েছে। তবে কাগজটি থেকে, আপনি পৃষ্ঠা 7 এর চিত্র 1 দেখুন (তুলনা (d) সাথে (চ)), এই পদ্ধতিটি বেশ কাছাকাছি সান্নিধ্য সরবরাহ করে। বিশেষত আপনি যদি (চ) তাকান, আপনি দেখতে পেতেন যে স্ট্যান্ডার্ড মডেলটিতেও একটি নীল রেখা আছে। এছাড়াও, খাঁটি আলোর উত্সের বর্ণ উপলব্ধি ব্যক্তিগতভাবে পরিবর্তিত হয়, সুতরাং ত্রুটির এই স্তরটি সম্ভবত नगणনীয়।
হাওচেন জি

7

আপনি তরঙ্গ দৈর্ঘ্য থেকে আরজিবি মান রূপান্তর করার কথা বলছেন ।

এখানে দেখুন, সম্ভবত আপনার প্রশ্নের উত্তর দিতে হবে। সোর্স কোড এবং কিছু ব্যাখ্যা সহ এটি করার জন্য আপনার একটি উপযোগ রয়েছে।

WaveLengthToRGB


1
কেবল একই পৃষ্ঠাটি পড়ে "তরঙ্গদৈর্ঘ্য এবং আরজিবি মানগুলির মধ্যে একের পর এক ম্যাপিং নেই" - তাই আপনি একটি সারণী এবং তাত্পর্যপূর্ণতার সাথে আটকে আছেন with প্রথম কাটা হিসাবে আমি এইচএসভিতে আরজিবি রূপান্তরগুলিতে নজর দেব কারণ "হিউ" নীল থেকে লাল পর্যন্ত। আরজিবি ডোমেনে রেড + নীল = ভায়োলেট এবং ভায়োলেটের সংক্ষিপ্ততম দৃশ্যমান তরঙ্গদৈর্ঘ্য হওয়ায় সম্ভবত কিছুটা বদল With
হোটনিক

3
এটি কি বাস্তবে এক নয়? ফ্রেইক = সি / তরঙ্গদৈর্ঘ্য
মরিসিও শিফার

1
@ মৌরিসিও শেফার হ্যাঁ এটি প্রায় একই রকম।
জোসেফ গর্ডন

এই ব্রুটনের অ্যালগরিদম বাস্তবের চেয়ে বরং নান্দনিক
মাইখাল

8
@ জোসেফ গর্ডন - দৃr়ভাবে একমত নন। বাতাসে নির্গত সবুজ বর্ণের 400nm রশ্মি বিবেচনা করুন জলের পৃষ্ঠকে আঘাত করে এবং তারপরে জলে ছড়িয়ে পড়ে। জলের রিফ্রাকশন সহগ বলুন, ১.৩৩, সুতরাং পানিতে একটি রশ্মি তরঙ্গদৈর্ঘ্য এখন 300nm, যা স্পষ্টতই এর রঙ পরিবর্তন করে না। যে বিষয়গুলি রশ্মিকে "বর্ণায়িত করে" তা ফ্রিকোয়েন্সি, তরঙ্গদৈর্ঘ্যের নয়। একই তরঙ্গদৈর্ঘ্যে একই পদার্থে (ভ্যাকুয়াম, বায়ু, জল) ফ্রিকোয়েন্সি (রঙ) মানচিত্র। বিভিন্ন মিডিয়া - না।
mbaitoff

3

আমার ধারণা আমি আনুষ্ঠানিক উত্তর দিয়ে আমার মন্তব্যটি অনুসরণ করতে পারি। সেরা বিকল্পটি এইচএসভি রঙের স্থানটি ব্যবহার করা - যদিও হিউ তরঙ্গদৈর্ঘ্যের প্রতিনিধিত্ব করে এটি একের সাথে এক তুলনা নয়।


1
আপনার লিঙ্কটি মারা গেছে।
Ruslan

3

আমি পরিচিত বর্ণের মান এবং ফ্রিকোয়েন্সিগুলির একটি লিনিয়ার ফিট করেছিলাম (লাল এবং ভায়োলেট বাদ দেয় কারণ তারা ফ্রিকোয়েন্সি মানগুলিতে এতদূর পর্যন্ত প্রসারিত করে যে তারা কিছুটা ছড়িয়ে দেয়) এবং আমি একটি মোটামুটি রূপান্তর সমীকরণ পেয়েছি।

এটা যায়
ফ্রিকোয়েন্সি (THZ তে) = 474 + (3/4) (হিউ অ্যাঙ্গেল (ডিগ্রীতে)) এর মতো যায়

আমি আশেপাশে দেখার চেষ্টা করেছি এবং দেখছি কেউ এই সমীকরণ নিয়ে এসেছে কিনা, তবে আমি ২০১০ সালের মে পর্যন্ত কিছুই পাইনি।


2

পদ্ধতি 1

এটি কিছুটা পরিষ্কার হয়েছে এবং @ হওচেন-এক্স এর সি ++ 11 সংস্করণটি পরীক্ষা করা হয়েছে। আমি এমন একটি ফাংশনও যুক্ত করেছি যা 0 থেকে 1 এর মানকে দৃশ্যমান বর্ণালীতে একটি তরঙ্গদৈর্ঘ্যে রূপান্তর করে যা এই পদ্ধতির সাথে ব্যবহারযোগ্য। আপনি কেবলমাত্র একটি হেডার ফাইলের নীচে রাখতে পারেন এবং কোনও নির্ভরতা ছাড়াই এটি ব্যবহার করতে পারেন। এই সংস্করণটি এখানে বজায় রাখা হবে ।

#ifndef common_utils_OnlineStats_hpp
#define common_utils_OnlineStats_hpp

namespace common_utils {

class ColorUtils {
public:

    static void valToRGB(double val0To1, unsigned char& r, unsigned char& g, unsigned char& b)
    {
        //actual visible spectrum is 375 to 725 but outside of 400-700 things become too dark
        wavelengthToRGB(val0To1 * (700 - 400) + 400, r, g, b);
    }

    /**
    * Convert a wavelength in the visible light spectrum to a RGB color value that is suitable to be displayed on a
    * monitor
    *
    * @param wavelength wavelength in nm
    * @return RGB color encoded in int. each color is represented with 8 bits and has a layout of
    * 00000000RRRRRRRRGGGGGGGGBBBBBBBB where MSB is at the leftmost
    */
    static void wavelengthToRGB(double wavelength, unsigned char& r, unsigned char& g, unsigned char& b) {
        double x, y, z;
        cie1931WavelengthToXYZFit(wavelength, x, y, z);
        double dr, dg, db;
        srgbXYZ2RGB(x, y, z, dr, dg, db);

        r = static_cast<unsigned char>(static_cast<int>(dr * 0xFF) & 0xFF);
        g = static_cast<unsigned char>(static_cast<int>(dg * 0xFF) & 0xFF);
        b = static_cast<unsigned char>(static_cast<int>(db * 0xFF) & 0xFF);
    }

    /**
    * Convert XYZ to RGB in the sRGB color space
    * <p>
    * The conversion matrix and color component transfer function is taken from http://www.color.org/srgb.pdf, which
    * follows the International Electrotechnical Commission standard IEC 61966-2-1 "Multimedia systems and equipment -
    * Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB"
    *
    * @param xyz XYZ values in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
    * @return RGB values in a double array, in the order of R, G, B. each value in the range of [0.0, 1.0]
    */
    static void srgbXYZ2RGB(double x, double y, double z, double& r, double& g, double& b) {
        double rl = 3.2406255 * x + -1.537208  * y + -0.4986286 * z;
        double gl = -0.9689307 * x + 1.8757561 * y + 0.0415175 * z;
        double bl = 0.0557101 * x + -0.2040211 * y + 1.0569959 * z;

        r = srgbXYZ2RGBPostprocess(rl);
        g = srgbXYZ2RGBPostprocess(gl);
        b = srgbXYZ2RGBPostprocess(bl);
    }

    /**
    * helper function for {@link #srgbXYZ2RGB(double[])}
    */
    static double srgbXYZ2RGBPostprocess(double c) {
        // clip if c is out of range
        c = c > 1 ? 1 : (c < 0 ? 0 : c);

        // apply the color component transfer function
        c = c <= 0.0031308 ? c * 12.92 : 1.055 * std::pow(c, 1. / 2.4) - 0.055;

        return c;
    }

    /**
    * A multi-lobe, piecewise Gaussian fit of CIE 1931 XYZ Color Matching Functions by Wyman el al. from Nvidia. The
    * code here is adopted from the Listing 1 of the paper authored by Wyman et al.
    * <p>
    * Reference: Chris Wyman, Peter-Pike Sloan, and Peter Shirley, Simple Analytic Approximations to the CIE XYZ Color
    * Matching Functions, Journal of Computer Graphics Techniques (JCGT), vol. 2, no. 2, 1-11, 2013.
    *
    * @param wavelength wavelength in nm
    * @return XYZ in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
    */
    static void cie1931WavelengthToXYZFit(double wavelength, double& x, double& y, double& z) {
        double wave = wavelength;

        {
            double t1 = (wave - 442.0) * ((wave < 442.0) ? 0.0624 : 0.0374);
            double t2 = (wave - 599.8) * ((wave < 599.8) ? 0.0264 : 0.0323);
            double t3 = (wave - 501.1) * ((wave < 501.1) ? 0.0490 : 0.0382);

            x = 0.362 * std::exp(-0.5 * t1 * t1)
                + 1.056 * std::exp(-0.5 * t2 * t2)
                - 0.065 * std::exp(-0.5 * t3 * t3);
        }

        {
            double t1 = (wave - 568.8) * ((wave < 568.8) ? 0.0213 : 0.0247);
            double t2 = (wave - 530.9) * ((wave < 530.9) ? 0.0613 : 0.0322);

            y = 0.821 * std::exp(-0.5 * t1 * t1)
                + 0.286 * std::exp(-0.5 * t2 * t2);
        }

        {
            double t1 = (wave - 437.0) * ((wave < 437.0) ? 0.0845 : 0.0278);
            double t2 = (wave - 459.0) * ((wave < 459.0) ? 0.0385 : 0.0725);

            z = 1.217 * std::exp(-0.5 * t1 * t1)
                + 0.681 * std::exp(-0.5 * t2 * t2);
        }
    }

};

} //namespace

#endif

375nm থেকে 725nm পর্যন্ত রঙের প্লটটি নীচের মত দেখাচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

এই পদ্ধতির একটি সমস্যা হ'ল এটি কেবল 400-700nm এর মধ্যে কাজ করে এবং এর বাইরে এটি খুব দ্রুত কালোতে নেমে আসে। আর একটি ইস্যু হ'ল সংকীর্ণ নীল।

তুলনার জন্য, ম্যাক্সম্যাক্স ডটকম এ ভিশন এফকিউ থেকে রঙগুলি নীচে:

এখানে চিত্র বর্ণনা লিখুন

আমি এটিকে গভীরতার মানচিত্রের ভিজ্যুয়ালাইজ করতে ব্যবহার করেছি যেখানে প্রতিটি পিক্সেল মিটারে গভীরতার মান উপস্থাপন করে এবং এটি নীচের মত দেখাচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

পদ্ধতি 2

এটি বিটম্যাপ_আইমেজ একক ফাইল হেডার-কেবল লাইব্রেরির অংশ হিসাবে আয়েশ পার্টোর দ্বারা প্রয়োগ করা হয়েছে:

inline rgb_t convert_wave_length_nm_to_rgb(const double wave_length_nm)
{
   // Credits: Dan Bruton http://www.physics.sfasu.edu/astro/color.html
   double red   = 0.0;
   double green = 0.0;
   double blue  = 0.0;

   if ((380.0 <= wave_length_nm) && (wave_length_nm <= 439.0))
   {
      red   = -(wave_length_nm - 440.0) / (440.0 - 380.0);
      green = 0.0;
      blue  = 1.0;
   }
   else if ((440.0 <= wave_length_nm) && (wave_length_nm <= 489.0))
   {
      red   = 0.0;
      green = (wave_length_nm - 440.0) / (490.0 - 440.0);
      blue  = 1.0;
   }
   else if ((490.0 <= wave_length_nm) && (wave_length_nm <= 509.0))
   {
      red   = 0.0;
      green = 1.0;
      blue  = -(wave_length_nm - 510.0) / (510.0 - 490.0);
   }
   else if ((510.0 <= wave_length_nm) && (wave_length_nm <= 579.0))
   {
      red   = (wave_length_nm - 510.0) / (580.0 - 510.0);
      green = 1.0;
      blue  = 0.0;
   }
   else if ((580.0 <= wave_length_nm) && (wave_length_nm <= 644.0))
   {
      red   = 1.0;
      green = -(wave_length_nm - 645.0) / (645.0 - 580.0);
      blue  = 0.0;
   }
   else if ((645.0 <= wave_length_nm) && (wave_length_nm <= 780.0))
   {
      red   = 1.0;
      green = 0.0;
      blue  = 0.0;
   }

   double factor = 0.0;

   if ((380.0 <= wave_length_nm) && (wave_length_nm <= 419.0))
      factor = 0.3 + 0.7 * (wave_length_nm - 380.0) / (420.0 - 380.0);
   else if ((420.0 <= wave_length_nm) && (wave_length_nm <= 700.0))
      factor = 1.0;
   else if ((701.0 <= wave_length_nm) && (wave_length_nm <= 780.0))
      factor = 0.3 + 0.7 * (780.0 - wave_length_nm) / (780.0 - 700.0);
   else
      factor = 0.0;

   rgb_t result;

   const double gamma         =   0.8;
   const double intensity_max = 255.0;

   #define round(d) std::floor(d + 0.5)

   result.red   = static_cast<unsigned char>((red   == 0.0) ? red   : round(intensity_max * std::pow(red   * factor, gamma)));
   result.green = static_cast<unsigned char>((green == 0.0) ? green : round(intensity_max * std::pow(green * factor, gamma)));
   result.blue  = static_cast<unsigned char>((blue  == 0.0) ? blue  : round(intensity_max * std::pow(blue  * factor, gamma)));

   #undef round

   return result;
}

375-725nm থেকে তরঙ্গ দৈর্ঘ্যের প্লট নীচের মত দেখাচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

সুতরাং এটি 400-725nm এ আরও ব্যবহারযোগ্য। আমি যখন পদ্ধতি 1 এর মতো একই গভীরতার মানচিত্রটি ভিজ্যুয়ালাইজ করি তখন আমি নীচে নামি। এই কালো রেখাগুলির একটি সুস্পষ্ট সমস্যা রয়েছে যা আমি মনে করি এই কোডটিতে ছোট্ট বাগটি নির্দেশ করে যা আমি আরও গভীরভাবে দেখিনি। এছাড়াও ভায়োলেটগুলি এই পদ্ধতিতে কিছুটা সংকীর্ণ যা দূরের বস্তুর জন্য কম বিপরীতে সৃষ্টি করে।

এখানে চিত্র বর্ণনা লিখুন


0

এসআরজিবি গাম্টের উপর তরঙ্গদৈর্ঘ্যের সিআইএক্সি ডি 65 হোয়াইটের দিকে প্রজেক্ট করুন

#!/usr/bin/ghci
ångstrømsfromTHz terahertz = 2997924.58 / terahertz
tristimulusXYZfromÅngstrøms å=map(sum.map(stimulus))[
 [[1056,5998,379,310],[362,4420,160,267],[-65,5011,204,262]],
 [[821,5688,469,405],[286,5309,163,311]],
 [[1217,4370,118,360],[681,4590,260,138]]]
 where stimulus[ω,μ,ς,σ]=ω/1000*exp(-((å-μ)/if å<μ then ς else σ)^2/2)

standardRGBfromTristimulusXYZ xyz=
 map(gamma.sum.zipWith(*)(gamutConfine xyz))[
 [3.2406,-1.5372,-0.4986],[-0.9689,1.8758,0.0415],[0.0557,-0.2040,1.057]]
gamma u=if u<=0.0031308 then 12.92*u else (u**(5/12)*211-11)/200
[red,green,blue,black]=
 [[0.64,0.33],[0.3,0.6],[0.15,0.06],[0.3127,0.3290,0]]
ciexyYfromXYZ xyz=if xyz!!1==0 then black else map(/sum xyz)xyz
cieXYZfromxyY[x,y,l]=if y==0 then black else[x*l/y,l,(1-x-y)*l/y]
gamutConfine xyz=last$xyz:[cieXYZfromxyY[x0+t*(x1-x0),y0+t*(y1-y0),xyz!!1]|
 x0:y0:_<-[black],x1:y1:_<-[ciexyYfromXYZ xyz],i<-[0..2],
 [x2,y2]:[x3,y3]:_<-[drop i[red,green,blue,red]],
 det<-[(x0-x1)*(y2-y3)-(y0-y1)*(x2-x3)],
 t <-[((x0-x2)*(y2-y3)-(y0-y2)*(x2-x3))/det|det/=0],0<=t,t<=1]

sRGBfromÅ=standardRGBfromTristimulusXYZ.tristimulusXYZfromÅngstrøms
x s rgb=concat["\ESC[48;2;",
               intercalate";"$map(show.(17*).round.(15*).max 0.min 1)rgb,
               "m",s,"\ESC[49m"]
spectrum=concatMap(x" ".sRGBfromÅ)$takeWhile(<7000)$iterate(+60)4000
main=putStrLn spectrum
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.