Related
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.
I'm currently trying to figure out how to increase/decrease the brightness of a .tiff file without parsing each pixel (too high power consumption). Right now, using the front micro-service, the user uses a ng-slider to change the value of the desired brightness,which goes directly to the back where it is parsed to try to compute a new .tiff.
So, I'm wondering if there isn't a gdal function I can't find to directly alter the images and increase/decrease the brightness at will!
The code currently looks like this (also trying to change the contrast, but I could find my way if I understand how to change the brightness) :
# Contrast & Luminosity
def get_correctMap(path, luminosity, contrast):
ds = gdal.Open(image_path)
#To normalize
band1 = ds.GetRasterBand(1)
#Get the max value
maxValue = int(2**16 -1)
if band1.DataType == gdal.GDT_UInt16:
maxValue = int(2**16 -1)
elif band1.DataType == gdal.GDT_Byte:
maxValue = int(2**8 -1)
else:
LOGGER.info(f"band type {band1.DataType} not handled: use default size of value (16 bits)")
band1 = ds.ReadAsArray(0,0,ds.RasterXSize,ds.RasterYSize)[0]
band2 = ds.ReadAsArray(0,0,ds.RasterXSize,ds.RasterYSize)[1]
band3 = ds.ReadAsArray(0,0,ds.RasterXSize,ds.RasterYSize)[2]
for x in range(0,ds.RasterXSize):
for y in range(0,ds.RasterXSize):
r = float(band1[x,y]) / maxValue
g = float(band2[x,y]) / maxValue
b = float(band3[x,y]) / maxValue
#Convert to HLS them apply luminosity and contrast
(h,l,s) = colorsys.rgb_to_hls(r, g, b)
l = min(max(0, l + (l - 0.5)*(luminosity - 0.5)) , 1)
s = min(max(0, s + (s - 0.5)*(contrast - 0.5)) , 1)
(r,g,b) = colorsys.hls_to_rgb(h, l, s)
band1[x,y] = int(r * maxValue)
band2[x,y] = int(g * maxValue)
band3[x,y] = int(b * maxValue)
#Need to save the changes, but obviously already too long to pursue this way
#and save the news bands
ds.flushCache()
return path
Hope you know a better way I can't find!
Thanks in advance.
A first lead could be to use the last features provide by OpenLayer for me, but it is not a back solution anymore, I'm digging it.
https://geoadmin.github.io/ol3/apidoc/ol.layer.Tile.html
EDIT: The constrast and luminosity feature are only implemented on OpenLayer 3 but not in the next version (including mine OL 5), so the proper answer is : it is not possible.
Python PIL library allows me to map any quadrilateral in an image to rectangle using
im.transform(size, QUAD, data)
What I need is a function that does the opposite, i.e. map a rectangular image to specified quadrilateral.
I figured this might be achieved with the above mentioned function like this:
I.e. I would find such quad (the red one in the image) that would, using the function im.transform(size, QUAD, data) transform the image to quad I want. The problem is I don't know how to find the red quad.
I would appreciate any idea on how to find the red quad or any other way to map a rect image to quad, only with PIL if possible.
So I solved the issue with a simple forward mapping, rather than inverse mapping, which is usually better, but in my application I only ever map the rectangle to a quad that is smaller than the rectangle, so there are usually no holes in the transformed image. The code is as follows:
def reverse_quad_transform(image, quad_to_map_to, alpha):
# forward mapping, for simplicity
result = Image.new("RGBA",image.size)
result_pixels = result.load()
width, height = result.size
for y in range(height):
for x in range(width):
result_pixels[x,y] = (0,0,0,0)
p1 = (quad_to_map_to[0],quad_to_map_to[1])
p2 = (quad_to_map_to[2],quad_to_map_to[3])
p3 = (quad_to_map_to[4],quad_to_map_to[5])
p4 = (quad_to_map_to[6],quad_to_map_to[7])
p1_p2_vec = (p2[0] - p1[0],p2[1] - p1[1])
p4_p3_vec = (p3[0] - p4[0],p3[1] - p4[1])
for y in range(height):
for x in range(width):
pixel = image.getpixel((x,y))
y_percentage = y / float(height)
x_percentage = x / float(width)
# interpolate vertically
pa = (p1[0] + p1_p2_vec[0] * y_percentage, p1[1] + p1_p2_vec[1] * y_percentage)
pb = (p4[0] + p4_p3_vec[0] * y_percentage, p4[1] + p4_p3_vec[1] * y_percentage)
pa_to_pb_vec = (pb[0] - pa[0],pb[1] - pa[1])
# interpolate horizontally
p = (pa[0] + pa_to_pb_vec[0] * x_percentage, pa[1] + pa_to_pb_vec[1] * x_percentage)
try:
result_pixels[p[0],p[1]] = (pixel[0],pixel[1],pixel[2],min(int(alpha * 255),pixel[3]))
except Exception:
pass
return result
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]
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.