উভয়ের জন্য 0-255 পরিসরে আরজিবিকে এইচএসভি এবং এইচএসভিকে আরজিবিতে রূপান্তর করতে অ্যালগরিদম


90

আমি আরজিবি থেকে এইচএসভিতে রঙ স্পেস কনভার্টারের সন্ধান করছি, বিশেষত উভয় রঙের স্পেসের জন্য 0 থেকে 255 ব্যাপ্তির জন্য।

উত্তর:


136

আমি এগুলি দীর্ঘদিন ব্যবহার করেছি - এ মুহুর্তে তারা কোথা থেকে এসেছিল সে সম্পর্কে কোনও ধারণা নেই ... দ্রষ্টব্য যে ডিগ্রিগুলির কোণ বাদে ইনপুট এবং আউটপুটগুলি 0 থেকে 1.0 এর মধ্যে রয়েছে।

দ্রষ্টব্য: এই কোডটি ইনপুটগুলিতে সত্যিকারের বিচক্ষণতা যাচাই করে না। সাবধানতার সাথে এগিয়ে যান!

typedef struct {
    double r;       // a fraction between 0 and 1
    double g;       // a fraction between 0 and 1
    double b;       // a fraction between 0 and 1
} rgb;

typedef struct {
    double h;       // angle in degrees
    double s;       // a fraction between 0 and 1
    double v;       // a fraction between 0 and 1
} hsv;

static hsv   rgb2hsv(rgb in);
static rgb   hsv2rgb(hsv in);

hsv rgb2hsv(rgb in)
{
    hsv         out;
    double      min, max, delta;

    min = in.r < in.g ? in.r : in.g;
    min = min  < in.b ? min  : in.b;

    max = in.r > in.g ? in.r : in.g;
    max = max  > in.b ? max  : in.b;

    out.v = max;                                // v
    delta = max - min;
    if (delta < 0.00001)
    {
        out.s = 0;
        out.h = 0; // undefined, maybe nan?
        return out;
    }
    if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash
        out.s = (delta / max);                  // s
    } else {
        // if max is 0, then r = g = b = 0              
        // s = 0, h is undefined
        out.s = 0.0;
        out.h = NAN;                            // its now undefined
        return out;
    }
    if( in.r >= max )                           // > is bogus, just keeps compilor happy
        out.h = ( in.g - in.b ) / delta;        // between yellow & magenta
    else
    if( in.g >= max )
        out.h = 2.0 + ( in.b - in.r ) / delta;  // between cyan & yellow
    else
        out.h = 4.0 + ( in.r - in.g ) / delta;  // between magenta & cyan

    out.h *= 60.0;                              // degrees

    if( out.h < 0.0 )
        out.h += 360.0;

    return out;
}


rgb hsv2rgb(hsv in)
{
    double      hh, p, q, t, ff;
    long        i;
    rgb         out;

    if(in.s <= 0.0) {       // < is bogus, just shuts up warnings
        out.r = in.v;
        out.g = in.v;
        out.b = in.v;
        return out;
    }
    hh = in.h;
    if(hh >= 360.0) hh = 0.0;
    hh /= 60.0;
    i = (long)hh;
    ff = hh - i;
    p = in.v * (1.0 - in.s);
    q = in.v * (1.0 - (in.s * ff));
    t = in.v * (1.0 - (in.s * (1.0 - ff)));

    switch(i) {
    case 0:
        out.r = in.v;
        out.g = t;
        out.b = p;
        break;
    case 1:
        out.r = q;
        out.g = in.v;
        out.b = p;
        break;
    case 2:
        out.r = p;
        out.g = in.v;
        out.b = t;
        break;

    case 3:
        out.r = p;
        out.g = q;
        out.b = in.v;
        break;
    case 4:
        out.r = t;
        out.g = p;
        out.b = in.v;
        break;
    case 5:
    default:
        out.r = in.v;
        out.g = p;
        out.b = q;
        break;
    }
    return out;     
}

13
@ স্টারগাজার 12১২ আপনি যদি গণিতটি করেন তবে এটি == হওয়া উচিত তবে আপনি যদি এটি ব্যবহার করেন তবে আপনার কাছে ফ্লোটগুলির তুলনা করার অভিযোগ পাওয়া যেতে পারে। তাত্ত্বিকভাবে এটি হওয়া অসম্ভব, যদিও, "==" এর পরিবর্তে "> =" ব্যবহার করে আমি ম্যাকের উপর এলএলভিএম / এক্সকোড ব্যবহার করে যে সংকলক ত্রুটিটি বন্ধ করে দিয়েছি,
ডেভিড এইচ

4
@ জেরার্ড আউট ডিগ্রীতে আছে। 60 একটি সম্পূর্ণ বৃত্তের 1 / ষ্ঠ। এটি রেডিয়ান নয়।
ডেভিড এইচ

4
কারণ >=কারণ এবং কম্পাইলার ত্রুটি double == doubleঅবৈধ এবং সবচেয়ে কম্পাইলার হল বেআইনি। ফ্লোটিং পয়েন্ট গাণিতিক এবং ভাসমান পয়েন্ট স্টোরেজ মানে দুটি মান আনুমানিক মানের সমান হতে পারে তবে সূত্রগতভাবে একই হলেও সঞ্চিত মানে সমান নয়। abs(double_a - double_b) <= epsilonঅ্যাপসিলন যেখানে সাধারণত কিছু মূল্য থাকে তা আপনি করার কথা 1e-4
ব্র্যান্ডন লেব্ল্যাঙ্ক

4
Rgb2hsv- এর জন্য, যেখানে in.r> = সর্বাধিক, কোডটি মোড অপারেটর ব্যবহার করছে না কেন? আউটড.কে "আউট হুক = ((যেমন - ইন.বি) / ডেল্টা)% 6 হিসাবে গণনা করা উচিত নয়;" ?
ক্রেগ্র্ফ

4
@ জোচিমব্র্যান্ডনলিব্ল্যাঙ্ক: "ডাবল == ডাবল বেশিরভাগ সংকলকগুলিতে অবৈধ এবং অবৈধ" এটি সত্য নয়। সমতার জন্য দুটি ভাসমান-পয়েন্ট মানের তুলনা সম্পূর্ণরূপে সংজ্ঞায়িত এবং করণীয় একটি আইনী বিষয় । কোনও মূলধারার এবং / অথবা অনুগত কম্পাইলার আপনাকে এটি করতে বাধা দেয় না will সমস্যাটি হ'ল আপনি যে উত্তরটি চেয়েছিলেন তা আপনি সম্ভবত পেতে না পেয়ে এবং সম্ভবত একটি আলগা তুলনা সম্পাদনের উদ্দেশ্যে তৈরি করেছেন।
অরবিট

39

আপনি এই কোডটি ভাসা ছাড়াইও চেষ্টা করতে পারেন (দ্রুত তবে কম নির্ভুল):

typedef struct RgbColor
{
    unsigned char r;
    unsigned char g;
    unsigned char b;
} RgbColor;

typedef struct HsvColor
{
    unsigned char h;
    unsigned char s;
    unsigned char v;
} HsvColor;

RgbColor HsvToRgb(HsvColor hsv)
{
    RgbColor rgb;
    unsigned char region, remainder, p, q, t;

    if (hsv.s == 0)
    {
        rgb.r = hsv.v;
        rgb.g = hsv.v;
        rgb.b = hsv.v;
        return rgb;
    }

    region = hsv.h / 43;
    remainder = (hsv.h - (region * 43)) * 6; 

    p = (hsv.v * (255 - hsv.s)) >> 8;
    q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
    t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;

    switch (region)
    {
        case 0:
            rgb.r = hsv.v; rgb.g = t; rgb.b = p;
            break;
        case 1:
            rgb.r = q; rgb.g = hsv.v; rgb.b = p;
            break;
        case 2:
            rgb.r = p; rgb.g = hsv.v; rgb.b = t;
            break;
        case 3:
            rgb.r = p; rgb.g = q; rgb.b = hsv.v;
            break;
        case 4:
            rgb.r = t; rgb.g = p; rgb.b = hsv.v;
            break;
        default:
            rgb.r = hsv.v; rgb.g = p; rgb.b = q;
            break;
    }

    return rgb;
}

HsvColor RgbToHsv(RgbColor rgb)
{
    HsvColor hsv;
    unsigned char rgbMin, rgbMax;

    rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
    rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);

    hsv.v = rgbMax;
    if (hsv.v == 0)
    {
        hsv.h = 0;
        hsv.s = 0;
        return hsv;
    }

    hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v;
    if (hsv.s == 0)
    {
        hsv.h = 0;
        return hsv;
    }

    if (rgbMax == rgb.r)
        hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
    else if (rgbMax == rgb.g)
        hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
    else
        hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);

    return hsv;
}

মনে রাখবেন যে এই অ্যালগরিদমটি এই 0-255সীমা হিসাবে ( 0-360যেমন নয় ) হিসাবে ব্যবহার করে যা এই প্রশ্নের লেখককে অনুরোধ করেছিল।


7
আপনি সমস্ত 16,777,216 টি সম্ভাব্য আরজিবি রঙগুলিকে এইচএসভিতে রূপান্তর করতে পারেন এবং আবার আরজিবিতে ফিরে যেতে পারেন। দুর্ভাগ্যক্রমে, এই অ্যালগরিদমটি ব্যবহার করে আপনি দেখতে পাবেন যে কিছু রঙগুলি রাউন্ডট্রিপ ভাল করবে না। সম্ভবত তারা বোধগম্যভাবে একইটির দিকে নজর রাখবেন তবে সংখ্যার দিক থেকে যথেষ্ট পার্থক্য রয়েছে, যেমন (0, 237, 11) (0, 237, 0) ইত্যাদিকে রাউন্ডট্রিপ করবে। ভাসমান পয়েন্ট গণনার উপর ভিত্তি করে ডেভিড এইচ এর অ্যালগরিদম ব্যবহার করার সময় এটি হয় না This ।
মার্টিন লিভারেজ

4
@ rightaway717 - এটি আমাকে সম্পূর্ণ পরিসীমা দেয়, সম্ভবত আপনি পরিসীমা হিসাবে 0-360 ব্যবহার করছেন? এই অ্যালগরিদম (কৃতজ্ঞতার সাথে) এর পরিসীমা হিসাবে 0x00 - 0xFF ব্যবহার করে
আন কুইন

পছন্দ করুন আমি এটি 0-360 হবে বলে আশাবাদী, তবে আমি কী ভুল তা খুঁজে বের করার যথেষ্ট আবেগ অনুভব করিনি, যখন দেখলাম গ্রহণযোগ্য উত্তরটি কেবল কাজ করে। আমি মনে করি যে লেসেকের উত্তরে হিউ রেঞ্জের কথা বলা উচিত ছিল, যদিও যাইহোক পোস্ট দেওয়ার জন্য তাকে ধন্যবাদ জানাই।
rightaway717

24

আমি আমাদের রেন্ডারিং ইঞ্জিনের জন্য এইচএলএসএলে এটি লিখেছিলাম, এটির কোনও শর্ত নেই:

    float3  HSV2RGB( float3 _HSV )
    {
        _HSV.x = fmod( 100.0 + _HSV.x, 1.0 );                                       // Ensure [0,1[

        float   HueSlice = 6.0 * _HSV.x;                                            // In [0,6[
        float   HueSliceInteger = floor( HueSlice );
        float   HueSliceInterpolant = HueSlice - HueSliceInteger;                   // In [0,1[ for each hue slice

        float3  TempRGB = float3(   _HSV.z * (1.0 - _HSV.y),
                                    _HSV.z * (1.0 - _HSV.y * HueSliceInterpolant),
                                    _HSV.z * (1.0 - _HSV.y * (1.0 - HueSliceInterpolant)) );

        // The idea here to avoid conditions is to notice that the conversion code can be rewritten:
        //    if      ( var_i == 0 ) { R = V         ; G = TempRGB.z ; B = TempRGB.x }
        //    else if ( var_i == 2 ) { R = TempRGB.x ; G = V         ; B = TempRGB.z }
        //    else if ( var_i == 4 ) { R = TempRGB.z ; G = TempRGB.x ; B = V     }
        // 
        //    else if ( var_i == 1 ) { R = TempRGB.y ; G = V         ; B = TempRGB.x }
        //    else if ( var_i == 3 ) { R = TempRGB.x ; G = TempRGB.y ; B = V     }
        //    else if ( var_i == 5 ) { R = V         ; G = TempRGB.x ; B = TempRGB.y }
        //
        // This shows several things:
        //  . A separation between even and odd slices
        //  . If slices (0,2,4) and (1,3,5) can be rewritten as basically being slices (0,1,2) then
        //      the operation simply amounts to performing a "rotate right" on the RGB components
        //  . The base value to rotate is either (V, B, R) for even slices or (G, V, R) for odd slices
        //
        float   IsOddSlice = fmod( HueSliceInteger, 2.0 );                          // 0 if even (slices 0, 2, 4), 1 if odd (slices 1, 3, 5)
        float   ThreeSliceSelector = 0.5 * (HueSliceInteger - IsOddSlice);          // (0, 1, 2) corresponding to slices (0, 2, 4) and (1, 3, 5)

        float3  ScrollingRGBForEvenSlices = float3( _HSV.z, TempRGB.zx );           // (V, Temp Blue, Temp Red) for even slices (0, 2, 4)
        float3  ScrollingRGBForOddSlices = float3( TempRGB.y, _HSV.z, TempRGB.x );  // (Temp Green, V, Temp Red) for odd slices (1, 3, 5)
        float3  ScrollingRGB = lerp( ScrollingRGBForEvenSlices, ScrollingRGBForOddSlices, IsOddSlice );

        float   IsNotFirstSlice = saturate( ThreeSliceSelector );                   // 1 if NOT the first slice (true for slices 1 and 2)
        float   IsNotSecondSlice = saturate( ThreeSliceSelector-1.0 );              // 1 if NOT the first or second slice (true only for slice 2)

        return  lerp( ScrollingRGB.xyz, lerp( ScrollingRGB.zxy, ScrollingRGB.yzx, IsNotSecondSlice ), IsNotFirstSlice );    // Make the RGB rotate right depending on final slice index
    }

4
আপনার কি অন্য উপায়ে রূপান্তর (RGB2HSV) আছে? একই পদ্ধতির ব্যবহার?
কার্লোস বার্সেলোস

8

অ্যাগোস্টনের কম্পিউটার গ্রাফিক্স এবং জ্যামিতিক মডেলিংয়ের ভিত্তিতে একটি সি প্রয়োগকরণ এখানে রয়েছে : বাস্তবায়ন এবং অ্যালগরিদম পি। 304, এইচ ∈ [0, 360] এবং এস , ভি ∈ [0, 1] সহ।

#include <math.h>

typedef struct {
    double r;       // ∈ [0, 1]
    double g;       // ∈ [0, 1]
    double b;       // ∈ [0, 1]
} rgb;

typedef struct {
    double h;       // ∈ [0, 360]
    double s;       // ∈ [0, 1]
    double v;       // ∈ [0, 1]
} hsv;

rgb hsv2rgb(hsv HSV)
{
    rgb RGB;
    double H = HSV.h, S = HSV.s, V = HSV.v,
            P, Q, T,
            fract;

    (H == 360.)?(H = 0.):(H /= 60.);
    fract = H - floor(H);

    P = V*(1. - S);
    Q = V*(1. - S*fract);
    T = V*(1. - S*(1. - fract));

    if      (0. <= H && H < 1.)
        RGB = (rgb){.r = V, .g = T, .b = P};
    else if (1. <= H && H < 2.)
        RGB = (rgb){.r = Q, .g = V, .b = P};
    else if (2. <= H && H < 3.)
        RGB = (rgb){.r = P, .g = V, .b = T};
    else if (3. <= H && H < 4.)
        RGB = (rgb){.r = P, .g = Q, .b = V};
    else if (4. <= H && H < 5.)
        RGB = (rgb){.r = T, .g = P, .b = V};
    else if (5. <= H && H < 6.)
        RGB = (rgb){.r = V, .g = P, .b = Q};
    else
        RGB = (rgb){.r = 0., .g = 0., .b = 0.};

    return RGB;
}

এইচএসভি থেকে আরজিবিতে রূপান্তর করার জন্য কি একই জাতীয় কোড কোড রয়েছে? ধন্যবাদ!
ব্যবহারকারী3236841

@ ব্যবহারকারী3236841 এর জন্য সিউডো কোডটি অ্যাগ্রস্টনের কম্পিউটার গ্রাফিক্স এবং জ্যামিতিক মডেলিংয়ের পূর্ববর্তী পৃষ্ঠায় (পৃষ্ঠা 303) রয়েছে : বাস্তবায়ন এবং অ্যালগরিদম
জেরেমিয়া

দয়া করে পরীক্ষা করুন - এটি এইচএসএল 2 আরজিবি, এইচএসভি নয়।
ক্রোমস্টার

7

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

এইচএসএল কোড

        float3 Hue(float H)
        {
            half R = abs(H * 6 - 3) - 1;
            half G = 2 - abs(H * 6 - 2);
            half B = 2 - abs(H * 6 - 4);
            return saturate(half3(R,G,B));
        }

        half4 HSVtoRGB(in half3 HSV)
        {
            return half4(((Hue(HSV.x) - 1) * HSV.y + 1) * HSV.z,1);
        }

ফ্লোট 3 হল 16 বিট নির্ভুলতা ভেক্টর 3 ডেটা টাইপ, অর্থাৎ ফ্লোট 3 হিউ () একটি ডেটা টাইপ (x, y, z) যেমন (আর, জি, বি) প্রদান করে, অর্ধেক যথার্থ, 8 বিট, একটি ফ্ল্যাট 4 হয় (আর, g, b, a) 4 টি মান।


4
জন্য কিছু টাইপ সংজ্ঞা প্রয়োজন half, half4, half3, float3, ইত্যাদি ইত্যাদি।
Quuxplusone

4
অর্ধ 4 রঙ রঙ (আর, জি, বি, এ) বা যে কোনও 4x অর্ধ নির্ভুলতা ভাসা, সম্পূর্ণ নির্ভুলতাও হতে পারে, এটি কেবল একটি ভেক্টর 4
অ্যালিয়েনশিয়াল

স্যাচুরেট () কি?
টাটিওভারফ্লো 16

স্যাচুরেট () এইচএলএসএল কোড রেফারেন্সে উপলভ্য: স্যাচুরেট (এক্স) 0 এবং 1 ডকস.মাইক্রোসফট.ইন.ইউস
পরম্পরায়

আপনি কি এইচএসভিটিআরজিবিতে রিটার্নের বিবৃতিটি ব্যাখ্যা করতে পারেন? এটি উপস্থিত হয় যে 3 টি উপাদান আরজিবি ভেক্টর হিউ দ্বারা একটি স্কেলারের দ্বারা বহুগুণে ফিরে এসেছে - এর ফলে [কে আর, কে জি, কে * বি, 1]
প্যাথফাইন্ডার

5

আপনি যখন সম্পৃক্তিটি নীচে নামিয়েছেন তখন @ ফিনসের জবাবটিতে আরডুওয়ের ওভারফ্লো সমস্যা রয়েছে। এটি প্রতিরোধের জন্য কিছু মানকে রূপান্তরিত করে।

typedef struct RgbColor
{
    unsigned char r;
    unsigned char g;
    unsigned char b;
} RgbColor;

typedef struct HsvColor
{
    unsigned char h;
    unsigned char s;
    unsigned char v;
} HsvColor;

RgbColor HsvToRgb(HsvColor hsv)
{
    RgbColor rgb;
    unsigned char region, p, q, t;
    unsigned int h, s, v, remainder;

    if (hsv.s == 0)
    {
        rgb.r = hsv.v;
        rgb.g = hsv.v;
        rgb.b = hsv.v;
        return rgb;
    }

    // converting to 16 bit to prevent overflow
    h = hsv.h;
    s = hsv.s;
    v = hsv.v;

    region = h / 43;
    remainder = (h - (region * 43)) * 6; 

    p = (v * (255 - s)) >> 8;
    q = (v * (255 - ((s * remainder) >> 8))) >> 8;
    t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;

    switch (region)
    {
        case 0:
            rgb.r = v;
            rgb.g = t;
            rgb.b = p;
            break;
        case 1:
            rgb.r = q;
            rgb.g = v;
            rgb.b = p;
            break;
        case 2:
            rgb.r = p;
            rgb.g = v;
            rgb.b = t;
            break;
        case 3:
            rgb.r = p;
            rgb.g = q;
            rgb.b = v;
            break;
        case 4:
            rgb.r = t;
            rgb.g = p;
            rgb.b = v;
            break;
        default:
            rgb.r = v;
            rgb.g = p;
            rgb.b = q;
            break;
    }

    return rgb;
}

HsvColor RgbToHsv(RgbColor rgb)
{
    HsvColor hsv;
    unsigned char rgbMin, rgbMax;

    rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
    rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);

    hsv.v = rgbMax;
    if (hsv.v == 0)
    {
        hsv.h = 0;
        hsv.s = 0;
        return hsv;
    }

    hsv.s = 255 * ((long)(rgbMax - rgbMin)) / hsv.v;
    if (hsv.s == 0)
    {
        hsv.h = 0;
        return hsv;
    }

    if (rgbMax == rgb.r)
        hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
    else if (rgbMax == rgb.g)
        hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
    else
        hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);

    return hsv;
}

4

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

ধরুন সবকিছু ভাসমান পয়েন্ট। আরজি এবং বি যদি 0 থেকে 1 এ যায় তবে h 0 থেকে 2pi পর্যন্ত চলে যায়, v 0 থেকে 4/3 পর্যন্ত যায় এবং s 0 থেকে 2/3 পর্যন্ত যায়।

নিম্নলিখিত কোড লুয়া লেখা হয়। এটি সহজেই অন্য যে কোনও ক্ষেত্রে অনুবাদযোগ্য।

local hsv do
    hsv         ={}
    local atan2 =math.atan2
    local cos   =math.cos
    local sin   =math.sin

    function hsv.fromrgb(r,b,g)
        local c=r+g+b
        if c<1e-4 then
            return 0,2/3,0
        else
            local p=2*(b*b+g*g+r*r-g*r-b*g-b*r)^0.5
            local h=atan2(b-g,(2*r-b-g)/3^0.5)
            local s=p/(c+p)
            local v=(c+p)/3
            return h,s,v
        end
    end

    function hsv.torgb(h,s,v)
        local r=v*(1+s*(cos(h)-1))
        local g=v*(1+s*(cos(h-2.09439)-1))
        local b=v*(1+s*(cos(h+2.09439)-1))
        return r,g,b
    end

    function hsv.tween(h0,s0,v0,h1,s1,v1,t)
        local dh=(h1-h0+3.14159)%6.28318-3.14159
        local h=h0+t*dh
        local s=s0+t*(s1-s0)
        local v=v0+t*(v1-v0)
        return h,s,v
    end
end

আপনি কি এই অ্যালগরিদমটির উত্সকে ব্যাখ্যা করতে পারেন, বা কমপক্ষে মৌলিক সম্পর্কের দিকে নির্দেশ করতে পারেন? আমি প্রত্যাশা করেছি যে কেবল কয়েকটি আরজিবি উপাদান নিয়ে গঠিত কিছু বর্ণচিহ্নগুলি খুঁজে পেয়েছিল - তবে এইচএসভি.টোরজিবি ফাংশনটি বোঝায় যে এই অ্যালগরিদমে এটি অসম্ভব। উইকিপিডিয়া এইচএসভি এবং
আরজিবির

2

প্যাটাপমসের উত্তরের ভিত্তিতে জিএলএসএল শেডার সংস্করণ:

vec3 HSV2RGB( vec3 hsv )
{
    hsv.x = mod( 100.0 + hsv.x, 1.0 ); // Ensure [0,1[
    float   HueSlice = 6.0 * hsv.x; // In [0,6[
    float   HueSliceInteger = floor( HueSlice );
    float   HueSliceInterpolant = HueSlice - HueSliceInteger; // In [0,1[ for each hue slice
    vec3  TempRGB = vec3(   hsv.z * (1.0 - hsv.y), hsv.z * (1.0 - hsv.y * HueSliceInterpolant), hsv.z * (1.0 - hsv.y * (1.0 - HueSliceInterpolant)) );
    float   IsOddSlice = mod( HueSliceInteger, 2.0 ); // 0 if even (slices 0, 2, 4), 1 if odd (slices 1, 3, 5)
    float   ThreeSliceSelector = 0.5 * (HueSliceInteger - IsOddSlice); // (0, 1, 2) corresponding to slices (0, 2, 4) and (1, 3, 5)
    vec3  ScrollingRGBForEvenSlices = vec3( hsv.z, TempRGB.zx );           // (V, Temp Blue, Temp Red) for even slices (0, 2, 4)
    vec3  ScrollingRGBForOddSlices = vec3( TempRGB.y, hsv.z, TempRGB.x );  // (Temp Green, V, Temp Red) for odd slices (1, 3, 5)
    vec3  ScrollingRGB = mix( ScrollingRGBForEvenSlices, ScrollingRGBForOddSlices, IsOddSlice );
    float   IsNotFirstSlice = clamp( ThreeSliceSelector, 0.0,1.0 );                   // 1 if NOT the first slice (true for slices 1 and 2)
    float   IsNotSecondSlice = clamp( ThreeSliceSelector-1.0, 0.0,1. );              // 1 if NOT the first or second slice (true only for slice 2)
    return  mix( ScrollingRGB.xyz, mix( ScrollingRGB.zxy, ScrollingRGB.yzx, IsNotSecondSlice ), IsNotFirstSlice );    // Make the RGB rotate right depending on final slice index
}

1

আমি সি ++ বিকাশকারী নই তাই আমি কোড সরবরাহ করব না। তবে আমি বর্তমানে সহজ hsv2rgb অ্যালগরিদম সরবরাহ করতে পারি (rgb2hsv এখানে ) যা আমি বর্তমানে আবিষ্কার করি - আমি বিবরণীর সাথে উইকি আপডেট করি: এইচএসভি এবং এইচএলএস । প্রধান উন্নতি হ'ল আমি হ'ল ফাংশন হিসাবে r, g, b কে যত্ন সহকারে পর্যবেক্ষণ করেছি এবং এগুলি বর্ণনা করার জন্য সহজ আকৃতির ফাংশনটি প্রবর্তন করেছি (নির্ভুলতাটি ছাড়াই)। অ্যালগরিদম - ইনপুটটিতে আমাদের রয়েছে: h (0-255), s (0-255), v (0-255)

r = 255*f(5),   g = 255*f(3),   b = 255*f(1)

নীচে বর্ণিত ফাংশনটি আমরা ব্যবহার করি

f(n) = v/255 - (v/255)*(s/255)*max(min(k,4-k,1),0)

যেখানে (মোড ভগ্নাংশ অংশ ফিরে আসতে পারে; কে ভাসমান পয়েন্ট নম্বর)

k = (n+h*360/(255*60)) mod 6;

এখানে জেএস: এইচএসভি এবং এইচএসএল-তে স্নিপেটস / পিওভি রয়েছে


হ্যালো কামিল! আমি আপনার অ্যালগরিদম ব্যবহার করার চেষ্টা করছি এবং সেই অংশটি সম্পর্কে আমার একটি প্রশ্ন আছে min(k,4-k,1)। কেন তিনটি মান আছে এবং এখানে ঠিক কী ঘটছে? আগাম ধন্যবাদ!
ইউজিন আলেক্সেভ

উইকির @EugeneAlexeev আমি ফিক্স নিবন্ধ (কেউ এটি ভেঙে) - এবং আপডেট লিঙ্কগুলি এখানে - তাই গভীর বোঝার জন্য পড়া এই
কামিল Kiełczewski

1

রঙ রূপান্তরকরণের জন্য সমস্ত অ্যালগরিদম ব্যাখ্যা করার পরে নিবন্ধের সাথে এখানে একটি অনলাইন রূপান্তরকারী।

আপনি সম্ভবত একটি রেডিমেড সি সংস্করণ পছন্দ করবেন তবে এটি প্রয়োগ করতে দীর্ঘ হওয়া উচিত নয় এবং এটি অন্য ভাষায় বা অন্য কোনও বর্ণের জায়গাতে একইরকম চেষ্টা করার লোকেদের সহায়তা করতে পারে।


0

এই লিঙ্কটিতে আপনি যা চান তার সূত্র রয়েছে। তাহলে আপনি যদি এটি দ্রুত চান তবে এটি পারফরম্যান্সের (সংখ্যাসূচক কৌশলগুলি) বিষয়।


0

উপরের মত একই রকম গণিতের উপর ভিত্তি করে আমি এই সকালে একটি লিখেছি যা এখানে রয়েছে:

/* math adapted from: http://www.rapidtables.com/convert/color/rgb-to-hsl.htm
 * reasonably optimized for speed, without going crazy */
void rgb_to_hsv (int r, int g, int b, float *r_h, float *r_s, float *r_v) {
  float rp, gp, bp, cmax, cmin, delta, l;
  int cmaxwhich, cminwhich;

  rp = ((float) r) / 255;
  gp = ((float) g) / 255;
  bp = ((float) b) / 255;

  //debug ("rgb=%d,%d,%d rgbprime=%f,%f,%f", r, g, b, rp, gp, bp);

  cmax = rp;
  cmaxwhich = 0; /* faster comparison afterwards */
  if (gp > cmax) { cmax = gp; cmaxwhich = 1; }
  if (bp > cmax) { cmax = bp; cmaxwhich = 2; }
  cmin = rp;
  cminwhich = 0;
  if (gp < cmin) { cmin = gp; cminwhich = 1; }
  if (bp < cmin) { cmin = bp; cminwhich = 2; }

  //debug ("cmin=%f,cmax=%f", cmin, cmax);
  delta = cmax - cmin;

  /* HUE */
  if (delta == 0) {
    *r_h = 0;
  } else {
    switch (cmaxwhich) {
      case 0: /* cmax == rp */
        *r_h = HUE_ANGLE * (fmod ((gp - bp) / delta, 6));
      break;

      case 1: /* cmax == gp */
        *r_h = HUE_ANGLE * (((bp - rp) / delta) + 2);
      break;

      case 2: /* cmax == bp */
        *r_h = HUE_ANGLE * (((rp - gp) / delta) + 4);
      break;
    }
    if (*r_h < 0)
      *r_h += 360;
  }

  /* LIGHTNESS/VALUE */
  //l = (cmax + cmin) / 2;
  *r_v = cmax;

  /* SATURATION */
  /*if (delta == 0) {
    *r_s = 0;
  } else {
    *r_s = delta / (1 - fabs (1 - (2 * (l - 1))));
  }*/
  if (cmax == 0) {
    *r_s = 0;
  } else {
    *r_s = delta / cmax;
  }
  //debug ("rgb=%d,%d,%d ---> hsv=%f,%f,%f", r, g, b, *r_h, *r_s, *r_v);
}


void hsv_to_rgb (float h, float s, float v, int *r_r, int *r_g, int *r_b) {
  if (h > 360)
    h -= 360;
  if (h < 0)
    h += 360;
  h = CLAMP (h, 0, 360);
  s = CLAMP (s, 0, 1);
  v = CLAMP (v, 0, 1);
  float c = v * s;
  float x = c * (1 - fabsf (fmod ((h / HUE_ANGLE), 2) - 1));
  float m = v - c;
  float rp, gp, bp;
  int a = h / 60;

  //debug ("h=%f, a=%d", h, a);

  switch (a) {
    case 0:
      rp = c;
      gp = x;
      bp = 0;
    break;

    case 1:
      rp = x;
      gp = c;
      bp = 0;
    break;

    case 2:
      rp = 0;
      gp = c;
      bp = x;
    break;

    case 3:
      rp = 0;
      gp = x;
      bp = c;
    break;

    case 4:
      rp = x;
      gp = 0;
      bp = c;
    break;

    default: // case 5:
      rp = c;
      gp = 0;
      bp = x;
    break;
  }

  *r_r = (rp + m) * 255;
  *r_g = (gp + m) * 255;
  *r_b = (bp + m) * 255;

  //debug ("hsv=%f,%f,%f, ---> rgb=%d,%d,%d", h, s, v, *r_r, *r_g, *r_b);
}

ক্ল্যাম্প এবং HUE_ANGLE এর প্রতীক সংজ্ঞাগুলি অনুপস্থিত
দিমিত্রি

0

আমি আরজিবিএস এবং ভি এর জন্য 0-1 রেঞ্জ এবং হিউ (বিভাগ এড়ানো) এর জন্য 0-6 রেঞ্জ ব্যবহার করে এবং কেস দুটি বিভাগে বিভক্ত করে একটি সম্ভবত দ্রুত বাস্তবায়ন তৈরি করেছি:

#include <math.h>
#include <float.h>

void fromRGBtoHSV(float rgb[], float hsv[])
{
//    for(int i=0; i<3; ++i)
//        rgb[i] = max(0.0f, min(1.0f, rgb[i]));

     hsv[0] = 0.0f;
     hsv[2] = max(rgb[0], max(rgb[1], rgb[2]));
     const float delta = hsv[2] - min(rgb[0], min(rgb[1], rgb[2]));

     if (delta < FLT_MIN)
         hsv[1] = 0.0f;
     else
     {
         hsv[1] = delta / hsv[2];
         if (rgb[0] >= hsv[2])
         {
             hsv[0] = (rgb[1] - rgb[2]) / delta;
             if (hsv[0] < 0.0f)
                 hsv[0] += 6.0f;
         }
         else if (rgb[1] >= hsv[2])
             hsv[0] = 2.0f + (rgb[2] - rgb[0]) / delta;
         else
             hsv[0] = 4.0f + (rgb[0] - rgb[1]) / delta;
     }    
}

void fromHSVtoRGB(const float hsv[], float rgb[])
{
    if(hsv[1] < FLT_MIN)
        rgb[0] = rgb[1] = rgb[2] = hsv[2];
    else
    {
        const float h = hsv[0];
        const int i = (int)h;
        const float f = h - i;
        const float p = hsv[2] * (1.0f - hsv[1]);

        if (i & 1) {
            const float q = hsv[2] * (1.0f - (hsv[1] * f));
            switch(i) {
            case 1:
                rgb[0] = q;
                rgb[1] = hsv[2];
                rgb[2] = p;
                break;
            case 3:
                rgb[0] = p;
                rgb[1] = q;
                rgb[2] = hsv[2];
                break;
            default:
                rgb[0] = hsv[2];
                rgb[1] = p;
                rgb[2] = q;
                break;
            }
        }
        else
        {
            const float t = hsv[2] * (1.0f - (hsv[1] * (1.0f - f)));
            switch(i) {
            case 0:
                rgb[0] = hsv[2];
                rgb[1] = t;
                rgb[2] = p;
                break;
            case 2:
                rgb[0] = p;
                rgb[1] = hsv[2];
                rgb[2] = t;
                break;
            default:
                rgb[0] = t;
                rgb[1] = p;
                rgb[2] = hsv[2];
                break;
            }
        }
    }
}

0-255 রেঞ্জের জন্য কেবল * 255.0f + 0.5f এবং এটিকে স্বাক্ষরবিহীন চরে বরাদ্দ করুন (বা বিপরীতে পেতে 255.0 দিয়ে ভাগ করুন)।


0
// This pair of functions convert HSL to RGB and vice-versa.
// It's pretty optimized for execution speed

typedef unsigned char       BYTE
typedef struct _RGB
{
    BYTE R;
    BYTE G;
    BYTE B;
} RGB, *pRGB;
typedef struct _HSL
{
    float   H;  // color Hue (0.0 to 360.0 degrees)
    float   S;  // color Saturation (0.0 to 1.0)
    float   L;  // Luminance (0.0 to 1.0)
    float   V;  // Value (0.0 to 1.0)
} HSL, *pHSL;

float   *fMin       (float *a, float *b)
{
    return *a <= *b?  a : b;
}

float   *fMax       (float *a, float *b)
{
    return *a >= *b? a : b;
}

void    RGBtoHSL    (pRGB rgb, pHSL hsl)
{
// See https://en.wikipedia.org/wiki/HSL_and_HSV
// rgb->R, rgb->G, rgb->B: [0 to 255]
    float r =       (float) rgb->R / 255;
    float g =       (float) rgb->G / 255;
    float b =       (float) rgb->B / 255;
    float *min =    fMin(fMin(&r, &g), &b);
    float *max =    fMax(fMax(&r, &g), &b);
    float delta =   *max - *min;

// L, V [0.0 to 1.0]
    hsl->L = (*max + *min)/2;
    hsl->V = *max;
// Special case for H and S
    if (delta == 0)
    {
        hsl->H = 0.0f;
        hsl->S = 0.0f;
    }
    else
    {
// Special case for S
        if((*max == 0) || (*min == 1))
            hsl->S = 0;
        else
// S [0.0 to 1.0]
            hsl->S = (2 * *max - 2*hsl->L)/(1 - fabsf(2*hsl->L - 1));
// H [0.0 to 360.0]
        if      (max == &r)     hsl->H = fmod((g - b)/delta, 6);    // max is R
        else if (max == &g)     hsl->H = (b - r)/delta + 2;         // max is G
        else                    hsl->H = (r - g)/delta + 4;         // max is B
        hsl->H *= 60;
    }
}

void    HSLtoRGB    (pHSL hsl, pRGB rgb)
{
// See https://en.wikipedia.org/wiki/HSL_and_HSV
    float a, k, fm1, fp1, f1, f2, *f3;
// L, V, S: [0.0 to 1.0]
// rgb->R, rgb->G, rgb->B: [0 to 255]
    fm1 = -1;
    fp1 = 1;
    f1 = 1-hsl->L;
    a = hsl->S * *fMin(&hsl->L, &f1);
    k = fmod(0 + hsl->H/30, 12);
    f1 = k - 3;
    f2 = 9 - k;
    f3 = fMin(fMin(&f1, &f2), &fp1) ;
    rgb->R = (BYTE) (255 * (hsl->L - a * *fMax(f3, &fm1)));

    k = fmod(8 + hsl->H/30, 12);
    f1 = k - 3;
    f2 = 9 - k;
    f3 = fMin(fMin(&f1, &f2), &fp1) ;
    rgb->G = (BYTE) (255 * (hsl->L - a * *fMax(f3, &fm1)));

    k = fmod(4 + hsl->H/30, 12);
    f1 = k - 3;
    f2 = 9 - k;
    f3 = fMin(fMin(&f1, &f2), &fp1) ;
    rgb->B = (BYTE) (255 * (hsl->L - a * *fMax(f3, &fm1)));
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.