Convert single 8 bit value (0-255) to 3, 8 bit values - python

Alright so the best way I can really explain this is on this site https://www.colorspire.com/rgb-color-wheel/ there is a color wheel when you first load the site don't move the little pointer in the square to select stuff. Just go to the bar that you can drag and drag it you'll see the r g b values change but you will also notice that one of the values is always 0, how can I recreate that but instead of the bar you drag you input a single 8 bit value (out of 255) so I can run the program with the value lets say 170 and it would somehow map that to a certain color.

You are actually changing the hue when you move the bar so try this
import colorsys
color = input("Enter a value from 0-359:")
test_color = colorsys.hsv_to_rgb(color/360.0, 1, 1)
References
HSV to RGB Color Conversion

test_color = colorsys.hsv_to_rgb(int(value)/255.0, 1, 1)
r, g, b = test_color
r = (r * 255)
r = math.trunc(r)
g = (g * 255)
g = math.trunc(g)
b = (b * 255)
b = math.trunc(b)
fg.orange = Style(RgbFg(r, g, b))
msg = fg.orange + str(f" r = {r}, g = {g}, b = {b}")
print(msg)

Related

Combine two normal texture maps with python cv2

I'm wanting to combine two normal texture maps. My understanding is one of the simplest methods is sum the red/green channels from each normal map and then divide by the length.
Reference a concept from here as well and trying to convert to python: https://blog.selfshadow.com/publications/blending-in-detail/ (the simpler UDN blending method)
float3 r = normalize(float3(n1.xy + n2.xy, n1.z));
Using the concept of dividing the rgb vector by its length as my "normalizing" method.
For any vector V = (x, y, z), |V| = sqrt(xx + yy + z*z) gives the
length of the vector. When we normalize a vector, we actually
calculate V/|V| = (x/|V|, y/|V|, z/|V|).
img1 = cv2.imread(str(base_image)).astype(np.float32)
img2 = cv2.imread(str(top_image)).astype(np.float32)
# img = img1 + img2 # Could just do this to combine r,g channels?
(b1, g1, r1) = cv2.split(img1)
(b2, g2, r2) = cv2.split(img2)
r = r1 + r2
g = g1 + g2
b = b1
r_norm = []
g_norm = []
for (_r, _g, _b) in zip(r.ravel(), g.ravel(), b.ravel()):
_l = length(_r, _g, _b)
r_norm.append((_r / _l)*255)
g_norm.append((_g / _l)*255)
r = np.reshape(r_norm, (-1, 2048))
g = np.reshape(g_norm, (-1, 2048))
img = np.dstack((b, g, r))
cv2.imwrite(str(output_path), img)
where length is defined as:
def length(r, g, b):
return math.sqrt((r ** 2 + g ** 2 + b ** 2))
But its not working..I get a very gray image.
On the side this process is slow so if anyone has ideas to speed up the loop (or remove it entirely) that would be awesome :). Been pulling my hair out on this one...

I am trying to exclude the color black when picking random colors

I have this random color generation code.
background_red = 0.25 * random.randrange(0, 2)
background_green = 0.25 * random.randrange(0, 2)
background_blue = 0.25 * random.randrange(0, 2)
how do I make it exclude the color black?
When generating a random value, if you want to exclude certain possibilities, the most simple way is to loop until you generate a valid one.
while(true):
background_red = 0.25 * random.randrange(0, 2)
background_green = 0.25 * random.randrange(0, 2)
background_blue = 0.25 * random.randrange(0, 2)
if any((background_red, background_green, background_blue)):
# if all values are 0 (black) don't break
break
If you wanted to exclude a large amount of possible values, it would be better to have a smarter approach, but for these cases you'll find this is more than enough.
The color black is 0, 0, 0 so you can simply again randomize the rgb values if you get 0, 0, 0 with using if statements, while staements and many more.
I have used while statement in here:
background_red = 0.25 * random.randrange(0, 2)
background_green = 0.25 * random.randrange(0, 2)
background_blue = 0.25 * random.randrange(0, 2)
while (background_red + background_green + background_blue) == 0:
background_red = 0.25 * random.randrange(0, 2)
background_green = 0.25 * random.randrange(0, 2)
background_blue = 0.25 * random.randrange(0, 2)
Hope it works!
you could try
N = 30
background_red = max((255 * random.random()), N)
background_green = max((255 * random.random()), N)
background_blue = max((255 * random.random()), N)
where N is a cut off for how dim the colour can be 0 is full black but 1, 1, 1 is extreamly close so you may want to play around with N, this version will pick random values between 0 and 255 the maximum value for RGB though im not sure exactly what parameters you are using to get te colour from your RGB valuesso this may not work for you
My answer assumes you want a (basically) continuous selection of colors from color space (a cube of side length one, with one corner at the origin and three sides aligned with the three color axes), excluding some region around black at the origin. At its core, they use random.random to generate three coordinates which are somehow mapped into color space.
The following function, v1, generates colors uniformly in color space excluding a cube of length k closest to the origin (where black is). It uses the tried and true "if it's not what you want, regenerate until it is" method, as suggested by other answers (and is definitely a solid choice).
def v1(k = 0.5):
while True:
r = random.random()
g = random.random()
b = random.random()
if any([c > k for c in [r,g,b]]):
break
return (r, g, b)
This function, on the other hand, only generates numbers once, and just maps the generated coordinates uniformly into the cube-minus-corner. Its calculationally more intensive, though there's a chance, depending on what the stream from random is, that it will go faster than v1 (though that's unlikely, and is more unlikely the smaller k is.
def v2(k):
V = np.array([1-k**3, 1-k**2])
P = 1 - (1-k)/V
x1 = random.random()
x2 = random.random()
x3 = random.random()
if x1 > P[0]:
r = k + (1-k)*(x1 - P[0])/(1- P[0])
g = x2
b = x3
else:
r = k*x1/P[0]
if x2 > P[1]:
g = k + (1-k)*(x2 - P[1])/(1- P[1])
b = x3
else:
g = k*x2/P[1]
b = k + (1-k)*x3
return (r,g,b)
v2 is also what you'd want to implement a vectorized version (the math, not the logic - you'd want to make it branchless) - so for an array of arrays of color coordinates of length N:
def v2_vectorized(k ,N):
V = np.array([1-k**3, 1-k**2])
P = 1 - (1-k)/V
x1 = np.random.rand(N)
x2 = np.random.rand(N)
x3 = np.random.rand(N)
r = (x1 > P[0])*(k + (1-k)*(x1 - P[0])/(1- P[0])) + (x1 <= P[0])*(k*x1/P[0])
g = (x1 > P[0])*x2 + (x1 <= P[0])*((x2 > P[1])*(k + (1-k)*(x2 - P[1])/(1- P[1])) + (x2 <= P[1])*(k*x2/P[1]))
b = (x1 > P[0])*x3 + (x1 <= P[0])*((x2 > P[1])*x3 + (x2 <= P[1])*(k + (1-k)*x3))
return np.array([r,g,b])
This guy is pretty messy, but it's fast and it works for large samples (at least, much faster than doing v1 in a loop)
Another option is to just make colors near black exceptionally unlikely: the following function, v3, generates colors unrestricted in color space, but the PDF of colors is a line - so the probability density of a coordinate of the color is proportional to the magnitude of that coordinate.
def v3():
r = np.sqrt(random.random())
g = np.sqrt(random.random())
b = np.sqrt(random.random())
return (r, g, b)
This one is nice, because it still allows some in the dark-grey region, and it's neither intensive in calculations and doesn't have the possibility of looping many times, though it has the downside of eventually getting arbitrarily close to black as the sample size gets larger and larger.
Other options include generating spherical coordinates and restricting the radius, or restricting yourself above planes normal to (1,1,1) (so, forbidding triangular pyramids as opposed to cubes). Another option is just to define a list of colors and randomly choosing from that (matplotlib's built in default color sequence is accessible as matplotlib.pyplot.rcParams['axes.prop_cycle'].by_key()['color'], and is a good choice for a pleasant sequence of diverse colors). Matplotlib also has nice choices in Colormap form, which map floats in [0,1) directly to colors, many of which do not include black.

Color Transfer Between Two Image with One Image as Plain Color

I came across this particular color-transfer tutorial using OpenCV:
https://www.pyimagesearch.com/2014/06/30/super-fast-color-transfer-images/
and implemented it like this:
def color_transfer(source, target):
# compute color statistics for the source and target images
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
# compute color stats for both images
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = self.image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = self.image_stats(target)
# split the color space
(l, a, b) = cv2.split(target)
# substract the means from target image
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# check values
print(lStdSrc, aStdSrc, bStdSrc)
print(lStdTar, aStdTar, bStdTar)
print(lMeanSrc, aStdSrc, bMeanSrc)
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
# add the source mean
l += lMeanSrc
a += aMeanSrc
b += bMeanSrc
# clipping the pixels between 0 and 255
l = np.clip(l, 0, 255)
a = np.clip(a, 0, 255)
b = np.clip(b, 0, 255)
# merge the channels
transfer = cv2.merge([l, a, b])
# converting back to BGR
transfer = cv2.cvtColor(transfer.astype("uint8"), cv2.COLOR_LAB2BGR)
return transfer
In this particular code:
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
it gets the standard deviation of the source, so when we combine the source and the target image, it will become a plain image as well since the lab will all be 0.
How can I fix this? It works when the source image is not a plain image with color.

RGB to HSV conversion using PIL

I'm trying to automate the enhancement of some images that are to be transfered to a digital frame. I have code in place that resizes, adds a date/time to the least-significant (least details) corner of the image and pastes together pairs of portrait images to avoid displaying a single portrait in the frame's 41:20 low resolution screen.
I've implemented a brightness-stretching filter for those pictures where the lighting wasn't so good, using the colorsys.rgb_to_hsv function to calculate H, S, V bands, operating on the V one and then converting back to RGB before saving a JPEG in the digital frame. Obviously, the conversion takes a lot of time, even using itertools tricks; I managed to improve things using psyco.
However, I noticed an example for the PIL Image.convert where RGB can be converted to XYZ color space using a 4×4 matrix as a second argument to the convert method, and I got to wonder:
How can I convert RGB to HSV (and then HSV back to RGB) using a custom matrix in the convert method call? (Minor rounding errors are not important in this case, so I don't mind that each band will be expressed as a series of 0…255 integers)
Thank you in advance.
Although I've seen references[1] that claim HSV color-space is linear transformation from RGB, which would seem to imply that it could be done with a matrix, I have been unable to find or determine for myself just what such a matrix would look like. In a way this doesn't really surprise me based on all the [similar] non-matrix procedural implementations I've also seen -- the way they go about it doesn't look linear.
Anyway, while looking into this, I ran across a [somewhat dated] article in former SGI researcher Paul Haeberli's online computer graphics notebook titled Matrix Operations for Image Processing which describes how to do a number of different color transformations using 4x4 matrices which might help you. All of the examples given operate directly on RGB color images and, like geometric matrix transformations, any sequence of them can be combined into a single matrix using concatenation.
Hope this helps.
[1]: Colour Space Conversions <http://www.poynton.com/PDFs/coloureq.pdf>:
2.7.3 HSL (Hue Saturation and Lightness)
This represents a wealth of similar
colour spaces, alternative names
include HSI (intensity), HSV (value),
HCI (chroma / colourfulness), HVC,
TSD (hue saturation and darkness) etc.
Most of these colour spaces are
linear transforms from RGB and are
therefore device dependent and
non–linear. Their advantage lies in
the extremely intuitive manner of
specifying colour. It is very easy to
select a desired hue and to then
modify it slightly by adjustment of
its saturation and intensity.
The formula to transform an RGB value to an HSV value can be found here: http://www.rapidtables.com/convert/color/rgb-to-hsv.htm. I once needed it the other way around, and made the following function for it.
def hsb2rgb(hsb):
'''
Transforms a hsb array to the corresponding rgb tuple
In: hsb = array of three ints (h between 0 and 360, s and v between 0 and 100)
Out: rgb = array of three ints (between 0 and 255)
'''
H = float(hsb[0] / 360.0)
S = float(hsb[1] / 100.0)
B = float(hsb[2] / 100.0)
if (S == 0):
R = int(round(B * 255))
G = int(round(B * 255))
B = int(round(B * 255))
else:
var_h = H * 6
if (var_h == 6):
var_h = 0 # H must be < 1
var_i = int(var_h)
var_1 = B * (1 - S)
var_2 = B * (1 - S * (var_h - var_i))
var_3 = B * (1 - S * (1 - (var_h - var_i)))
if (var_i == 0):
var_r = B ; var_g = var_3 ; var_b = var_1
elif (var_i == 1):
var_r = var_2 ; var_g = B ; var_b = var_1
elif (var_i == 2):
var_r = var_1 ; var_g = B ; var_b = var_3
elif (var_i == 3):
var_r = var_1 ; var_g = var_2 ; var_b = B
elif (var_i == 4):
var_r = var_3 ; var_g = var_1 ; var_b = B
else:
var_r = B ; var_g = var_1 ; var_b = var_2
R = int(round(var_r * 255))
G = int(round(var_g * 255))
B = int(round(var_b * 255))
return [R, G, B]

How to generate random 'greenish' colors

Anyone have any suggestions on how to make randomized colors that are all greenish? Right now I'm generating the colors by this:
color = (randint(100, 200), randint(120, 255), randint(100, 200))
That mostly works, but I get brownish colors a lot.
Simple solution: Use the HSL or HSV color space instead of rgb (convert it to RGB afterwards if you need this). The difference is the meaning of the tuple: Where RGB means values for Red, Green and Blue, in HSL the H is the color (120 degree or 0.33 meaning green for example) and the S is for saturation and the V for the brightness. So keep the H at a fixed value (or for even more random colors you could randomize it by add/sub a small random number) and randomize the S and the V. See the wikipedia article.
As others have suggested, generating random colours is much easier in the HSV colour space (or HSL, the difference is pretty irrelevant for this)
So, code to generate random "green'ish" colours, and (for demonstration purposes) display them as a series of simple coloured HTML span tags:
#!/usr/bin/env python2.5
"""Random green colour generator, written by dbr, for
http://stackoverflow.com/questions/1586147/how-to-generate-random-greenish-colors
"""
def hsv_to_rgb(h, s, v):
"""Converts HSV value to RGB values
Hue is in range 0-359 (degrees), value/saturation are in range 0-1 (float)
Direct implementation of:
http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_HSV_to_RGB
"""
h, s, v = [float(x) for x in (h, s, v)]
hi = (h / 60) % 6
hi = int(round(hi))
f = (h / 60) - (h / 60)
p = v * (1 - s)
q = v * (1 - f * s)
t = v * (1 - (1 - f) * s)
if hi == 0:
return v, t, p
elif hi == 1:
return q, v, p
elif hi == 2:
return p, v, t
elif hi == 3:
return p, q, v
elif hi == 4:
return t, p, v
elif hi == 5:
return v, p, q
def test():
"""Check examples on..
http://en.wikipedia.org/wiki/HSL_and_HSV#Examples
..work correctly
"""
def verify(got, expected):
if got != expected:
raise AssertionError("Got %s, expected %s" % (got, expected))
verify(hsv_to_rgb(0, 1, 1), (1, 0, 0))
verify(hsv_to_rgb(120, 0.5, 1.0), (0.5, 1, 0.5))
verify(hsv_to_rgb(240, 1, 0.5), (0, 0, 0.5))
def main():
"""Generate 50 random RGB colours, and create some simple coloured HTML
span tags to verify them.
"""
test() # Run simple test suite
from random import randint, uniform
for i in range(50):
# Tweak these values to change colours/variance
h = randint(90, 140) # Select random green'ish hue from hue wheel
s = uniform(0.2, 1)
v = uniform(0.3, 1)
r, g, b = hsv_to_rgb(h, s, v)
# Convert to 0-1 range for HTML output
r, g, b = [x*255 for x in (r, g, b)]
print "<span style='background:rgb(%i, %i, %i)'> </span>" % (r, g, b)
if __name__ == '__main__':
main()
The output (when viewed in a web-browser) should look something along the lines of:
Edit: I didn't know about the colorsys module. Instead of the above hsv_to_rgb function, you could use colorsys.hsv_to_rgb, which makes the code much shorter (it's not quite a drop-in replacement, as my hsv_to_rgb function expects the hue to be in degrees instead of 0-1):
#!/usr/bin/env python2.5
from colorsys import hsv_to_rgb
from random import randint, uniform
for x in range(50):
h = uniform(0.25, 0.38) # Select random green'ish hue from hue wheel
s = uniform(0.2, 1)
v = uniform(0.3, 1)
r, g, b = hsv_to_rgb(h, s, v)
# Convert to 0-1 range for HTML output
r, g, b = [x*255 for x in (r, g, b)]
print "<span style='background:rgb(%i, %i, %i)'> </span>" % (r, g, b)
Check out the colorsys module:
http://docs.python.org/library/colorsys.html
Use the HSL or HSV color space. Randomize the hue to be close to green, then choose completely random stuff for the saturation and V (brightness).
If you stick with RGB, you basically just need to make sure the G value is greater than the R and B, and try to keep the blue and red values similar so that the hue doesn't go too crazy. Extending from Slaks, maybe something like (I know next to nothing about Python):
greenval = randint(100, 255)
redval = randint(20,(greenval - 60))
blueval = randint((redval - 20), (redval + 20))
color = (redval, greenval, blueval)
So in this case you are lucky enough to want variations on a primary color, but for artistic uses like this it is better to specify color wheel coordinates rather than primary color magnitudes.
You probably want something from the colorsys module like:
colorsys.hsv_to_rgb(h, s, v)
Convert the color from HSV coordinates to RGB coordinates.
The solution with HSx color space is a very good one. However, if you need something extremely simplistic and have no specific requirements about the distribution of the colors (like uniformity), a simplistic RGB-based solution would be just to make sure that G value is greater than both R and B
rr = randint(100, 200)
rb = randint(100, 200)
rg = randint(max(rr, rb) + 1, 255)
This will give you "greenish" colors. Some of them will be ever so slightly greenish. You can increase the guaranteed degree of greenishness by increasing (absolutely or relatively) the lower bound in the last randint call.
What you want is to work in terms of HSL instead of RGB. You could find a range of hue that satisfies "greenish" and pick a random hue from it. You could also pick random saturation and lightness but you'll probably want to keep your saturation near 1 and your lightness around 0.5 but you can play with them.
Below is some actionscript code to convert HSL to RGB. I haven't touched python in a while or it'd post the python version.
I find that greenish is something like 0.47*PI to 0.8*PI.
/**
#param h hue [0, 2PI]
#param s saturation [0,1]
#param l lightness [0,1]
#return object {r,g,b} {[0,1],[0,1][0,1]}
*/
public function hslToRGB(h:Number, s:Number, l:Number):Color
{
var q:Number = (l<0.5)?l*(1+s):l+s-l*s;
var p:Number = 2*l-q;
var h_k:Number = h/(Math.PI*2);
var t_r:Number = h_k+1/3;
var t_g:Number = h_k;
var t_b:Number = h_k-1/3;
if (t_r < 0) ++t_r; else if (t_r > 1) --t_r;
if (t_g < 0) ++t_g; else if (t_g > 1) --t_g;
if (t_b < 0) ++t_b; else if (t_b > 1) --t_b;
var c:Color = new Color();
if (t_r < 1/6) c.r = p+((q-p)*6*t_r);
else if (t_r < 1/2) c.r = q;
else if (t_r < 2/3) c.r = p+((q-p)*6*(2/3-t_r));
else c.r = p;
if (t_g < 1/6) c.g = p+((q-p)*6*t_g);
else if (t_g < 1/2) c.g = q;
else if (t_g < 2/3) c.g = p+((q-p)*6*(2/3-t_g));
else c.g = p;
if (t_b < 1/6) c.b = p+((q-p)*6*t_b);
else if (t_b < 1/2) c.b = q;
else if (t_b < 2/3) c.b = p+((q-p)*6*(2/3-t_b));
else c.b = p;
return c;
}
The simplest way to do this is to make sure that the red and blue components are the same, like this: (Forgive my Python)
rb = randint(100, 200)
color = (rb, randint(120, 255), rb)
I'd go with with the HSV approach everyone else mentioned. Another approach would be to get a nice high resolution photo which some greenery in it, crop out the non-green parts, and pick random pixels from it using PIL.

Categories