Segment extraction from an image in any direction

Hi, i'm trying to extract a segment from an image in any direction. Suppose i have an 800X600 image (RGB) and i want to read a segment from point A(500,200) to point B(300,600). Is there any way i can get a column vector which contains the pixels values in that "diagonal"? i think it has to be some sort of interpolation between the nearest pixels. I don´t want to rotate the image, i need the values as they are. Regards.

 Accepted Answer

Yes. You can use improfile()
x = [200, 600];
y = [500, 300];
values = improfile(grayImage, x, y);

33 Comments

By the way, that is not how "image segmentation" is defined.
That seems to work, thanks!!!! but there is a way to display that array (i have an rgb image) as an image? right now i'm getting a black line. I need to apply this to a number of images and create a matrix which contains all the vectors from those images, and display the "new" image with all the previous segments. Sorry for "segmentation"
It's just a line so you can plot it with plot(). If you really want an image of an all black rectangle except for one gray level line, then you'll have to use imline and create a mask that you can multiply by your image. See attached demo.
I'm going to check that. What i need to do is displayed in the attached image.
Just do
x = [200, 600];
y = [500, 300];
values = improfile(grayImage, x, y);
bar(values);
sorry for not explaining myself well. The attached image is an image created with 1920 vectors concatenated into a matrix. Each vector belongs to a certain image. It is done by selecting two points from an image (two points in the same horizontal coordinate) and reading the pixels between those points. As the two points were in the same horizontal coordinate, i had no problems. But now i have to do it in any direction (from A to B as i explained before). I thought improfile would solve the problem, but as i explained to you before, when i use imshow() on the generated vector "values" it displays a black image. I need it to be a "color" segment or image. Hope it make sense now.
i couldn't do it with the explame you send me. I was trying to use Bresenham's line algorithm, but that only gave me the coordinates, i need the values aswell and the plot.
You can do it with improfile. It interpolates a straight line which is better than the jagged one you get from Bresenham. You just need to pass in a constant number of samples to improfile and then tack them on to an array:
x = [200, 600];
y = [500, 300];
values = improfile(grayImage, x, y, 300);
% Stitch this profile on to the rest of them.
theImage = [theImage, values];
You might have to transpose values if it's a row vector instead of a column vector.
i get this error: Error using horzcat Dimensions of matrices being concatenated are not consistent. Error in pruebayborra (line 9) A=[A,values];
values is a column vector 1301x1x3 double and A is my RGB image 1080x1920x3 uint8
I think i have to initialize a matrix of the size of values.
It's more complicated for a color image. You might have to do it on each color channel one at a time.
i keep getting the same error, even when i do it on each color.
what is this:
theImage = [theImage, values];
in my code grayImage,theImage = A (RGB)
If you extracted each color channel into it's own grayscale image, then why does improfile give you a 1301x1x3 array? It won't. It will give you a 1D array. You'll have to share more of your code.
sorry, that was before i did it with each color.
A=imread('img_calib.png');
x = [100, 1400];
y = [700, 200];
values=improfile(A(:,:,1),x,y,'bicubic');
A=[A,values];
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
Error in pruebayborra (line 9)
A=[A,values];
i tried with a random vector:
b=zeros(1080,300);
A=[A(:,:,1),b];
imshow(A);
and this displays the image with a black rectangle on the side. It is not quite i have to do but still, i need to display as an image the "values" vector. Any way i can do that?
Well you need to put some thought into this. You're taking a profile from two points somewhere in the image, right? Now the number of samples taken along that line would not necessarily be the same as the number of rows in the image, would it? Of course not, so you don't want to append the line to the entire original RGB image (the poorly-named "A") like you tried to do. That makes no sense.
You said you need to do lots of these lines: "I need to apply this to a number of images and create a matrix which contains all the vectors from those images" So how can we do that? Well how about we loop over all the images and in the loop we have a call to improfile. On the first image, there is nothing to append to so the first one we just take the profile itself to get started. Only if the loop index if >=2 do we append. So don't you think you'll need to do something like this inside your loop
rgbImage = imread(filenames(k).name); % read kth image.
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
x = [100, 1400];
y = [700, 200];
redValues=improfile(redChannel,x,y,'bicubic');
if k == 1
redProfiles = redValues;
else
redProfiles = [redProfiles, redValues];
end
Do the same for the green and blue channels. Then make an RGB image from them like
rgbProfiles = cat(3, redProfiles, greenProfiles, blueProfiles);
If you don't know how to loop over the filenames, see the FAQ: http://matlab.wikia.com/wiki/FAQ#How_can_I_process_a_sequence_of_files.3F
ok, let me check. Actually i have the loop code. I need to display improfile as an image. Let me check.
i still get a black line.
rgbImage=imread('img_calib.png');
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
x = [100, 1400];
y = [700, 200];
redValues=improfile(redChannel,x,y,'bicubic');
greenValues=improfile(greenChannel,x,y,'bicubic');
blueValues=improfile(blueChannel,x,y,'bicubic');
redProfiles = uint8(redValues);
greenProfiles = uint8(greenValues);
blueProfiles = uint8(blueValues);
%Do the same for the green and blue channels. Then make an RGB image from them like
rgbProfiles = cat(3, redProfiles, greenProfiles, blueProfiles);
imshow(rgbProfiles);
This is for one image. I tried changing to uint8 and still get the black line.
That's not what I showed you. Where is the "if k==1" stuff????? Well that's my last post for the day most likely. I'll be out until almost midnight. Good luck.
i was testing with one image. I can't do it for all the images if the code is not working.
i did it with 100 images. I still have tha black rectangle.
correction, that seems to work. Let me do it with all the images (2000). i'm trying to initialize a matrix because "redProfiles" is changing size in every loop.
ok, i did it, but i couldn't initialize an array and display it as the final image. I'm trying to do that because i think the process would be faster. Is that correct?
weel, here's the array %vect_foto = zeros(abs(x(2)-x(1))+1,n2,3); and here is the code.
lee_archivos2 = dir('*.jpg');
dimension2 = length(lee_archivos2);
n2 = dimension2;
B2 = 1:n2; %B2 es un vector fila
for k=1:n2
ttt=sscanf(lee_archivos2(k).name(7:end),'%ld');
B2(k)=ttt;
end
%disp(B2);
[sorted_array2,orden2] = sort(B2);%B = sort(A) sorts the elements along different dimensions of an array,
%and arranges those elements in ascending order. a can be a cell array of strings
x = [100, 1400];
y = [700, 200];
%vect_foto = zeros(abs(x(2)-x(1))+1,n2,3);
wbr = waitbar(0,'1','Name','Espere Por Favor',...
'CreateCancelBtn',...
'setappdata(gcbf,''canceling'',1)');
setappdata(wbr,'canceling',0)
for j = 1:n2 %recorre número de archivos guardados en el directorio
ima_read = imread(lee_archivos2(orden2(j)).name); %se lee cada imagen ascendentemente
redChannel = ima_read(:, :, 1);
greenChannel = ima_read(:, :, 2);
blueChannel = ima_read(:, :, 3);
redValues=improfile(redChannel,x,y,'bicubic');
greenValues=improfile(greenChannel,x,y,'bicubic');
blueValues=improfile(blueChannel,x,y,'bicubic');
if j == 1
redProfiles = uint8(redValues);
greenProfiles = uint8(greenValues);
blueProfiles = uint8(blueValues);
else
redProfiles = [redProfiles, redValues];
greenProfiles = [greenProfiles, greenValues];
blueProfiles = [blueProfiles, blueValues];
end
%Do the same for the green and blue channels. Then make an RGB image from them like
rgbProfiles = cat(3, redProfiles, greenProfiles, blueProfiles);
if getappdata(wbr,'canceling')
break
end
waitbar(j/n2,wbr,{sprintf('%g%%Completado',...
fix(100*(j/(n2))))});
fclose('all');
clear ima_read rotate_ima vect1 ttt B2 sorted_array2
end
delete(wbr);
%size(rgbProfiles)
imshow(rgbProfiles);
i have another question regarding the pixel coordinate of "redvalue" in the original image. i'll ask when you respond. Regards.
You can pass in a size for the profile so that it will be the same length for every profile it extracts. That way you can stitch the current image's profile onto the growing image of all profiles.
it seems it doesn't affect the computation time when i initialize the vectors. it should, shouldn't it? (this is my final qustion, i already solved the problem of the coordinates)
I don't know since you're not showing the code. It may or may not make a noticeable difference in run time.
lee_archivos2 = dir('*.jpg');
dimension2 = length(lee_archivos2);
n2 = dimension2;
B2 = 1:dimension2; %B2 es un vector fila
for k=1:n2
ttt=sscanf(lee_archivos2(k).name(7:end),'%ld');
B2(k)=ttt;
end
%disp(B2);
[sorted_array2,orden2] = sort(B2);%B = sort(A) sorts the elements along different dimensions of an array,
%and arranges those elements in ascending order. a can be a cell array of strings
x = [100, 1400];
y = [700, 200];
wbr = waitbar(0,'1','Name','Espere Por Favor',...
'CreateCancelBtn',...
'setappdata(gcbf,''canceling'',1)');
setappdata(wbr,'canceling',0)
cx = zeros(abs(x(2)-x(1))+1,n2);
cy = zeros(abs(x(2)-x(1))+1,n2);
cx2 = zeros(abs(x(2)-x(1))+1,n2);
cy2 = zeros(abs(x(2)-x(1))+1,n2);
cx3 = zeros(abs(x(2)-x(1))+1,n2);
cy3 = zeros(abs(x(2)-x(1))+1,n2);
redValues = zeros(abs(x(2)-x(1))+1,n2);
greenValues = zeros(abs(x(2)-x(1))+1,n2);
blueValues = zeros(abs(x(2)-x(1))+1,n2);
for j = 1:n2 %recorre número de archivos guardados en el directorio
ima_read = imread(lee_archivos2(orden2(j)).name); %se lee cada imagen ascendentemente
redChannel = ima_read(:, :, 1);
greenChannel = ima_read(:, :, 2);
blueChannel = ima_read(:, :, 3);
[cx(:,j),cy(:,j),redValues(:,j)]=improfile(redChannel,x,y,'bicubic');
[cx2(:,j),cy2(:,j),greenValues(:,j)]=improfile(greenChannel,x,y,'bicubic');
[cx3(:,j),cy3(:,j),blueValues(:,j)]=improfile(blueChannel,x,y,'bicubic');
%if j == 1
% redProfiles = uint8(redValues);
% greenProfiles = uint8(greenValues);
% blueProfiles = uint8(blueValues);
%else
% redProfiles = [redProfiles, redValues];
% greenProfiles = [greenProfiles, greenValues];
%blueProfiles = [blueProfiles, blueValues];
%end
redProfiles = uint8(redValues);
greenProfiles = uint8(greenValues);
blueProfiles = uint8(blueValues);
%Do the same for the green and blue channels. Then make an RGB image from them like
rgbProfiles = cat(3, redProfiles, greenProfiles, blueProfiles);
if getappdata(wbr,'canceling')
break
end
waitbar(j/n2,wbr,{sprintf('%g%%Completado',...
fix(100*(j/(n2))))});
fclose('all');
clear ima_read rotate_ima vect1 ttt B2 sorted_array2
end
delete(wbr);
imshow(rgbProfiles);
You are still not passing in a number to improfile to tell it how many elements to take, though it will probably be the same number every time since x and y are the same every time.
yes. x and y are the same for every loop. I change the values before the loop just for test the code. How can ia pass in the number to improfile?
numberOfSamplesToTake = round(sqrt((x(1)-x(2))^2+(y(1)-(2))^2));
[cx(:,j),cy(:,j),redValues(:,j)] = improfile(redChannel,x,y, ...
numberOfSamplesToTake, 'bicubic');
oh, ok. That is the distance between the points, but it increases the size of the vector. Is there any advantage regarding the precision of the pixel values in the final image (rgbProfiles)? Because the run time is the same, a little longer i would say.
That's using the same spacing as the original sampling. You can go higher for more "resolution" though it's just giving you more samples, not necessarily giving more information, or you can use a smaller number if you want a sampling less frequent than you have in the image. It's your choice. Do whatever you want considering the time to process and what you want to do with the final image you're building up.
I understand perfectly. Thank you!!!!

Sign in to comment.

More Answers (0)

Categories

Find more on Mathematics and Optimization in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!