Creating a circle with a gradient [closed] - matlab

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
In a different thread, I found this bit of code to make a circle that has a gradient in it (plot circle with gradient gray scale color in matlab):
N = 200; %// this decides the size of image
[X,Y] = meshgrid(-1:1/N:1, -1:1/N:1) ;
nrm = sqrt(X.^2 + Y.^2);
out = uint8(255*(nrm/min(nrm(:,1)))); %// output image
padsize = 50; %// decides the boundary width
out = padarray(out,[padsize padsize],0);
figure, imshow(out) %// show image
Now I would like to replace that gradient with a fixed vector of decreasing values, so that every radius has it's own value.
Thanks in advance for any help on this

Here is an elegant way to replace elements with values from a vector:
Assume your vector is: V = 283:-1:0.
I used descending values for demonstration.
The value 283 is sqrt(2)*N (supposed to be the maximum radius in the bounding square).
Code differences from your original post:
Divide out by max(out(:)) - set the range of out to [0, 1].
Multiply by length of V (minus 1) - set the range of out to [0, length(V)-1].
Use round instead of uint8 (converting to uint8 clamps value to 255).
Use vector V as a Look Up Table - replace each elements of out with value of V in place of the value.
Here is the code:
N = 200; %// this decides the size of image
%V = round(sqrt(2)*N):-1:0;
%Assume this is your vector.
V = 283:-1:0;
[X,Y] = meshgrid(-1:1/N:1, -1:1/N:1) ;
nrm = sqrt(X.^2 + Y.^2);
%out = uint8(255*(nrm/min(nrm(:,1)))); %// output image
%1. Divide by max(out(:)) - set the range of out to [0, 1].
%2. Multiply by length of V (minus 1) - set the range of out to [0, length(V)-1].
%3. Use round instead of uint8 (converting to uint8 clamps value to 255).
out = nrm/min(nrm(:,1));
out = round(out/max(out(:)) * (length(V)-1));
%4. Use vector V as a Look Up Table - replace each elements of out with value of V in place of the value.
out = V(out+1);
padsize = 50; %// decides the boundary width
out = padarray(out,[padsize padsize],0);
%figure, imshow(out) %// show image
figure, imagesc(out);impixelinfo;colormap hsv %// use imagesc for emphasis values.
As you can see, values are taken from vector V.

Try
R = sqrt(X.^2+Y.^2);
out = uint8(255*R);
padsize = 50; %// decides the bounary width
out = padarray(out,[padsize padsize],0);
figure, imshow(out) %// show image

Related

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

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)

Count black pixels within a circle [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have one vector of radii and second vector of hundreds of [X,Y] coordinates. For each possible coordinate-radius pair I have count all black pixels within a circle (whose center is placed in the coordinate) on an input binary image.
What is the fastest way to do it? My only idea is to iterate through every pixel of an image, check the circle equation and then the pixel color but it doesn't seem much optimized for several hundred such operations.
Matlab is great for working with images thanks to the matrix syntax. It does also work with indices so most time you can avoid "iterating through pixels" (although sometimes you'll still have to).
Instead of checking all the pixels within each circle, and having to detect how many pixels were counted twice, another approach is to create a mask, the same size of you image. Blank this mask for each of your circles (so overlapping pixels are only 'blanked' once), then apply the mask on your original picture and count the remaining illuminated pixels.
For an example, I have to take some sample data, the image:
load trees
BW = im2bw(X,map,0.4);
imshow(BW)
And 20 random point/circle coordinates (you can change the number of points and the min/max radii easily):
%// still building sample data
s = size(BW) ;
npt = 20 ; Rmin=5 ; Rmax=20 ; %// problem constants
x = randi([1 s(2)] ,npt,1); %// random X coordinates
y = randi([1 s(1)] ,npt,1); %// Y
r = randi([Rmin Rmax],npt,1); %// radius size between 5 to 20 pixels.
Then we build your custom mask :
%// create empty mask with enough overlap for the circles on the border of the image
mask = false( s+2*Rmax ) ;
%// prepare grid for a sub-mask of pixels, as wide as the maximum circle
xmask = -Rmax:Rmax ;
[xg,yg] = ndgrid(xmask,xmask) ;
rg = sqrt( (xg.^2+yg.^2) ) ; %// radius of each pixel in the subgrid
for ip=1:npt
mrow = xmask+Rmax+y(ip) ; %// calc coordinates of subgrid on original mask
mcol = xmask+Rmax+x(ip) ; %// calc coordinates of subgrid on original mask
cmask = rg <= r(ip) ; %// calculate submask for this radius
mask(mrow,mcol) = mask(mrow,mcol) | cmask ; %// apply the sub-mask at the x,y coordinates
end
%// crop back the mask to image original size (=remove border overlap)
mask = mask(Rmax+1:end-Rmax,Rmax+1:end-Rmax) ;
imshow(mask)
Then you just apply the mask and count :
%% // Now apply on original image
BWm = ~BW & mask ; %// note the ~ (not) operator because you want the "black" pixels
nb_black_pixels = sum(sum(BWm)) ;
imshow(BWm)
nb_black_pixels =
5283
Here is one implementation:
Advantages:
No loops, meshgrid/ndgrid. Instead used faster bsxfun and pdist2
Dots are counted only once, even when the circles overlap.
Variable radius used (radius of all circle is not same)
Code:
%// creating a binary image with little black dots
A = randi(600,256);
imbw = A ~= 1;
%// Your binary image with black dots
imshow(imbw);
%// getting the index of black dots
[dotY, dotX] = find(~imbw);
nCoords = 10; %// required number of circles
%// generating its random coordinates as it is unknown here
Coords = randi(size(A,1),nCoords,2);
%// calculating the distance from each coordinate with every black dots
out = pdist2(Coords,[dotX, dotY]).'; %//'
%// Getting only the black dots within the radius
%// using 'any' avoids calculating same dot twice
radius = randi([10,25],1,size(Coords,1));
pixelMask = any(bsxfun(#lt, out, radius),2);
nPixels = sum(pixelMask);
%// visualizing the results by plotting
hold on
scatter(dotX(pixelMask),dotY(pixelMask));
viscircles([Coords(:,1),Coords(:,2)],radius.'); %//'
hold off
Output:
>> nPixels
nPixels =
19

Pixel subtraction

I am working on code that select set of pixels randomly from gray images, then comparing the intensity of each 2 pixels by subtracting the intensity of pixel in one location from another one in different location.
I have code do random selection, but I am not sure of this code and I do not know how to do pixels subtraction?
thank you in advance..
{
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
randRow = randi(nRow,[N,1]);
randCol = randi(nCol,[N,1]);
subplot(2,1,1)
imagesc(im(randRow,randCol,:))
subplot(2,1,2)
imagesc(im)
}
Parag basically gave you the answer. In order to achieve this vectorized, you need to use sub2ind. However, what I would do is generate two sets of rows and columns. The reason why is because you need one set for the first set of pixels and another set for the next set of pixels so you can subtract the two sets of intensities. Therefore, do something like this:
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
%// Generate two sets of locations
randRow1 = randi(nRow,[N,1]);
randCol1 = randi(nCol,[N,1]);
randRow2 = randi(nRow,[N,1]);
randCol2 = randi(nCol,[N,1]);
%// Convert each 2D location into a single linear index
%// for vectorization, then subtract
locs1 = sub2ind([nRow, nCol], randRow1, randCol1);
locs2 = sub2ind([nRow, nCol], randRow2, randCol2);
im_subtract = im(locs1) - im(locs2);
subplot(2,1,1)
imagesc(im_subtract);
subplot(2,1,2)
imagesc(im);
However, the above code only assumes that your image is grayscale. If you want to do this for colour, you'll have to do a bit more work. You need to access each channel and subtract on a channel basis. The linear indices that were defined above are just for a single channel. As such, you'll need to offset by nRow*nCol for each channel if you want to access the same corresponding locations in the next channels. As such, I would use sub2ind in combination with bsxfun to properly generate the right values for vectorizing the subtraction. This requires just a slight modification to the above code. Therefore:
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
%// Generate two sets of locations
randRow1 = randi(nRow,[N,1]);
randCol1 = randi(nCol,[N,1]);
randRow2 = randi(nRow,[N,1]);
randCol2 = randi(nCol,[N,1]);
%// Convert each 2D location into a single linear index
%// for vectorization
locs1 = sub2ind([nRow, nCol], randRow1, randCol1);
locs2 = sub2ind([nRow, nCol], randRow2, randCol2);
%// Extend to as many channels as we have
skip_ind = permute(0:nRow*nCol:(c-1)*nRow*nCol, [1 3 2]);
%// Create 3D linear indices
locs1 = bsxfun(#plus, locs1, skip_ind);
locs2 = bsxfun(#plus, locs2, skip_ind);
%// Now subtract the locations
im_subtract = im(locs1) - im(locs2);
subplot(2,1,1)
imagesc(im_subtract);
subplot(2,1,2)
imagesc(im);

How to convert RGB images to grayscale in matlab without using rgb2gray

I'm currently using code:
i = imread('/usr/share/icons/matlab.png');
for k=1:1:m
for l=1:1:n
%a(k,l)=m*n;
a(k,l) = (.299*i(k,l,1))+(.587*i(k,l,2))+(.114*i(k,l,3));
end
end
imshow(a);
It shows only a white screen. Also the newly generated dimensions are n x m x 3 whereas it should be only m x n x 1.
If I use mat2gray it display the image like this
Since the image is a PNG, imread() is returning an integer image, with intensity values in the range [0 255] or equivalent, depending on the original bit depth. The conversion formula makes a a double image, which is expected to have intensities in the range [0 1]. Since all the pixel values in a are probably much greater than 1, they get clipped to 1 (white) by imshow().
The best option is to explicitly convert the image format before you start - this will take care of scaling things correctly:
i = imread('/usr/share/icons/matlab.png');
i = im2double(i);
a = .299*i(:,:,1) + .587*i(:,:,2) + .114*i(:,:,3); % no need for loops
imshow(a);
input=imread('test.jpg');
subplot(1,2,1), imshow(input), title('RGB Scale image');
[x,y,~] = size(input);
for i = 1:1:x
for j = 1:1:y
output(i,j) = 0.40*input(i,j,1) + 0.50*input(i,j,2) + 0.30*input(i,j,3);
end
end
subplot(1,2,2), imshow(output), title('Gray Scale image');

Roberts Operator just makes the image brighter

I posted another question about the Roberts operator, but I decided to post a new one since my code has changed significantly since that time.
My code runs, but it does not generate the correct image, instead the image becomes slightly brighter.
I have not found a mistake in the algorithm, but I know this is not the correct output. If I compare this program's output to edge(<image matrix>,'roberts',<threshold>);, or to images on wikipedia, it looks nothing like the effect of the roberts operator shown there.
code:
function [] = Robertize(filename)
Img = imread(filename);
NewImg = Img;
SI = size(Img);
I_W = SI(2)
I_H = SI(1)
Robertsx = [1,0;0,-1];
Robertsy = [0,-1;1,0];
M_W = 2; % do not need the + 1, I assume the for loop means while <less than or equal to>
% x and y are reversed...
for y=1 : I_H
for x=1 : I_W
S = 0;
for M_Y = 1 : M_W
for M_X = 1 : M_W
if (x + M_X - 1 < 1) || (x + M_X - 1 > I_W)
S = 0;
%disp('out of range, x');
continue
end
if (y + M_Y - 1 < 1) || (y + M_Y - 1 > I_H)
S = 0;
%disp('out of range, y');
continue
end
S = S + Img(y + M_Y - 1 , x + M_X - 1) * Robertsx(M_Y,M_X);
S = S + Img(y + M_Y - 1, x + M_X - 1) * Robertsy(M_Y,M_X);
% It is y + M_Y - 1 because you multiply Robertsx(1,1) *
% Img(y,x).
end
end
NewImg(y,x) = S;
end
end
imwrite(NewImg,'Roberts.bmp');
end
I think you may be misinterpreting how the Roberts Cross operator works. Use this page as a guide. Notice that it states that you convolve the original image separately with the X and Y operator. Then, you may calculate the final gradient (i.e. "total edge content") value by taking the square root of the sum of squares of the two (x and y) gradient values for a particular pixel. You're presently summing the x and y values into a single image, which will not give the correct results.
EDIT
I'll try to explain a bit better. The problem with summation instead of squaring/square root is that you can end up with negative values. Negative values are natural using this operator depending on the edge orientation. That may be why you think the image 'lightens' -- because when you display the image in MATLAB the negative values go to black, the zero values go to grey, and the positive values go to white. Here's the image I get when I run your code (with a few changes -- mostly setting NewImg to be zeros(size(Img)) so it's a double type instead of uint8. uint8 types don't allow negative values... Here's the image I get:.
You have to be very careful when trying to save files as well. Instead of calling imwrite, call imshow(NewImg,[]). That will automatically rescale the values in the double-valued image to show them correctly, with the most negative number being equal to black and most positive equal to white. Thus, in areas with little edge content (like the sky), we would expect grey and that's what we get!
I ran your code and got the effect you described. See how everything looks lighter:
Figure 1 - Original on the left, original roberts transformation on the right
The image on my system was actually saturated. My image was uint8 and the operations were pushing the image past 255 or under 0 (for the negative side) and everything became lighter.
By changing the line of code in the imread to convert to double as in
Img = double(rgb2gray( imread(filename)));
(note my image was color so I did an rgb conversion, too. You might use
Img = double(( imread(filename)));
I got the improved image:
Original on left, corrected code on right.
Note that I could also produce this result using 2d convolution rather than your loop:
Robertsx = [1,0;0,-1];
Robertsy = [0,-1;1,0];
dataR = conv2(data, Robertsx) + conv2(data, Robertsy);
figure(2);
imagesc(dataR);
colormap gray
axis image
For the following result:
Here is an example implementation. You could easily replace CONV2/IMFILTER with your own 2D convolution/correlation function:
%# convolve image with Roberts kernels
I = im2double(imread('lena512_gray.jpg')); %# double image, range [0,1]
hx = [+1 0;0 -1]; hy = [0 +1;-1 0];
%#Gx = conv2(I,hx);
%#Gy = conv2(I,hy);
Gx = imfilter(I,hx,'conv','same','replicate');
Gy = imfilter(I,hy,'conv','same','replicate');
%# gradient approximation
G = sqrt(Gx.^2+Gy.^2);
figure, imshow(G), colormap(gray), title('Gradient magnitude [0,1]')
%# direction of the gradient
Gdir = atan2(Gy,Gx);
figure, imshow(Gdir,[]), title('Gradient direction [-\pi,\pi]')
colormap(hot), colorbar%, caxis([-pi pi])
%# quiver plot
ySteps = 1:8:size(I,1);
xSteps = 1:8:size(I,2);
[X,Y] = meshgrid(xSteps,ySteps);
figure, imshow(G,[]), hold on
quiver(X, Y, Gx(ySteps,xSteps), Gy(ySteps,xSteps), 3)
axis image, hold off
%# binarize gradient, and compare against MATLAB EDGE function
BW = im2bw(G.^2, 6*mean(G(:).^2));
figure
subplot(121), imshow(BW)
subplot(122), imshow(edge(I,'roberts')) %# performs additional thinning step