Matlab overlaying color on an image - matlab

I have a grascale image where I want to overlay different colors to different areas that have similar properties (say direction or intensity etc.) I am not referring to a heat map. Rather I have hard coded segmentation code where I have grouped pixels together by their "similarities". Now I want to over lay colors to those pixels.
For example, for a 3x3 pixel pic, say I know that the top row and bottom row are similar group. And the middle row is another group. How can I overlay a red hue with one group and a blue hue with another?

You could make your 3x3x1 grayscale image into a 3x3x3 color image, and then adjust the hue values for the pixels you want.
So say:
GreyImg=[0.2, 0.3, 0.35;...
0.5, 0.6, 0.56;...
0.8, 0.8, 0.85];
%Convert To Color Img
ColorImg(:,:,1)=GreyImg;
ColorImg(:,:,2)=GreyImg;
ColorImg(:,:,3)=GreyImg;
%Add a red hew to top row:
ColorImg(1:1,:,1)=ColorImg(1:1,:,1)+[.2, .2, .2];
%Add a blew hew to top row:
ColorImg(3:3,:,3)=ColorImg(3:3,:,3)+[.2, .2, .2];
imshow(ColorImg);

Related

Altair: How to make scatter plot aligned with image background created by mark_image?

I'm looking for a working example to have a .png picture as the background of a scatter chart.
Currently, I use mark_image to draw the background image:
source = pd.DataFrame.from_records([
{"x": 0, "y": 0,
"img": "http://localhost:8888/files/BARTStreamlit/assets/BARTtracksmap.png?_xsrf=2%7Ce13c35be%7Ce013c83479b892363239e5b6a77d97dc%7C1652400559"}
])
tracksmap = alt.Chart(source).mark_image(
width=500,
height=500
).encode(
x='x',
y='y',
url='img'
)
tracksmap
Here is the resulted image drown:
and draw the scater chart,
chart = alt.Chart(maptable).mark_circle(size=60).encode(
x= 'x',
y= 'y',
tooltip=['short_name', 'ENTRY']
).interactive()
chart
I have scaled the x, y channel values for the scatter chart to be in the range of [0, 500]. 500 is the width and height of the background image that I guessed.
Here is the resulted scatter plot:
then I combined the two chart with layer mechanism:
geovizvega = alt.layer(tracksmap, chart)
geovizvega
resulting the following:
The two charts do not align. I'd like to have the scatter dots aligning with the tracks on the background image. How can I achieve that?
To have them aligned, I might need to have the background image's top left corner at the coordinates (0, 0), how can I achieve that? (It seems that the x, y channel values for mark_image is the coordinates of the center of the image? With accurate definition of the x, y channel values, it might be possible to calculate the proper value of x, and y for the top left coroner to be at (0, 0)).
I might need to to have precise dimension of the background image. How?
My above approach may not be the right one. Please show me a working example.
Yes, if you change the values of x and y in your image plot to something like y=-200 and x=200, the image should be more centered in the scatter plot.
You can also change the anchor point of the image using align and baseline:
import altair as alt
import pandas as pd
source = pd.DataFrame.from_records([
{"x": 2, "y": 2, "img": "https://vega.github.io/vega-datasets/data/7zip.png"}
])
imgs = alt.Chart(source).mark_image(
width=100,
height=100
).encode(
x='x',
y='y',
url='img'
)
imgs + imgs.mark_circle(size=200, color='red', opacity=1)
imgs = alt.Chart(source).mark_image(
width=100,
height=100,
align='right',
baseline='top'
).encode(
x='x',
y='y',
url='img'
)
imgs + imgs.mark_circle(size=200, color='red', opacity=1)
After this, you would still need to change the dimensions of the chart so that it has the same size as the image. The default is width=400 and height=300. You can get the dimensions of your image in most image editing software or using the file <imagename> command (at least on linux). But even after getting these dimensions, you would have to do some manual adjustments due to axes taking up some of that space in the chart.

Flutter- Draw points on image use canvas

I want to plot some (red color)points in the image, my image width and height assume (300 x 300) and I plot (red color) points in Offset(76.2, 75.2) position at image(1,1).
[1]: https://i.stack.imgur.com/mvGt0.jpg
In some cases I need to change the image to (450x 450), but already plot (red color)points are a mismatch.
How to move red color points to (1,1) position of image? how to calculate Offset value.
[2]: https://i.stack.imgur.com/Xua9h.jpg
You have to recalcuate the offsets for the new resolution.
Simply calculate a scale factor by which you can multiply the offsets and redraw the canvas. Pseudocode:
offset = (76.2, 75.2)
scale = 450/300 // 1.5
newOffset = offset * scale //(114.3, 112,5)

Getting the coordinates of vertices of an A4 sheet with coins on it, for its further projective transformation and coin detection

I need to transform my tilted image in a way I can find coins on an A4 paper. So far, I have been getting four coordinates of edges of my paper by manually selecting them with ginput.
targetImageData = imread('coin1.jpg');
imshow(targetImageData);
fprintf('Corner selection must be clockwise or anti-clockwise.\n');
[X,Y] = ginput(4);
Is there a way to automate this process, say, apply some edge detector and then find coordinates of each vertex and then pass them as the coordinates needed for transformation?
Manual selection:
Result:
You can try using detectHarrisFeatures on the S color channel of HSV color space:
I was looking for a color space that gets maximum contrast of the paper.
It looks like the saturation color channel of HSV makes a good contrast between the paper and the background.
Image is resized the image by a factor of 0.25, for removing noise.
detectHarrisFeatures finds the 4 corners of the paper, but it might not be robust enough.
You may need to find more features, and find the 4 correct features, using some logic.
Here is a code sample:
%Read input image
I = imread('im.png');
%Remove the margins, and replace them using padding (just because the image is a MATLAB figure)
I = padarray(I(11:end-10, 18:end-17, :), [10, 17], 'both', 'replicate');
HSV = rgb2hsv(I);
%H = HSV(:, :, 1);%figure;imshow(H);title('H');
S = HSV(:, :, 2);%figure;imshow(S);title('S');
%V = HSV(:, :, 3);%figure;imshow(V);title('V');
%Reduce image size by a factor of 0.25 in each axis
S = imresize(S, 0.25);
%S = imclose(S, ones(3)); %May be requiered
%Detect corners
corners = detectHarrisFeatures(S);
imshow(S); hold on;
plot(corners.selectStrongest(4));
Result:
Different approach you may try:
Take a photo without the coins.
Mark the corners manually, and extract features of the 4 corners.
Use image matching techniques to match the image with the coins with the image without the coins (mach basted on the 4 corners).

Finding dark purple pixels in an image

I am doing a research for my higher studies in automation. I have done the automation part of the microscope but I need help in MATLAB. An example of what I would like to segment is shown here:
I need to extract the dark purple pixels from this image and only display that in a figure. It is almost like colour based segmentation but I just want to only take the dark purple pixel from the whole image.
What would I do in this case?
Here's something to get you started. Let's go with the theme of colour segmentation where you only want to extract pixels that are of a deep purple. I would like to point you to the HSV colour space before we get started. The HSV colour space is ideal for representing colours in a way that is most intuitive to humans. We tend to describe colours by their dominant colour, followed by attributes such as how washed out or how pure the colour is, and how bright or dark the colour is. The dominant colour is represented by the Hue, the appearance of how washed out or how pure the colour is is represented by the Saturation and the intensity of the colour is represented by the Value, and hence Hue-Saturation-Value, or the HSV colour space.
We can transform a RGB image so that it becomes HSV by rgb2hsv. This will return a 3D matrix that has the hue, saturation and value as 2D slices in a 3D matrix, much like a RGB image where each slices represents the red, green and blue channels. Let's see what each component looks like once we transform the image into HSV:
im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
subplot(1,3,idx);
imshow(hsv(:,:,idx));
end
The first line of code reads in an image from a URL. I'm going to use the one that Hoki referred you to, as it's the most simplest one to deal with. For self-containment, this is what the original image looks like:
Once we do this, we convert the image into the HSV colour space. It is important that you convert the image to double precision and you normalize each component to [0,1], and that is performed by im2double. Next, we spawn a new figure, and place each component in a single row over three columns. The first column represents the hue, next column the saturation and finally the last column being the value. This is the figure that we see:
With the first figure, it looks like the dominant colour is purple, whether it's a light shade or a dark shade of the colour, so the hue won't help us here. If you look at a HSV colour wheel:
(source: hobbitsandhobos.com)
Normalize the wheel so that it falls between [0,1] instead of 0 to 360 degrees. The hue is actually represented as degrees due to the nature of the colour space, but MATLAB normalizes this to [0,1]. You can see that purple falls within a hue of [0.6,0.8], which corresponds to the first figure I showed you that displays the hue for our image. If you examine the pixels around the image, they fluctuate between this range. Therefore, the hue won't help us much here.
What will certainly help us are the saturation and value components. If you take a look, the deep purple pixels have a higher saturation than the rest of the background, which makes sense because the deep purple has a much more pure version of purple than the rest of the background. For the value, you can see that the brightness of the dark purple is darker than the background.
We can use these two points as an exploit to segment out the purple colour in the image. The easiest thing to do would be to threshold the saturation and value planes so that any values that are within a certain range you keep while those that are outside you throw away. Therefore, you can do something like this:
sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;
I used impixelinfo and I hovered my mouse over the saturation and value components to examine what the values were for the deep purple regions. It looks like those pixels that are deep purple have a saturation value between 0.6 and 0.9, while the value component has values between 0.4 and 0.65. The above code will create two binary masks where true means that the pixel satisfies our criteria while false means it doesn't. Because I want to combine both things together and not leave any stone unturned, let's logical OR the masks together for the final result:
figure;
result = sThresh | vThresh;
imshow(result);
We will also show the result too. This is what we get:
As you can see, this does a pretty good job, but we have remnants of the red arrow that we don't want in the final result. To do a bit of cleanup, we can use morphology - specifically an opening filter of a small window so that we don't affect the pixels that we want as much. We can use imopen to perform our opening operation for us. A morphological opening removes isolated pixels that appear around your image. You use what is called a structuring element that is used to look at local neighbourhoods of your image. For the basics, any pixel regions that are as small as the shape that is contained within the structuring element get removed. Because we want to preserve the shape of the other objects, we can try using a 5 x 5 disk structuring element to clean these pixels up:
figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);
This is what we get:
Not bad! There are some holes that we need to patch up, so let's fill in those holes with imfill:
figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);
This is what we get:
OK! So we have our mask. The last thing we need to do is present the image so that you only show the deep purple colours from the original image, and nothing else. That can easily be achieved with bsxfun:
figure;
out = bsxfun(#times, im, uint8(final_noholes));
imshow(out);
The above operation takes your mask, and multiplies every pixel in your image by this mask. One small thing I'd like to point out is that the mask we found in the previous step needs to be cast to uint8, because bsxfun requires that the multiplication (or whatever operation you perform) need to be the same type. We replicate this mask in 3D so that you mask out the unwanted RGB pixels and only keep the ones you are looking for.
This is what we finally get:
As you can see, it isn't perfect, but it's certainly enough to get you started. Those thresholds are what are important, but with some very simple thresholding, I extracted most of the purple pixels out.
To make it easier for you, here's the code that I wrote above that can easily be copied and pasted into MATLAB for you to run:
clear all; close all; clc;
im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
subplot(1,3,idx);
imshow(hsv(:,:,idx));
end
sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;
figure;
result = sThresh | vThresh;
imshow(result);
figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);
figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);
figure;
out = bsxfun(#times, im, uint8(final_noholes));
imshow(out);
Good luck!
Try this:
function main
clc,clear
A = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
subplot(1,2,1)
imshow(A)
RGB = [230 210 200]; % color you want
e = 40; % color shift
B = pix_in(A,RGB,e);
B = B + 255.*uint8(~B); % choosing white background
subplot(1,2,2)
imshow(B)
end
function B = pix_in(A,RGB,e)
% select specific pixels in image
% A - color image (3D matrix uint8)
% RGB - [R G B] - color to select
% e - color shift/deviation
A = double(A); % for same class operations (RGB - double)
[m, n, ~] = size(A);
RGB = reshape(RGB,1,1,3);
RGB = repmat(RGB,m,n,1); % creating 3D matrix
b = abs(A-RGB) < e; % logical 3D
b = sum(b,3) == 3; % if [R,G,B] of a pixel in range
B = A.*repmat(b,1,1,3); % selecting pixels those in range
B = uint8(B);
end

draw vertical lines at regular intervals in a rectangle in matlab

I need to draw vertical lines at regular intervals in a rectangular box. this is what i have used so far:
xmin=000;
xmax=70000;
ymin=0;
ymax=1000;
line1Val=900;
line2Val=600;
line3Val=300;
xlim([xmin xmax])
ylim([ymin ymax])
xl=get(gca,'XLim');
line(xl,[line1Val line1Val],'Color','y');
line(xl,[line2Val line2Val],'Color','y');
line(xl,[line3Val line3Val],'Color','y');
hold on ;
rectangle('Position',[120000,900,(280000-120000),37],'faceColor','k')
so the width of the rectangle is 160000 units i want to divide this into 4 , where the vertical line is of a different color(say red) and the height of the line is 37 units.
any ideas on how i can draw this without drawing 4 rectangles whose edges are red and are filled with black color.
You could use the parameters xstart,ystart,width and height for drawing your rectangle:
rectangle('Position',[xstart,ystart,width,height],'faceColor','k');
After that, you could determine the line positions in a loop and simply draw these lines:
for i = 1:3
x = xstart+i*width/4;
line([x x],[ystart ystart+height],'Color','r');
end
If you want a red line at the start and end of the rectangle, let i = 0:4.