How to interpolate a HSV color? - c

I am creating an application in win32 api, which will use a progress bar. This progress bar, should change its color. From red (left end) to green(right), and in the middle some yellow.
I searched a little, and found out, that I should use HSV to achieve this. I just don't know how? I found in this link, two functions, to convert the color, from RGB to HSV and back.
But what should I do if the color has been converted to HSV?

Like RGB coordinates, HSV coordinates define a point in a three dimensional space.
You may find a trajectory form one point (x0, one color) to the second (x1) with a formula like:
x = x0 + alpha * (x1-x0)
with alpha varying form 0.0 to 1.0
You can do this for all three components simultaneaously.
With a trajectory from green to red in HSV space you will mainly modify the H (Hue) value. If you want to see some yellow in the middle of your path (and not violett) you need to define a second or even third color and walk
green -> yellow -> red
Edit: Example
int hue0 = 0; // red
int hue2 = 120; // green
// find 100 colors between red and green
for(double alpha = 0; alpha <= 1.0; alpha += 0.01)
{
hueX = hue0 + alpha * (hue1 - hue0);
// same for value, saturation:
// valX = val0 + alpha * (val1 - val0)
// ...
// plot this color
}

Related

How to properly create outline around image using RGB values?

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

How to change colour of specific points in ggtern

I am using ggtern to graph some RGB data, where each point refers to the colour % from red, green or blue.
I was wondering if it is possible to change the colour of specific plot points to match the actual colour which they are representing?
I have tried using some ggplot2 commands but it doesn't work.
This is what I am using now:
library(ggplot2)
library(ggtern)
library(readxl)
Image9 <- read_excel("~/PhD/Image9.xlsx")
View(Image9)
ggtern(data=Image9, aes(x = Blue, y = Red, z= Green )) + geom_point( size=2,
shape=16, color="black") + theme_rgbw() + theme_hidegrid_major() +
theme_hidetitles()+ theme_rotate(degrees = 120) +
geom_text(aes(label=Colour), size=3, color="black", hjust=0, vjust=0)
Using this command I can plot the data as a colour intensity percentage in Red, Green and Blue and label the points so that I can map them back to the original image
1; representative image of plot.
Ideally I would like to plot each point as the same shade of color which they represent within the color space, I don't know if this is possible with this package.
Any suggestions would be greatly appreciated.

How to plot an NxN array of circles?

I want to plot an NxN array of circles. Just to visualize, I attached an image of what I want to achieve. I'm new in MatlLab so I tried to plot a single circle first, and here is the sample code below:
n = 2^10; % size of mask
M = zeros(n);
I = 1:n;
x = I - n/2; % mask x - coordinates
y = n/2 - I; % mask y - coordinates
[X,Y] = meshgrid(x,y); % create 2-D mask grid
R = 200; % aperture radius
A = (X.^2 + Y.^2 <= R^2); % Circular aperture of radius R
M(A) = 1; % set mask elements inside aperture to 1
imagesc(M) % plot mask
axis image
I really don't have any idea on how to plot a 2D-array of circles. The distance between two circles is two radii. I need this for my research. Hoping anyone can help.A 4 x 4 array of circles.
If you just want to plot a set of circles, you can use the rectangle function within a loop
If in the call to rectangleyou set the Curvature property to 1 it will be drawn as circle (ref. to the documentation).
In the loop you hav to properly set the position of each rectangle (circle) by defining its lower left coordinates along with its width and height.
Having defined with n the number of circles and with d their diameter, you can compute the set of lower left coordinates as:
px=linspace(0,d*(nc-1),nc)
py=linspace(0,d*(nr-1),nr)
The black background can be either obtained by setting the color of the axes or by plotting another rectangle.
Then you can set the xlim and ylim to fit with the external rectangle.
You can also make the axex invisible, by setting its â—‹Visibleproperty tooff`.
Edit #1
Code updated to allow drawing a user-defined number of circles (set the number of rows and the number of columns)
% Define the number of circles
% Number of rows
nr=8
% NUmber of column
nc=8
% Define the diameter of the circle
d=6
% Create an axex and set hold to on
ax=axes
hold on
% Evalaute the lower left position of each circle
px=linspace(0,d*(nc-1),nc)
py=linspace(0,d*(nr-1),nr)
% Plot the background rectangle
rectangle('Position',[px(1),py(1),d*nc,d*nr],'Curvature',[0 0],'facecolor','k')
% Plot all the circles
for i=1:length(px)
for j=1:length(py)
rectangle('Position',[px(i) py(j) d d],'Curvature',1,'facecolor','w')
end
end
% Set the aspect ratio of the axes
daspect([1 1 1])
% Set the XLim and YLim
xlim([px(1) d*nc])
ylim([py(1) d*nr])
% Make the axes invisible
ax.Visible='off'
Edit #2
Aternative solution to address the OP comment:
If I want to make the axes fixed, say I want a meshgrid of 1024 by 1024, (the image size is independent of the circle radius) how do I incorporate it in the code?
If you want to use a fixed (1024 x 1024) mask on which to plot the circles, starting from the cde you've posted in the question, you can simply do the following:
define the number of circles you want to plot, on a (1024 x 1024) mask they can be 2, 4, 8, ...
define a basic mask holding just one circle
identify the points inside that circle and set them to 1
Replicate (using the function repmat the basic mask accoding to the numner of circles to be plotted
The implemntation, based on your code could be:
% Define the number of circles to be plotted
% on a (1024 x 1024) mask they can be 2, 4, 8, ...
n_circles=4
% Define the size of the basic mask
n0 = (2^10)/n_circles;
% Initialize the basic mask
M0 = zeros(n0);
% Define the x and y coordinates of the basic mask
I = 1:n0;
x = I - n0/2;
y = n0/2 - I;
% Create the mask
[X,Y] = meshgrid(x,y);
% Define the radius of the basic circle
R = n0/2;
% Get the indices of the points insiede the basic circle
A = (X.^2 + Y.^2 <= R^2);
% Set basic mask
M0(A) = 1;
% Open a FIgure
figure
% Replicate the basic mask accoding to the numner of circles to be plotted
M=repmat(M0,n_circles,n_circles);
% Display the mask
imagesc(M)
% Set the axes aspect ratio
daspect([1 1 1])

Formula to determine transparancy

Say you want to put pixel with a color (R0 G200 B255) in a BMP picture and you have transp option in percents.
How do I determine the new pixel color, considering the transp and the background color?
I actually could figure out a formula that looks promising:
newpixel = newpixel + (bgpixel * transp) / %(transp of 255)
I created it by analyzing the pixel color change in GIMP. Not sure if that is the correct formula. I think it is also rounded up.
The standard formula is pixel = new_pixel * alpha + pixel * (1 - alpha), where alpha is a number between 0 and 1 that describes the opacity of the new (foreground) pixel.
You'll note that if the new pixel is fully transparent (alpha = 0) the pixel is unchanged and that if the new pixel is fully opaque (alpha = 1) the new pixel replaces the old one.
This formula must be applied separately for each pixel components (red, green and blue).
the code needs to change to 24 bit pixels.
where the 4th byte is the transparency factor.
The actual color values do not change

relation between light intensity and R,G,B

I have a one ambient light with intesity ( 10000,10000, 5000 ). I am trying to color the primitive.
As you know, color values for R,G, and B are between 0 and 255. How can I find color of the pixel according to light intesity ?
platform : linux and programming language c
EDIT :
In ray tracer, we are calculating
for each ambient light in the environment
color . R += Intensity of the light * ambient coefficient for color R
color . G += Intensity of the light * ambient coefficient for color G
color . B += Intensity of the light * ambient coefficient for color B
However, whenever I have tried to emit this pixel color value on the screen with openGL.
set pixel color ( color )
I have taken wrong color because of intensity is high and maximum color value is low.
The question is unclear, as written, so here's some general advice.
Colours in renderers are typically held as values with a nominal range of [0..1] for each of the RGB components.
When those colours are rendered to pixels, they're usually just multiplied by 255 to give a 24-bit colour value (8 bits per component).
If the original values are outside of the [0..1] range they must be "clamped" so that the resulting pixel values fall in the [0..255] range.
That clamping can either be done "per component", which in your case would result in (255, 255, 255), or each component could be divided by the maximum component, giving (255, 255, 127) - i.e. preserving their relative intensities in pseudo-code:
float scale = max(r, g, b);
if (scale < 1) {
scale = 1; // don't normalise colours that are "in range"
}
byte R = 255 * (r < 0 ? 0 : r / scale);
byte G = 255 * (g < 0 ? 0 : g / scale);
byte B = 255 * (b < 0 ? 0 : b / scale);
It's usual for all intermediate calculations to preserve the full dynamic range of intensities. For example, it wouldn't make sense for the Sun to have a brightness of "1", since every other object in the scene would by comparison have an almost infinitesimally small value.
The net result of the clamping will therefore be that light sources which contribute too much light to the scene will produce "saturation" of the image - i.e. the same effect that you get if you leave the shutter open too long on a picture of a bright scene.
It's this one you want:
brightness = sqrt( .241*R*R + .691*G*G + .068*B*B )
Find more here: http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
or here: http://en.wikipedia.org/wiki/Luminance_(relative)

Resources