How to find a brightest point an image and mark it in Matlab? [duplicate] - matlab

This question already has an answer here:
How to find and highlight the brightest region an image in Matlab?
(1 answer)
Closed 1 year ago.
Dears,
I would like to ask you for help with the code. My goal is to find the brightest point an image and mark it.
I used the following code to get the Image in Grey Values -> How to find and highlight the brightest region an image in Matlab? and tried to extend it based on my intention.
Then I found the max value of the matrix and go with the for loop function to highlight the coordinates of the max points. Unfortunately, here I have started struggle.
rgbImage = imread( 'Zoom1_WhiteImage.png' );
%imshow(rgbImage);
[rows, columns, numberOfColorChannels] = size(rgbImage)
if numberOfColorChannels == 1
brightness = rgbImage; % For a 1 channel image, brightness is the same as the original pixel value.
else
% For an RGB image, the brightness can be estimated in various ways, here's one standard formula:
brightness = (0.2126*rgbImage(:, :, 1) + 0.7152*rgbImage(:, :, 2) + 0.0722*rgbImage(:, :, 3));
end
% Establish a brightness threshold - pixels brighter than this value will
% be highlighted
threshold = 105;
% Create a zero-filled mask of equal size to the image to hold the
% information of which pixels met the brightness criterion:
mask = zeros(rows, columns, 'logical');
% Assign "1" to any mask pixels whose corresponding image pixel met the
% brightness criterion:
mask(brightness > threshold) = 1;
[a,b] = size(brightness)
maxgrey = max(max(brightness));
aux=0;
for i=1:1:a;
for j=1:1:b;
if brightness(a,b)>brightness(a,b+1)
aux=brightness(a,b+1)
else aux
end
end
end
Could you help me to finish the code, please?

You can achieve your goal with the function find() or with the function ind2sub():
% Random 2D matrix
I = rand(10);
% First option with find
[x,y] = find(I == max(I(:)))
% Second option using ind2sub, a bit more efficient since we only read I once.
[~,ind] = max(I(:))
[x,y] = ind2sub(size(I),ind)

Related

How to draw a line between two coordinates of an image permanently in Matlab? [duplicate]

This question already has answers here:
MATLAB: Drawing a line over a black and white image
(5 answers)
Closed 4 years ago.
I have a set of points that I want to connect sequentially. Suppose the points are (A1,A2,A3,...A9); I want to connect A1 to A2, A2 to A3 and so on and finally connect A9 to A1.
All I need is to know a function that would help me connect A1 to A2, I could do the rest using for loops.
I know connecting two points is a question that has been asked here several times before but I couldn't find the answer I required. Several of the solutions suggest using "plot" and "line" but these functions overlay the results on the image and don't actually make any changes to the original image.
I did try them out and managed to save the resulting figure using the "saveas" and "print" functions but the image doesn't get saved in the proper format and there are a lot of problems using the parameters for these functions. Besides, I don't really want to save the image, it's just an unnecessary overhead I was willing to add if I could get the desired image with the lines.
I've also tried "imline" to draw lines but it seems to be interactive.
This particular question reflects my problem perfectly but when I ran the code snippets given as solutions, all of them gave a set of dots in the resulting image.
I tried the above mentioned codes in the link with this image that I found here.
A dotted line was an output for all three code snippets in the link above.
For example, I ran the first code like this:
I = imread('berries_copy.png');
grayImage=rgb2gray(I);
img =false(size(grayImage,1), size(grayImage,2));
I wrote the above piece of code just to get a black image for the following operations:
x = [500 470]; % x coordinates
y = [300 310]; % y coordinates
nPoints = max(abs(diff(x)), abs(diff(y)))+1; % Number of points in line
rIndex = round(linspace(y(1), y(2), nPoints)); % Row indices
cIndex = round(linspace(x(1), x(2), nPoints)); % Column indices
index = sub2ind(size(img), rIndex, cIndex); % Linear indices
img(index) = 255; % Set the line points to white
imshow(img); % Display the image
This is the resulting image for the above code as well as the other two, which as you can see, is just a few points on a black background which isn't the desired output.
I changed the code and used the "plot" function for the same to get this output which is what I want. Is there anyway I can change the dotted output into a solid line?
Or if could anyone suggest a simple function or a method that would draw a line from A1 to A2 and would actually make a change in the input image, I'd be grateful. (I really hope this is just me being a novice rather than Matlab not having a simple function to draw a line in an image.)
P.S. I don't have the Computer Vision toolbox and if possible, I'd like to find a solution that doesn't involve it.
Your first problem is that you are creating a blank image the same size as the image you load with this line:
img =false(size(grayImage,1), size(grayImage,2));
When you add the line to it, you get a black image with a white line on it, as expected.
Your second problem is that you are trying to apply a solution for grayscale intensity images to an RGB (Truecolor) image, which requires you to modify the data at the given indices for all three color planes (red, green, and blue). Here's how you can modify the grayscale solution from my other answer:
img = imread('berries_copy.png'); % Load image
[R, C, D] = size(img); % Get dimension sizes, D should be 3
x = [500 470]; % x coordinates
y = [300 310]; % y coordinates
nPoints = max(abs(diff(x)), abs(diff(y)))+1; % Number of points in line
rIndex = round(linspace(y(1), y(2), nPoints)); % Row indices
cIndex = round(linspace(x(1), x(2), nPoints)); % Column indices
index = sub2ind([R C], rIndex, cIndex); % Linear indices
img(index) = 255; % Modify red plane
img(index+R*C) = 255; % Modify green plane
img(index+2*R*C) = 255; % Modify blue plane
imshow(img); % Display image
imwrite(img, 'berries_line.png'); % Save image, if desired
And the resulting image (note the white line above the berry in the bottom right corner):
You can use the Bresenham Algorithm. Of course it has been implemented and you can find it here: Bresenham optimized for Matlab. This algorithm selects the pixels approximating a line.
A simple example, using your variable name could be:
I = rgb2gray(imread('peppers.png'));
A1 = [1 1];
A2 = [40 40];
[x y] = bresenham(A1(1),A1(2),A2(1),A2(2));
ind = sub2ind(size(I),x,y);
I(ind) = 255;
imshow(I)
You can use imshow to display a image and then use plot to plot lines and save the figure. Check the below code:
I = imread('peppers.png') ;
imshow(I)
hold on
[m,n,p] = size(I) ;
%% Get random points A1, A2,..A10
N = 9 ;
x = (n-1)*rand(1,N)+1 ;
y = (m-1)*rand(1,N)+1 ;
P = [x; y]; % coordinates / points
c = mean(P,2); % mean/ central point
d = P-c ; % vectors connecting the central point and the given points
th = atan2(d(2,:),d(1,:)); % angle above x axis
[th, idx] = sort(th); % sorting the angles
P = P(:,idx); % sorting the given points
P = [P P(:,1)]; % add the first at the end to close the polygon
plot( P(1,:), P(2,:), 'k');
saveas(gcf,'image.png')

Contrast Stretching for colore images with MATLAB

i'm working in matlab and i wanted to apply the Contrast Stretching for grey scale image and also RGB image ,
so for the grey scale i've tried this one and it worked
clear all;
clc;
itemp = imread('cameraman.tif'); %read the image
i = itemp(:,:,1);
rtemp = min(i); % find the min. value of pixels in all the
columns (row vector)
rmin = min(rtemp); % find the min. value of pixel in the image
rtemp = max(i); % find the max. value of pixels in all the
columns (row vector)
rmax = max(rtemp); % find the max. value of pixel in the image
m = 255/(rmax - rmin); % find the slope of line joining point
(0,255) to (rmin,rmax)
c = 255 - m*rmax; % find the intercept of the straight line
with the axis
i_new = m*i + c; % transform the image according to new slope
figure,imshow(i); % display original image
figure,imshow(i_new); % display transformed image
this is for greyscale image ,
the problem is that that i don't know how to do for the RGB image
any idea? how to implement that?
thank you :)
Could the function stretchlim (reference) be useful for your purpose?
Find limits to contrast stretch image.
Low_High = stretchlim(RGB,Tol) returns Low_High, a two-element vector
of pixel values that specify lower and upper limits that can be used
for contrast stretching truecolor image RGB.
img = imread('myimg.png');
lohi = stretchlim(img,[0.2 0.8]);
If you write
rmin = min(i(:));
Then it computes the minimum over all values in i. This will work for RGB images also, which simply are 3D matrices with 3 values along the 3rd dimension.
The rest of your code also applies directly to such images.

Count circle objects in an image using matlab

How to count circle objects in a bright image using MATLAB?
The input image is:
imfindcircles function can't find any circle in this image.
Based on well known image processing techniques, you can write your own processing tool:
img = imread('Mlj6r.jpg'); % read the image
imgGray = rgb2gray(img); % convert to grayscale
sigma = 1;
imgGray = imgaussfilt(imgGray, sigma); % filter the image (we will take derivatives, which are sensitive to noise)
imshow(imgGray) % show the image
[gx, gy] = gradient(double(imgGray)); % take the first derivative
[gxx, gxy] = gradient(gx); % take the second derivatives
[gxy, gyy] = gradient(gy); % take the second derivatives
k = 0.04; %0.04-0.15 (see wikipedia)
blob = (gxx.*gyy - gxy.*gxy - k*(gxx + gyy).^2); % Harris corner detector (high second derivatives in two perpendicular directions)
blob = blob .* (gxx < 0 & gyy < 0); % select the top of the corner (i.e. positive second derivative)
figure
imshow(blob) % show the blobs
blobThresshold = 1;
circles = imregionalmax(blob) & blob > blobThresshold; % find local maxima and apply a thresshold
figure
imshow(imgGray) % show the original image
hold on
[X, Y] = find(circles); % find the position of the circles
plot(Y, X, 'w.'); % plot the circle positions on top of the original figure
nCircles = length(X)
This code counts 2710 circles, which is probably a slight (but not so bad) overestimation.
The following figure shows the original image with the circle positions indicated as white dots. Some wrong detections are made at the border of the object. You can try to make some adjustments to the constants sigma, k and blobThresshold to obtain better results. In particular, higher k may be beneficial. See wikipedia, for more information about the Harris corner detector.

Accurately detect color regions in an image using K-means clustering

I'm using K-means clustering in color-based image segmentation. I have a 2D image which has 3 colors, black, white, and green. Here is the image,
I want K-means to produce 3 clusters, one represents the green color region, the second one represents the white region, and the last one represents the black region.
Here is the code I used,
%Clustering color regions in an image.
%Step 1: read the image using imread, and show it using imshow.
img = (imread('img.jpg'));
figure, imshow(img), title('X axis rock cut'); %figure is for creating a figure window.
text(size(img,2),size(img,1)+15,...
'Unconventional shale x axis cut', ...
'FontSize',7,'HorizontalAlignment','right');
%Step 2: Convert Image from RGB Color Space to L*a*b* Color Space
conversionform = makecform('srgb2lab'); %the form of the conversion is defined as from rgb to l a b
lab_img = applycform(img,conversionform); %converting the rgb image to l a b image using the conversion form defined above.
%Step 3: Classify the Colors in 'a*b*' Space Using K-Means Clustering
ab = double(lab_img(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
%Step 4: Label Every Pixel in the Image Using the Results from KMEANS
%For every object in your input, kmeans returns an index corresponding to a cluster. The cluster_center output from kmeans will be used later in the example. Label every pixel in the image with its cluster_index.
pixel_labels = reshape(cluster_idx,nrows,ncols);
figure, imshow(pixel_labels,[]), title('image labeled by cluster index');
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = img;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
figure, imshow(segmented_images{1}), title('objects in cluster 1');
figure, imshow(segmented_images{2}), title('objects in cluster 2');
figure, imshow(segmented_images{3}), title('objects in cluster 3');
But I'm not getting the results as required. I get one cluster with green regions, one cluster with green region boundaries, and one with gray, black, and white colors. Here are the resulting clusters.
The aim of doing this is that after getting the correct clustering results, I want to count the number of pixels in every region using the concept of connected components.
So, my aim is to know how many pixels there are in every color region. I tried another simpler way by getting the matrix of the 2D image and trying to figure out the number of pixels for every color. However, I found more than 3 RGB colors in the matrix, maybe because pixels of the same color have a slightly different color levels. That's why I went to image segmentation.
Can anyone please tell me how to fix the code above in order to get the required results?
I would also appreciate it if you give me hints on how to do this in an easier way, if there is any.
EDIT: Here is a code I made to iterate over every pixel in the image. Please notice I use 4 colors red, yellow, blue, and white instead of green, white, and black, but the idea is the same. rgb2name is the function that returns the color name given RGB color.
im= imread ('img.jpg');
[a b c] = size (im);
%disp ([a b]);
yellow=0;
blue=0;
white=0;
red=0;
for i=1:a
for j=1:b
x= impixel(im, i, j)/255 ;
color= rgb2name (x);
if (~isempty (strfind (color, 'yellow')))
yellow= yellow+1;
elseif (~isempty (strfind(color, 'red')))
red= red+1;
elseif (~isempty (strfind (color, 'blue')))
blue= blue+1;
elseif (~isempty (strfind (color, 'white')))
white= white+1;
else
%disp ('warning'); break;
end
disp (color);
disp (i);
end
end
disp (yellow)
disp (red)
disp (blue)
disp (white)
Thank You.
I thought this problem was very interesting, so I apologize ahead of time if the answer is a little overboard. In short, k-means is the right strategy, in general, for problems where you want to segment an image into a discrete color space. But, your example image, which contains primarily only three colors, each of which is well separated in color space, is easily segmented using only a histogram. See below for segmenting using thresholds.
You can easily get the pixel counts by summing each matrix. e.g., bCount = sum(blackPixels(:))
filename = '379NJ.png';
x = imread(filename);
x = double(x); % cast to floating point
x = x/max(max(max(x))); % normalize
% take histogram of green dimension
g = x(:, :, 2);
c = hist(g(:), 2^8);
% smooth the hist count
c = [zeros(1, 10), c, zeros(1, 10)];
N = 4;
for i = N+1:length(c) - N;
d(i - N) = mean(c(i -N:i));
end
d = circshift(d, [1, N/2]);
% as seen in histogram, the three colors fall nicely into 3 peaks
figure, plot(c, '.-');
[~, clusterCenters] = findpeaks(d, 'MinPeakHeight', 1e3);
% set the threshold halfway between peaks
boundaries = [floor((clusterCenters(2) - clusterCenters(1))/2), ...
clusterCenters(2) + floor((clusterCenters(3) - clusterCenters(2))/2)];
thresh1 = boundaries(1)*ones(size(g))/255;
thresh2 = boundaries(2)*ones(size(g))/255;
% categorize based on threshold
blackPixels = g < thresh1;
greenPixels = g >= thresh1 & g < thresh2;
whitePixels = g >= thresh2;
This is my approach to count the number of pixels in every region. Given that (as discussed in the comments):
the value (RGB) and the number (K) of colors are known a priori
compression artifacts and anti-aliasing generated additional colors, that must be considered as the nearest-neighbor among the K know colors.
Since you know a priori the colors, you don't need k-means. It could actually lead to bad results as in your question. The approach of #crowdedComputeeer take care of this aspect.
You can compute nearest neighbor with pdist2 directly on the pixel values. There's no need to use the really slow function that looks for the color name.
Here is the code. You can change the number and values of colors simply modifying the variable colors. This will compute the number of pixels in each color, and output the masks.
img = (imread('path_to_image'));
colors = [ 0 0 0; % black
0 1 0; % green
1 1 1]; % white
% % You can change the colors
% colors = [ 0 0 1; % red
% 1 1 0; % yellow
% 1 0 0; % blue
% 1 1 1]; % white
% Find nearest neighbour color
list = double(reshape(img, [], 3)) / 255;
[~, IDX] = pdist2(colors, list, 'euclidean', 'Smallest', 1);
% IDX contains the indices to the nearest element
N = zeros(size(colors, 1), 1);
for i = 1 : size(colors, 1)
% Count the number of pixels for each color
N(i) = sum( IDX == i );
end
% This will display the number of pixels for each color
disp(N);
% Eventually build the masks
indices = reshape(IDX, [size(img,1), size(img,2)]);
figure();
szc = size(colors,1);
for i = 1 : szc
subplot(1,szc,i);
imagesc(indices == i);
end
Resulting counts:
97554 % black
16894 % green
31852 % white
Resulting masks:
Maybe this project could help, please take a try.

Colour Segmentation by l*a*b

I'm using the code on the MatLab website, "Color-Based Segmentation Using the Lab* Color Space":
http://www.mathworks.com/help/images/examples/color-based-segmentation-using-the-l-a-b-color-space.html
So I'm trying to select some areas myself instead of using the "load region_coordinates", using roipoly(fabric), but i get stuck. How do I save coordinates of the polygon I just drew? I'm actually following advice from lennon310 at Solution II, bottom of page:
A few questions about color segmentation with L*a*b*
I'm not sure when to save region_coordinates and do size(region_coordinates,1)
I made the following changes (Step 1):
1) Removed "load region_coordinates"
2) Added "region_coordinates = roipoly(fabric);"
Here's the code:
`
%% Step 1
fabric = imread(file);
figure(1); %Create figure window. "If h is not the handle and is not the Number property value of an existing figure, but is an integer, then figure(h) creates a figure object and assigns its Number property the value h."
imshow(fabric)
title('fabric')
%load regioncoordinates; % 6 marices(?) labelled val(:,:,1-6), 5x2 (row x column)
region_coordinates = roipoly(fabric);
nColors = 6;
sample_regions = false([size(fabric,1) size(fabric,2) nColors]); %Initializing an Image Dimension, 3x3 (:,:,:) to zero? Zeros() for arrays only I guess.
%Size one is column, size two is row?
for count = 1:nColors
sample_regions(:,:,count) = roipoly(fabric,region_coordinates(:,1,count),region_coordinates(:,2,count));
end
figure, imshow(sample_regions(:,:,2)),title('sample region for red');
%%Step 2
% Convert your fabric RGB image into an L*a*b* image using rgb2lab .
lab_fabric = rgb2lab(fabric);
%Calculate the mean a* and b* value for each area that you extracted with roipoly. These values serve as your color markers in a*b* space.
a = lab_fabric(:,:,2);
b = lab_fabric(:,:,3);
color_markers = zeros([nColors, 2]);%... I think this is initializing a 6x2 blank(0) array for colour storage. 6 for colours, 2 for a&b colourspace.
for count = 1:nColors
color_markers(count,1) = mean2(a(sample_regions(:,:,count))); %Label for repmat, Marker for
color_markers(count,2) = mean2(b(sample_regions(:,:,count)));
end
%For example, the average color of the red sample region in a*b* space is
fprintf('[%0.3f,%0.3f] \n',color_markers(2,1),color_markers(2,2));
%% Step 3: Classify Each Pixel Using the Nearest Neighbor Rule
%
color_labels = 0:nColors-1;
% Initialize matrices to be used in the nearest neighbor classification.
a = double(a);
b = double(b);
distance = zeros([size(a), nColors]);
%Perform classification, Elucidean Distance.
for count = 1:nColors
distance(:,:,count) = ( (a - color_markers(count,1)).^2 + (b - color_markers(count,2)).^2 ).^0.5;
end
[~, label] = min(distance,[],3);
label = color_labels(label);
clear distance;
%% Step 4: Display Results of Nearest Neighbor Classification
%
% The label matrix contains a color label for each pixel in the fabric image.
% Use the label matrix to separate objects in the original fabric image by color.
rgb_label = repmat(label,[1 1 3]);
segmented_images = zeros([size(fabric), nColors],'uint8');
for count = 1:nColors
color = fabric;
color(rgb_label ~= color_labels(count)) = 0;
segmented_images(:,:,:,count) = color;
end
%figure, imshow(segmented_images(:,:,:,1)), title('Background of Fabric');
%Looks different somehow.
figure, imshow(segmented_images(:,:,:,2)), title('red objects');
figure, imshow(segmented_images(:,:,:,3)), title('green objects');
figure, imshow(segmented_images(:,:,:,4)), title('purple objects');
figure, imshow(segmented_images(:,:,:,5)), title('magenta objects');
figure, imshow(segmented_images(:,:,:,6)), title('yellow objects');
`
You can retrieve the coordinates of the polygon using output arguments in the call to roipoly. You can then get a binary mask of the polygon, as well as vertices coordinates if you want.
Simple example demonstrating:
clear
clc
close all
A = imread('cameraman.tif');
figure;
imshow(A)
%// The vertices of the polygon are stored in xi and yi;
%// PolyMask is a binary image where pixels == 1 are white.
[polyMask, xi, yi] = roipoly(A);
This looks like this:
And if you wish to see the vertices with the binary mask:
%// display polymask
imshow(polyMask)
hold on
%// Highlight vertices in red
scatter(xi,yi,60,'r')
hold off
Which gives the following:
So to summarize:
1) The polygon's vertices are stored in xi and yi.
2) You can plot the binaryMask of the polygon using imshow(polyMask).
3) If you need the coordinates of the white pixels, you can use something like this:
[row_white,col_white] = find(polyMask == 1);
You're then good to go. Hope that helps!