4

In this question I need some algorithmic or logical help from you guys. If this is possible in some ways...

So I have to develop/write a function that receive a temperature value as an input (C° or F°), and return the specific color against the temperature exactly in this picture. For example if we input 0C° the color value should be return as Cyan (Hex value: 29eff6 OR RGB: 41,239,246)

Reference Image

enter image description here

I have searched a lot on different sites but found nothing related this. There are kelvin color codes for 1000K° plus and these are not related to my problem.

Any help on this would be greatly appreciated.

Inder Kumar Rathore
  • 39,458
  • 17
  • 135
  • 184
  • What's the provenance of the reference image? Whoever produced that picture probably also has the background information about how it was produced. – tripleee Mar 08 '18 at 07:01
  • Yes already asked it to image provider. But did not find any satisfactory answer on it. – Muhammad Ahmad Mar 08 '18 at 07:05
  • Even if they can't or won't tell you, it would perhaps help us understand your situation better if you could explain where this came from and how they are not telling you the full story. – tripleee Mar 08 '18 at 07:07
  • 1
    Crop the image so you only have the color gradient, then map your input to a pixel value of the width of the image (e.g. -50°C => 0px, +55°C => image.width) and read the color value at that x-Position of the picture. This way you dont need any information how the image was created and you can simply change it if you want different results. – d.felber Mar 08 '18 at 07:15
  • @d.felber can you please explain a little more on your comment " then map your input to a pixel value of the width of the image (e.g. -50°C => 0px, +55°C => image.width) and read the color value at that x-Position of the picture." – Muhammad Ahmad Mar 08 '18 at 07:29
  • I mean that you should translate the input value to a position of the image with the gradient. then you could use something like that: https://stackoverflow.com/questions/25146557/how-do-i-get-the-color-of-a-pixel-in-a-uiimage-with-swift to get the color at that pixel-position of the image – d.felber Mar 08 '18 at 07:39

2 Answers2

2

range.png: range.png

Here is an example of a simple/fake solution I mentioned in a comment:

import UIKit


func mapValue(value: CGFloat, inMin: CGFloat, inMax: CGFloat, outMin: CGFloat, outMax: CGFloat) -> CGFloat {
    // when the input value is lower than `inMin` use `inMin`
    // when the input value is bigger than `inMax` use `inMax`
    let value = max(min(value, inMax), inMin)

    let div = inMax - inMin
    guard div > 0 else {
        return inMin
    }

    return (value - inMin) / div * (outMax - outMin) + outMin
}


func getColor(for degreesCelsius: CGFloat) -> UIColor {
    // your color-range-image
    let rangeImage = UIImage(named: "range.png")!

    // the size of your color-range-image
    let imageSize = rangeImage.size

    let inMin: CGFloat = -50 // the lowest value as seen from the image
    let inMax: CGFloat = 55 // the highest value as seen from the image

    // the mapped input value
    let mappedInput = mapValue(value: degreesCelsius,
                               inMin: inMin, inMax: inMax,
                               outMin: 0, outMax: imageSize.width - 1)

    // position of the pixel in the image whose color should be extracted
    let pos = CGPoint(x: mappedInput, y: 0)

    return rangeImage.getPixelColor(pos: pos)
}

// get the color of 37°C
let color = getColor(for: 37)

For extracting the UIColor of an UIImage at a certain position you could use:

// taken from https://stackoverflow.com/a/40237504/4511639
extension UIImage {
    func getPixelColor(pos: CGPoint) -> UIColor {

        let pixelData = self.cgImage!.dataProvider!.data
        let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)

        let pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4

        let r = CGFloat(data[pixelInfo]) / CGFloat(255.0)
        let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
        let b = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
        let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}
d.felber
  • 5,288
  • 1
  • 21
  • 36
1

What you need is convert Temperature to RGB color. For that you can use:

You image however suggest you are using wavelength colors instead of temperature colors:

as your gradient has nothing to do with real temperature then just use the code in the link. Then just linearly interpolate between temperature and wavelength like:

wavelength = 400 + (800-400)*(T-t0)/(t1-t0) [nm]

where T is your temperature and t0,t1 are the gradient edge temperatures in the same units as T for example:

t0=-50C
t1=+50C

if you play with t0,t1 you might shift the colors to left and right. You can also use any other interpolation not just linear. Or even interpolate the image RGB like I did in both of the linked QAs.

In case you wanted the real thing (which you clearly stated you don't but those who venture here due to your title might) then the real problem is how to convert temperature into BV index. I cannot find any equation for it now. The only stuff I found is

equation:

T=f(BV)

table:

    T[K]    BV
O5  42 000  -0.33
O9  34 000  -0.31
B0  30 000  -0.30
B2  20 900  -0.24
B5  15 200  -0.17
B8  11 400  -0.11
A0  9 790   -0.02
A2  9 000   0.05
A5  8 180   0.15
F0  7 300   0.30
F2  7 000   0.35
F5  6 650   0.44
F8  6 250   0.52
G0  5 940   0.58
G2  5 790   0.63
G5  5 560   0.68
G8  5 310   0.74
K0  5 150   0.81
K2  4 830   0.91
K5  4 410   1.15
M0  3 840   1.40
M2  3 170   1.49
M5  3 170   1.64

dependece graph::

T vs. BV

So you either interpolate it or approximate from table/graph or compute it algebraically from the equation (looks like quadratic equation to me).

if I did not make any mistake than:

bv0=(+sqrt((729.0*T*T) + 52900000000.0) - (58*T) + 230000.0 ) / 46.0*T
bv1=(-sqrt((729.0*T*T) + 52900000000.0) - (58*T) + 230000.0 ) / 46.0*T

my guts are telling me that bv0 is the one as bv1 would be too much negative. but It looks like the Wiki equation is just very poor approximation so its inverse is even worse ...

On top of all this if you got specific parameters of the object and environment than you need to change the color by it by adding scattering and mixing body color if you want more realistic colors.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • I'm pretty sure we're looking at producing a weather map rather than a star chart - as you imply, stars are never purple. The asker just needs to do some linear interpolation with a series of fixed points. – AakashM Mar 08 '18 at 09:31