Am I doing this correctly?
For example, I have an RGB(165,165,165) and convert it to the HSL(Get (0, 0, 64.7)).
Actually I parse xml, and there I have two parameters lumMod = '60 000' and lumOff = '40 000' (As I know it means that I must multiply the L component by 0.6 and then add 0.4 to the L component)
Okey new_l = 0.647*0.6 + 0.4 = 0.7882
And now I convert back from HSL(0, 0, 78.8) to RGB(198, 198, 198)
Actually I need get RGB(183,183,183). Because it's right answer. Where I was wrong?
After all night debugging I have been founded answer for my question.
Thanks to King Salemno from this topic
The algorithm the charts are performing, the following steps are
performed:
Obtain RGB of the base color they’re interested in (e.g. Accent 3)
Convert to HSL
Multiply the L component by lumMod
Add lumOff to the L component
Convert back to RGB
The same logic also applies to satMod, satOff, hueMod, & hueOff.
But for rgb-color, which have only one value for all levels (like as (255, 255, 255) or (123, 123, 123)) I change lumMod to lumMod = lumMod - 0.04(+-0.005) and do the same for lumoff parameter.
So if I have RGB(165,165,165) and convert it to the HSL(0, 0, 0.647).
After I change HSL.L = HSL.L*(lumMod - 0.04) + (lumOff - 0.04) = 0.718
And now I convert back from HSL(0, 0, 0.718) to RGB(183,183,183)
I don't know why it work like this, but it work. I tried to find out it.
Related
I have an image that I import into Octave 5.2, and I would like to create an outline all the way around the image array using RGB values.
I'm having trouble inserting the RGB values back into the array correctly, inserting / generating the two rows at top, two columns on the left, two columns on the right, and two rows on the bottom all the way around the image / converted double array.
Example of original image:
Example of the image I'm trying to get when done:
My logic was:
To convert the image to a double array so I can do math / insert the RGB values where I wanted them.
Insert the RGB values into the left, right, top, bottom of the array.
Convert the double array back to uint8 to export / view it as image.
My code so far:
pkg load image
img_fn=('https://i.imgur.com/KKxJaOy.png'); %original image
f=imread(img_fn);
[im_r im_c]=size(f);
size_min=min(im_r,im_c); %get minum size from row and col
f_double=double(f); %need to convert to double to do math functions on it
outline_left_of_box=repmat(255,[rows(f_double),2]); %Create left line array of outline red box
f_double_tmp_red(:,:,1)=[outline_left_of_box,f_double];%Create left line of outline red box
red_outline_right_of_box=repmat(255,[rows(f_double),2]); %Create right line array of outline red box
red_outline_top_of_box=repmat(255,[2,columns(f_double)]); %Create top line array of outline red box
red_outline_bottom_of_box=repmat(255,[2,columns(f_double)]); %Create bottom line array of outline red box
%convert back to image
red_outline_img=uint8(f_double);
imshow(red_outline_img); %used to show image in octave plot window
Please note: I'm converting the image array into a double because calculations will be done on the array to get the desired color box around the image, but I'm just trying to get the inserting RGB values into the array issue fixed first.
Maybe it's easier to simply paste the inner part of the input image onto some "background" image with the desired border color, like so:
pkg load image
% Read image, get dimensions, convert to double
f = imread('https://i.imgur.com/KKxJaOy.png');
[im_ro, im_co, im_ch] = size(f);
f_double = double(f);
% Set up width and color of border
bw = 2;
color = ones(1, 1, im_ch);
color(1, 1, :) = [255, 0, 0];
% Create image of same size as input with solid color, and paste inner part of input
red_outline_img = ones(im_ro, im_co, im_ch) .* color;
red_outline_img(bw+1:end-bw, bw+1:end-bw, :) = f_double(bw+1:end-bw, bw+1:end-bw, :);
red_outline_img = uint8(red_outline_img);
imshow(red_outline_img);
That'd be the output:
Another thing you could try is plot the lines as you suggest, which can be done very efficiently with some clever use of xlim/ylim, and then print the whole thing as an -RGBImage to get it back in image form.
The only caveat here though is that you will need to play with the formatting options to get what you're really after (e.g. in case you want higher or lower resolution), since you really are printing what's on your screen at this point.
E.g.
L = imread('leaf.png');
imshow(L)
hold on
plot( [xlim, fliplr(xlim);xlim, xlim], [ylim, ylim;fliplr(ylim), ylim], 'r', 'linewidth', 2 )
hold off
set( gca, 'position', [0, 0, 1, 1] );
set( gcf, 'paperposition', [0, 0, 1, 1] );
R = print( '-RGBImage' );
close
imshow(R); set( gcf, 'color', 'k'); axis off
In Matlab:
How do I modify plot(x,y,'o'), where x=1:10 and y=ones(1,10), such that each point in the plot will have a random shape?
And how can I give it colors chosen from a scheme where the value at x=1 is the darkest blue, and x=10 is red (namely some sort of heat map)?
Can this be done without using loops? Perhaps I should replace "plot" with a different function for this purpose (like "scatter"? I don't know...)? The reason is that I am plotting this inside another loop, which is already very long, so I am interested in keeping the running-time short.
Thanks!
First, the plain code:
x = 1:20;
nx = numel(x);
y = ones(1, nx);
% Color map
cm = [linspace(0, 1, nx).' zeros(nx, 1) linspace(1, 0, nx).'];
% Possible markers
m = 'o+*.xsd^vph<>';
nm = numel(m);
figure(1);
hold on;
for k = 1:nx
plot(x(k), y(k), ...
'MarkerSize', 12, ...
'Marker', m(ceil(nm * (rand()))), ...
'MarkerFaceColor', cm(k, :), ...
'MarkerEdgeColor', cm(k, :) ...
);
end
hold off;
And, the output:
Most of this can be found in the MATLAB help for the plot command, at the Specify Line Width, Marker Size, and Marker Color section. Colormaps are simply n x 3 matrices with RGB values ranging from 0 to 1. So, I interpreted the darkest blue as [0 0 1], whereas plain red is [1 0 0]. Now, you just need a linear "interpolation" between those two for n values. Shuffling the marker type is done by simple rand. (One could generate some rand vector with size n beforehand, of course.) I'm not totally sure, if one can put all of these in one single plot command, but I'm highly sceptical. Thus, using a loop was the easiest way right now.
I am trying to write a method which will work on WPF's Color struct to return a byte representing the Hue of the Color. I am struggling with the formula, I have written unit tests for the hues of Black (255, 255, 255), Red (255, 0, 0), Green (0, 255, 0), Blue (0, 0, 255), Yellow (255, 255, 0), Cyan (0, 255, 255), Magenta (255, 0, 255) and White (255, 255, 255) - they all pass except Yellow (which returns 1 instead of 42) and Magenta (which tries to return -1 instead of 212 but fails as -1 won't cast into a byte).
My extension methods for GetHue appear as follows:
public static byte GetHue(this Color color)
=> GetHue(color.ToRgbDictionary(), color.GetMinComponent(), color.GetMaxComponent());
private static byte GetHue(Dictionary<ColorComponent, byte> rgbDictionary, ColorComponent minimumRgbComponent, ColorComponent maximumRgbComponent)
{
decimal chroma = rgbDictionary[maximumRgbComponent] - rgbDictionary[minimumRgbComponent];
return (byte)
(
chroma == 0
? 0
: thirdOfByte
* (byte)maximumRgbComponent
+
(
rgbDictionary[MathHelper.Wrap(maximumRgbComponent + 1)]
- rgbDictionary[MathHelper.Wrap(maximumRgbComponent - 1)]
)
/ chroma
);
}
ToRgbDictionary simply turns the Color into a dictionary of its red, green and blue components; ColorComponent is an enum used as the key for those components. MathHelper.Wrap is a method which wraps an enum back into its declared range if it overflows or underflows. GetMinComponent and GetMaxComponent are two other extension methods on Color which return the first lowest and first highest ColorComponents of the Color (where the ColorComponent order is: Red, Green, Blue). thirdOfByte is a constant equal to the byte.MaxValue / 3.
I have based this formula on another I found here (http://www.blackwasp.co.uk/rgbhsl_2.aspx) which looks like this:
private decimal GetH(RGB rgb, decimal max, decimal chroma)
{
decimal h;
if (rgb.R == max)
h = ((rgb.G - rgb.B) / chroma);
else if (rgb.G == max)
h = ((rgb.B - rgb.R) / chroma) + 2M;
else
h = ((rgb.R - rgb.G) / chroma) + 4M;
return 60M * ((h + 6M) % 6M);
}
The problem with that formula is it's mapped to a 0 - 360 hue range, not a 0 - 255 range which is what I need. I'm not sure what the constant numbers in this formula do but I'm guessing the 60 has something to do with 360 / 3 = 120 hence my third of byte constant to try to do something similar. As for the 6Ms I have no idea where they come from nor why they are added to and modulused with the hue value at that stage. Could anyone with a mind for maths help me out here?
UPDATE
The reason for the 0 - 255 range was that I thought that was all that was required having seen it used in another piece of software (as shown) for Hue, Saturation and Lightness. It is also where I obtained the 42 Hue value for Yellow. I am now trying to find the correct range for Hues to cover all possible different hues in a 16777216 (256 * 256 * 256) colour range.
Your "...except Yellow (which returns 1 instead of 42)" what's the logic behind expecting a 42?
It's "mapped to a 0 - 360 hue range" because there are 360 hues in the colour wheel. Even if you had an unsigned byte (holding 256 values), you'd be cropping off the other 104 possible hues. It won't be an accurate representation.
Why not just use a 2-byte short to hold the possible 360 hues instead of using 1 byte?
If you still want to fit 360 inside a 255 range, just do simple math :
byte_value = hue_value / (360/255); //where hue_value is the 0-360 amount.
Try involving Math methods like Math.round to get none fractions as final byte value.
Example 180 hue :
byte_value = Math.round( 180 / (360/255) ); //gives 127
Ok, so what I want to do is go through an entire array of pixels, and for each pixel grab the green value, blue value and red value. This is so later I can see patterns between them.
So, this is what my code looks like.
for frame in camera.capture_continuous(rawCapture, format='bgr', use_video_port =True):
data=frame.array
rawCapture.truncate(0)
ColourCount = Calculations(data)
Ok, now that was just to show you what the general code is. This is where it gets tricky. Also, if that doesn't work for you guys on Pc, just use any opencv, I'm sure they save the data the same.
Calculations(data):
for n in data:
for s in n
B=s[0]
G=s[1]
R=s[2]
Then when I print these, it doesn't yield the result I want.
So s is like [0, 14, 0]
And B is like [0, 0, 0] as is the others. (those are just examples, although the values aren't getting high for some reason.
Now what I would like, is to split it so B is the blue channel, G is the green channel, etc.
So for the N example:
B= 0
G= 14
R = 0
So how do I achieve this?
I want single integers, but it's sending me back an entire pixel nearly?
EDIT: I believe part of my mistake before was that the item I was collecting was in fact a row instead of a pixel. So I put another for loop in, as seen above.
You can use the split() function.
Calculations(data):
bgr = cv2.split(data)
B = bgr[0]
G = bgr[1]
R = bgr[2]
I have a 3D viewport that uses the TrackBall of WPF 3D tool to rotate the object by mouse. As a result, I get a single AxisAngleRotation3D with Axis vector like (0.5, 0.2, 0.6) and Angle of e.g. 35. That's fine.
What I would like to do is, as an alternative, to give user the ability to rotate the object by individual axis (i.e. x, y, z). So, if the object is rotated around the axis of (0.5, 0.2, 0.6) by 35 degree, how can I convert this into three rotations around each axis, ie. Xangle for vector (1, 0, 0), Yangle for vector (0, 1, 0), and Zangle for vector (0, 0, 1).
I also need a way to convert them back to a single AxisAngleRotation3D object.
EDIT:
I found some stuff at http://www.gamedev.net/reference/articles/article1095.asp. One thing I learnt is that I can easily get a (combined) quaternion from separete AxisAngleRotation3D. For example,
private AxisAngleRotation3D _axisX = new AxisAngleRotation3D();
private AxisAngleRotation3D _axisY = new AxisAngleRotation3D();
private AxisAngleRotation3D _axisZ = new AxisAngleRotation3D();
...
_axisX.Axis = new Vector3D(1, 0, 0);
_axisY.Axis = new Vector3D(0, 1, 0);
_axisZ.Axis = new Vector3D(0, 0, 1);
...
Quaternion qx = new Quaternion(_axisX.Axis, _axisX.Angle);
Quaternion qy = new Quaternion(_axisY.Axis, _axisY.Angle);
Quaternion qz = new Quaternion(_axisZ.Axis, _axisZ.Angle);
Quaternion q = qx * qy * qz;
This is fine. Now, the problem is how can I do the reverse? So, for a given q, how can I find out qx, qy, qz?
You can convert it to a matrix and then back to three separate rotations representation. You can find formulas for both conversions on the net. You can also optimize it by writing it down and solving the equations on paper resulting in possibly faster formula.
However, I suggest to never represent rotation in three numbers, that's due to singularities resulting from this implementation and numeric instability. Use quaternions instead.
cuanternion to Euler angles