I am very new to Python, and I am struggling with understanding how the following code works.
I have an image read into a numpy array. Similar to this:
# Read the image
image = mpimg.imread('images/rgb-road.png')
After this I set a 3-value boundary list rgb_boundary[123,231,122]. The values are irrelevant.
Then comes the confusing part.
boundary = (image[:,:,0] < rgb_boundary[0]) \
| (image[:,:,1] < rgb_threshold[1]) \
| (image[:,:,2] < rgb_threshold[2])
image[boundary] = [0,0,0]
It is the combination of my poor knowledge of Python syntax and working with images that is causing the issue.
I would be extremely happy if somebody could explain what is happening in the above piece of code. Especially in the line where we have the image[boundary] assignment. My image values are changed, but I don't understand how this is working in Python.
In addition, if there is a resource where I can read about how/why this is working, please feel free to refer me to it.
Thanks!
Let's start with the first piece that executes:
image[:,:,0] < rgb_boundary[0]
Now, rgb_boundary[0] is simply 123, so what this does is find the locations where the first color (red) in the image is less than 123 intensity (so about half-bright, since 255 is max-bright).
The result of the above expression will be a 2D boolean array, which is True wherever the red color byte is less than 123, and False elsewhere.
We can then understand this code:
boundary = (image[:,:,0] < rgb_boundary[0]) \
| (image[:,:,1] < rgb_boundary[1]) \
| (image[:,:,2] < rgb_boundary[2])
It is creating a 2D mask called boundary which will be True for any pixel where red is less than 123, or green is less than 231, or blue is less than 122. It will be False wherever none of those conditions are met.
Finally:
image[boundary] = [0,0,0]
This sets the selected pixels to black. In NumPy, a boolean mask like boundary can be used with "fancy indexing" to create a "view" of an array. In this case, the "view" is used to assign [0,0,0] (black) to image wherever the boundary condition is True.
Related
There seems to be a bug in the compiler of Pine Script, in this below example the use of a variable called transp sets a user definable input value for the transparency of a given colour.
Yet when using plotshape and bgcolor it has inconsistent results. bgcolour works as expected, plotshape however behaves very oddly. It sets the colour correctly for the plotted shape using style=shape.cross, but it fails to understand the colour instruction for the text = ‘hi’ or text = ‘lo’. In this case it uses the default colour of blue.
If you change transp to a set integer like transp = 80, it then works correctly and displays both the shape and text in the given colour. This is incredibly bogus, if it merely didn’t accept variables assigned to user inputs for transparency then it would affect both shape and text. You could also just enter the color.new expression straight into plotshape, and this works in the same way, use a variable for transparency that has a user input associated to it and it will not work correctly, use a hardcoded integer assignment and it works fine.
//#version=5
indicator(title='RSI and test colour variable', shorttitle='Colour test', overlay=false)
transp = input.int(60, minval=0, maxval=100, title='Transparency:')
blue = color.new(color.blue, 0)
green = color.new(color.green, transp)
red = color.new(color.red, transp)
white = color.new(color.white, 0)
lower = 30
higher = 60
Len = input(title='RSI Length:', defval=10)
Src = input(title='RSI Source:', defval=close)
rsi = ta.rsi(Src, Len)
plot(rsi, color=white)
plot(lower, color=blue)
plot(higher, color=blue)
plotshape (rsi > higher, location=location.top, color=green, style=shape.cross, text='Hi', size=size.tiny)
bgcolor (rsi > higher ? green : na)
plotshape (rsi < lower, location=location.top, color=red, style=shape.cross, text='Lo', size=size.tiny)
bgcolor (rsi < lower ? red : na)
I have looked over this and tried every conceivable permutation to the code to get around this, and it always responds in the same incoherent manner. It took sometime to actually realise what the issue was, this is clearly a bug, not overly fatal, but it’s not an ideal presentation, and I can’t move on with this bug looking at me, still bugging me. ;o\
Any work-arounds?
Although it might not be the reason, it does not necessarily need to be a user defined input. The value needs to be known at compile time.
If you try transp=close > 2 ? 40 : 80, you will get the same behavior.
Some more info.
As a workaround, use the textcolor parameter.
plotshape (rsi > higher, location=location.top, color=green, textcolor=green, style=shape.cross, text='Hi', size=size.tiny)
plotshape (rsi < lower, location=location.top, color=red, textcolor=red, style=shape.cross, text='Lo', size=size.tiny)
I'm trying to extract a mask with an "unknown" shape. I'm going to explain my self better:
My original data consists of a matrix with NaNs that, more or less, surround the true data. I have used a sobel operator to detect the edge:
#data is a matrix with Nan
mask = np.isnan(data)
data[mask] = 0
data[~mask] = 1
out = sobel(data) #sobel is a function that returns the gradient
In figure the output of sobel operation is reported. Since the original data has also NaNs among true data, sobel operator detect inner edges.
I want to try a method to detect only the outer edges (the figure that looks like a rhombus). Consider that not only this shape can vary (it can be a square or a rectangle), but also the position can change (i.e. can be decentered, or very small respect to the image dimension). The result that I would obtain should be a mask with all outer pixel set to True (or False), while all inner pixel set to False (or True).
Thanks!
A possible, partial, solution is using an opening operation, defined as an erosion followed by a dilation. I used the one provided by skimage:
from skimage.morphology import opening
#data has shape shape_1, shape_2
mask_data = np.ones((shape_1, shape_2), dtype=bool)
mask = np.isnan(data)
mask_data[_mask] = 0
mask_data = opening(mask_data).astype(bool)
Such method returns something that is similar to what I'm looking for. As the picture suggests, this actually leaves some black inner dots, but it is the best I found.
I am working in Processing and I would like to compare the color of 2 the pixels of 2 different images.
let's say we comparing the pixel in position 10
color c1= image1.pixels[10]; color c2= image2.pixels[10];
if(c1==c2) { //so something }
Firstly I was playing with brightnsess
if(brightness(c1)==brightness(c2))
Generally it was working but not exactly as I wanted as the pixels were a little bit similar but not exactly the same color.
if you want to compare colours you are probably better off comparing the three basic ones instead of the actual number that "color" is. Thus instead of
if(c1 == c2)
where you compare two large numbers like 13314249 you can go
if(red(c1) == red(c2) && green(c1) == green(c2) && blue(c1) == blue(c2))
where you compare numbers from 0 - 255, the possible values of red or green or blue you can get from a colour. As for the "little bit similar" colours, you can set a threshold and any difference below that threshold will be considered negligible thus the colours are the same. Something like this:
int threshold = 5
if(abs(red(c1) red(c2)) < threshold && abs(green(c1) - green(c2)) < threshold && abs(blue(c1) == blue(c2)) < threshold)
Remember, you have to take the absolute difference! This way, if you decrease the threshold only very similar colours are considered the same while is you increase it different colours can be considered the same. That threshold number depends on your likings!
This would also work with your brightness example...
int threshold = 5
if(abs(brightness(c1) - brightness(c2)) < threshold)
To extend on Petros's answer. Generally, when I am comparing image pixels, I normalize, so that the code will work with images that are not in standard range 0-255. It also is good when you are doing many operations on the images to keep in mind the range you are currently working with for scaling purposes.
MAX_PIXEL=255 //maybe range is different for some reason
MIN_PIXEL=0
pixel_difference = 10
threshold = pixel_difference/(MAX_PIXEL-MIN_PIXEL)
if ( abs( (brightness(c1)-brightness(c2))/(MAX_PIXEL-MIN_PIXEL))< threshold ) {
//then the pixels are similar.
}
Sometimes you can gain more ground by transforming to a difference color space.
And depending on your task at hand you can build a background model that can adapt over time or compare higher level global features such as histograms or local features such as Scale Invariant Feature Transform (SIFT), or Corners, Edges.
I have a hunch this has been done before but I am a total layman at this and don't know how to begin to ask the right question. So I will describe what I am trying to do...
I have an unknown ARGB color. I only know its absolute RGB value as displayed over two known opaque background colors, for example black 0x000000 and white 0xFFFFFF. So, to continue the example, if I know that the ARGB color is RGB 0x000080 equivalent when displayed over 0x000000 and I know that the same ARGB color is RGB 0x7F7FFF equivalent when displayed over 0xFFFFFF, is there a way to compute what the original ARGB color is?
Or is this even possible???
So, you know that putting (a,r,g,b) over (r1,g1,b1) gives you (R1,G1,B1) and that putting it over (r2,g2,b2) gives you (R2,G2,B2). In other words -- incidentally I'm going to work here in units where a ranges from 0 to 1 -- you know (1-a)r1+ar=R1, (1-a)r2+ar=R2, etc. Take those two and subtract: you get (1-a)(r1-r2)=R1-R2 and hence a=1-(R1-R2)/(r1-r2). Once you know a, you can work everything else out.
You should actually compute the values of a you get from doing that calculation on all three of {R,G,B} and average them or something, to reduce the effects of roundoff error. In fact I'd recommend that you take a = 1 - [(R1-R2)sign(r1-r2) + (G1-G2)sign(g1-g2) + (B1-B2)sign(b1-b2)] / (|r1-r2|+|g1-g2|+|b1-b2), which amounts to weighting the more reliable colours more highly.
Now you have, e.g., r = (R1-(1-a)r1)/a = (R2-(1-a)r2)/a. These two would be equal if you had infinite-precision values for a,r,g,b, but of course in practice they may differ slightly. Average them: r = [(R1+R2)-(1-a)(r1+r2)]/2a.
If your value of a happens to be very small then you'll get only rather unreliable information about r,g,b. (In the limit where a=0 you'll get no information at all, and there's obviously nothing you can do about that.) It's possible that you may get numbers outside the range 0..255, in which case I don't think you can do better than just clipping.
Here's how it works out for your particular example. (r1,g1,b1)=(0,0,0); (r2,g2,b2)=(255,255,255); (R1,G1,B1)=(0,0,128); (R2,G2,B2)=(127,127,255). So a = 1 - [127+127+127]/[255+255+255] = 128/255, which happens to be one of the 256 actually-possible values of a. (If it weren't, we should probably round it at this stage.)
Now r = (127-255*127/255)*255/256 = 0; likewise g = 0; and b = (383-255*127/255)*255/256 = 255.
So our ARGB colour was 80,00,00,FF.
Choosing black and white as the background colors is the best choice, both for ease of calculation and accuracy of result. With lots of abuse of notation....
a(RGB) + (1-a)0xFFFFFF = 0x7F7FFF
a(RGB) + (1-a)0x000000 = 0x000080
Subtracting the second from the first...
(1-a)0xFFFFFF = 0x7F7FFF-0x000080 = 0x7F7F7F
So
(1-a) = 0x7F/0xFF
a = (0xFF-0x7F)/0xFF = 0x80/0xFF
A = 0x80
and RGB = (a(RGB))/a = 0x000080/a = 0x0000FF
You can do something very similar with other choices of background color. The smaller a is and the closer the two background colors are the less accurately you will be able to determine the RGBA value. Consider the extreme cases where A=0 or where the two background colors are the same.
I have code that needs to render regions of my object differently depending on their location. I am trying to use a colour map to define these regions.
The problem is when I sample from my colour map, I get collisions. Ie, two regions with different colours in the colourmap get the same value returned from the sampler.
I've tried various formats of my colour map. I set the colours for each region to be "5" apart in each case;
Indexed colour
RGB, RGBA: region 1 will have RGB 5%,5%,5%. region 2 will have RGB 10%,10%,10% and so on.
HSV Greyscale: region 1 will have HSV 0,0,5%. region 2 will have HSV 0,0,10% and so on.
(Values selected in The Gimp)
The tex2D sampler returns a value [0..1].
[ I then intend to derive an int array index from region. Code to do with that is unrelated, so has been removed from the question ]
float region = tex2D(gColourmapSampler,In.UV).x;
Sampling the "5%" colour gave a "region" of 0.05098 in hlsl.
From this I assume the 5% represents 5/100*255, or 12.75, which is rounded to 13 when stored in the texture. (Reasoning: 0.05098 * 255 ~= 13)
By this logic, the 50% should be stored as 127.5.
Sampled, I get 0.50196 which implies it was stored as 128.
the 70% should be stored as 178.5.
Sampled, I get 0.698039, which implies it was stored as 178.
What rounding is going on here?
(127.5 becomes 128, 178.5 becomes 178 ?!)
Edit: OK,
http://en.wikipedia.org/wiki/Bankers_rounding#Round_half_to_even
Apparently this is "banker's rounding". I have no idea why this is being used, but it solves my problem. Apparently, it's a Gimp issue.
I am using Shader Model 2 and FX Composer. This is my sampler declaration;
//Colour map
texture gColourmapTexture <
string ResourceName = "Globe_Colourmap_Regions_Greyscale.png";
string ResourceType = "2D";
>;
sampler2D gColourmapSampler : register(s1) = sampler_state {
Texture = <gColourmapTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Clamp;
AddressV = Clamp;
};
I never used HLSL, but I did use GLSL a while back (and I must admit it's terribly far in my head).
One issue I had with textures is that 0 is not the first pixel. 1 is not the second one. 0 is the edge of the texture and 1 is the right edge of the first pixel. The values get interpolated automatically and that can cause serious trouble if what you need is precision like when applying a lookup table rather than applying a normal texture. You need to aim for the middle of the pixel, so asking for [0.5,0.5], [1.5,0.5] rather than [0,0], [1, 0] and so on.
At least, that's the way it was in GLSL.
Beware: region in levels[region] is rounded down. When you see 5 % in your image editor, the actual value in the texture 8b representation is 5/100*255 = 12.75, which may be either 12 or 13. If it is 12, the rounding down will hit you. If you want rounding to nearest, you need to change this to levels[region+0.5].
Another similar thing (already written by Louis-Philippe) which might hit you is texture coordinates rounding rules. You always need to hit a spot in the texel so that you are not in between of two texels, otherwise the result is ill-defined (you may get any of two randomly) and some of your source texels may disapper while other duplicate. Those rules are different for bilinar and point sampling, you may need to add half of texel size when sampling to compensate for this.
GIMP uses banker's rounding. Apparently.
This threw out my code to derive region indicies.