I have to extract features of an image using the image extraction from MATLAB. It works successfully with the image provided by The MathWorks in their tutorial, but when I enter another image it doesn't work
My code for image extraction is:
boxImage = imread('stapleRemover.jpg');
%boxImage = imread('D:\matlab test\book\IMG_2294.jpg');
figure;
imshow(boxImage);
title('Image of a Box');
%sceneImage = imread('D:\matlab test\book\IMG_2291.jpg');
sceneImage = imread('clutteredDesk.jpg');
figure;
imshow(sceneImage);
title('Image of Cluttered Scene');
%detecting feature point
boxPoints = detectSURFFeatures(boxImage);
scenePoints = detectSURFFeatures(sceneImage);
figure;
imshow(boxImage);
title('100 strongest feature Points from Box Image');
hold on;
plot(selectStrongest(boxPoints, 100));
figure;
imshow(sceneImage);
title('300 Strongest Feature Points from Scene Image');
hold on;
plot(selectStrongest(scenePoints, 300));
%extracting feature descriptor
[boxFeatures, boxPoints] = extractFeatures(boxImage, boxPoints);
[sceneFeatures, scenePoints] = extractFeatures(sceneImage, scenePoints);
%finding putative point match
boxPairs = matchFeatures(boxFeatures, sceneFeatures);
matchedBoxPoints = boxPoints(boxPairs(:, 1), :);
matchedScenePoints = scenePoints(boxPairs(:, 2), :);
figure;
showMatchedFeatures(boxImage, sceneImage, matchedBoxPoints, matchedScenePoints, 'montage');
title('Putatively Matched Points (Including Outliers)');
%locating object in the scene using putative matches
[tform, inlierBoxPoints, inlierScenePoints] = estimateGeometricTransform(matchedBoxPoints, matchedScenePoints, 'affine');
figure;
showMatchedFeatures(boxImage, sceneImage, inlierBoxPoints,inlierScenePoints, 'montage');
title('Matched Points (Inliers Only)');
boxPolygon = [1, 1; % top-left
size(boxImage, 2), 1; % top-right
size(boxImage, 2), size(boxImage, 1); % bottom-right
1, size(boxImage, 1); % bottom-left
1, 1]; % top-left again to close the polygon
newBoxPolygon = transformPointsForward(tform, boxPolygon);
figure;
imshow(boxPolygon);
imshow(sceneImage);
hold on;
line(newBoxPolygon(:, 1), newBoxPolygon(:, 2), 'Color', 'y');
title('Detected Box');
It runs successfully, but when I change the image which is made by me using my camera, it stops executing code on this line:
boxPoints = detectSURFFeatures(boxImage);
Can anyone help me to out?
What error are you getting? From the information you've given, I would guess that your image is RGB, and you need to convert it to grayscale before passing it to detectSURFFeatures.
Undefined function showMatchedFeatures
for input arguments of type SURFPoints.
in matlab 2012a
Related
How can I paste back a part of my picture after I changed it in MATLAB? I cropped the plates off this image of a car and now I want to put it back automatically. The plates are still at the same coordinates as they were initially, but the background is all black.
The car I want to paste on:
And this is what I want to paste:
Here is my code, I want to change the part where I need to draw by hand the plate.
fontSize = 20;
format compact;
baseFileName1 = 'blurr_plate.jpg';
baseFileName2 = 'car2.jpg';
sourceImage = imread(baseFileName1);
subplot(1, 2, 1);
imshow(sourceImage);
axis on;
caption = sprintf('Source image, %s', baseFileName1);
title(caption, 'FontSize', fontSize, 'Interpreter', 'none');
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Give a name to the title bar.
set(gcf,'name','Demo by ImageAnalyst','numbertitle','off')
targetImage = imread(baseFileName2);
subplot(1, 2, 2);
imshow(targetImage);
axis on;
caption = sprintf('Target image, %s, original', baseFileName2);
title(caption, 'FontSize', fontSize, 'Interpreter', 'none');
% Ask user to draw freehand mask.
message = sprintf('In the LEFT IMAGE...\nLeft click and hold to begin drawing.\nSimply lift the mouse button to finish');
subplot(1, 2, 1);
uiwait(msgbox(message));
hFH = imfreehand(); % Actual line of code to do the drawing.
% Create a binary image ("mask") from the ROI object.
mask = hFH.createMask();
xy = hFH.getPosition;
% Paste it onto the target image.
targetImage(mask) = sourceImage(mask);
% Display new image.
subplot(1, 2, 2); % Switch active axes to right hand axes.
imshow(targetImage);
imwrite(targetImage, 'car_new.jpg')
axis on;
caption = sprintf('Target image, %s, after paste', baseFileName2);
title(caption, 'FontSize', fontSize, 'Interpreter', 'none');
Your code will work only in case when both source and target images are grayscale. As your target image is coloured, make following changes:
Delete line number 35,36 and 41.
paste this code after line 33.
redChannel = targetImage(:, :, 1);
greenChannel = targetImage(:, :, 2);
blueChannel = targetImage(:, :, 3);
redChannel(mask) = sourceImage(mask);
greenChannel(mask) = sourceImage(mask);
blueChannel(mask) = sourceImage(mask);
targetImage = cat(3, redChannel, greenChannel, blueChannel);
I'm trying to color only a segment of an image in Matlab. For example, I load an RGB image, then I obtain a mask with Otsu's method (graythresh). I want to keep the color only in the pixels that have value of 1 after applying im2bw with graythresh as the threshold. For example:
image = imread('peppers.png');
thr = graythresh(image);
bw = im2bw(image, thr);
With this code I obtain the following binary image:
My goal is to keep the color in the white pixels.
Thanks!
I have another suggestion on how to replace the pixels we don't care about. This works by creating linear indices for each of the slices where black pixels exist in the bw image. The summation with the result of find is done because bw is the size of just one "slice" of image and this is how we get the indices for the other 2 slices.
Starting MATLAB 2016b:
image(find(~bw)+[0 numel(bw)*[1 2]]) = NaN;
In older versions:
image(bsxfun(#plus,find(~bw),[0 numel(bw)*[1 2]])) = NaN;
Then imshow(image) gives:
Note that NaN gets converted to 0 for integer classes.
Following the clarification that the other pixels should be kept in their gray version, see the below code:
% Load image:
img = imread('peppers.png');
% Create a grayscale version:
grayimg = rgb2gray(img);
% Segment image:
if ~verLessThan('matlab','9.0') && exist('imbinarize.m','file') == 2
% R2016a onward:
bw = imbinarize(grayimg);
% Alternatively, work on just one of the color channels, e.g. red:
% bw = imbinarize(img(:,:,1));
else
% Before R2016a:
thr = graythresh(grayimg);
bw = im2bw(grayimg, thr);
end
output_img = repmat(grayimg,[1 1 3]);
colorpix = bsxfun(#plus,find(bw),[0 numel(bw)*[1 2]]);
output_img(colorpix) = img(colorpix);
figure; imshow(output_img);
The result when binarizing using only the red channel:
Your question misses "and replace the rest with black". here are two ways:
A compact solution: use bsxfun:
newImage = bsxfun(#times, Image, cast(bw, 'like', Image));
Although I am glad with the previous one, you can also take a look at this step-by-step approach:
% separate the RGB layers:
R = image(:,:,1);
G = image(:,:,2);
B = image(:,:,3);
% change the values to zero or your desired color wherever bw is false:
R(~bw) = 0;
G(~bw) = 0;
B(~bw) = 0;
% concatenate the results:
newImage = cat(3, R, G, B);
Which can give you different replacements for the black region:
UPDATE:
According to the comments, the false area of bw should be replaced with grayscale image of the same input. This is how to achieve it:
image = imread('peppers.png');
thr = graythresh(image);
bw = im2bw(image, thr);
gr = rgb2gray(image); % generate grayscale image from RGB
newImage(repmat(~bw, 1, 1, 3)) = repmat(gr(~bw), 1, 1, 3); % substitude values
% figure; imshow(newImage)
With this result:
I'd like to plot a graph over an image. I followed this tutorial to Plot over an image background in MATLAB and it works fine:
% replace with an image of your choice
img = imread('myimage.png');
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
% make data to plot - just a line.
x = min_x:max_x;
y = (6/8)*x;
imagesc([min_x max_x], [min_y max_y], img);
hold on;
plot(x,y,'b-*','linewidth',1.5);
But when I apply the procedure to my study case, it doesn't work. I'd like to do something like:
I = imread('img_png.png'); % here I load the image
DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000);
% with the last 3 lines I calculated the stream network on a geographic area using the TopoToolBox
imagesc(I);
hold on
plot(S)
The aim is to plot the stream network over the satellite image of the same area.
The only difference between the two examples that doesn't let the code working is in the plot line, in the first case "plot(x,y)" works, in the other one "plot(S)" doesn't.
Thanks guys.
This is the satellite image, imagesc(I)
It is possible that the plot method of the STREAMobj performs it's own custom plotting including creating new figures, axes, toggling hold states, etc. Because you can't easily control what their plot routine does, it's likely easier to flip the order of your plotting so that you plot your stuff after the toolbox plots the STREAMobj. This way you have completely control over how your image is added.
% Plot the STREAMobj
hlines = plot(S);
% Make sure we plot on the same axes
hax = ancestor(hlines, 'axes');
% Make sure that we can add more plot objects
hold(hax, 'on')
% Plot your image data on the same axes
imagesc(I, 'Parent', hax)
Maybe I am preaching to the choir or overlooking something here but the example you used actually mapped the image to the data range of the plot, hence the lines:
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
imagesc([min_x max_x], [min_y max_y], img);
where you directly plot your image
imagesc(I);
If now your data coordinates and your image coordinates are vastly different you either see one or the other.
Thanks guys, I solved in this way:
I = imread('orto.png'); % satellite image loading
DEM = GRIDobj('demF1.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000); % Stream network extraction
x = S.x; % [node attribute] x-coordinate vector
y = S.y; % [node attribute] y-coordinate vector
min_x = min(x);
max_x = max(x);
min_y = min(y);
max_y = max(y);
imagesc([min_x max_x], [min_y max_y], I);
hold on
plot(S);
Here's the resulting image: stream network over the satellite image
Actually the stream network doesn't match the satellite image just because I'm temporarily using different images and DEM.
I'm trying to plot small images on a larger plot... Actually its isomap algorithm, I got many points, now each point correspond to some image, I know which image is it... The porblem is how to load that image and plot on the graph?
One more thing I have to plot both image and the points, so, basically the images will overlap the points.
Certainly, the type of image given here
Something like this should get you started. You can use the low-level version of the image function to draw onto a set of axes.
% Define some random data
N = 5;
x = rand(N, 1);
y = rand(N, 1);
% Load an image
rgb = imread('ngc6543a.jpg');
% Draw a scatter plot
scatter(x, y);
axis([0 1 0 1]);
% Offsets of image from associated point
dx = 0.02;
dy = 0.02;
width = 0.1;
height = size(rgb, 1) / size(rgb, 2) * width;
for i = 1:N
image('CData', rgb,...
'XData', [x(i)-dx x(i)-(dx+width)],...
'YData', [y(i)-dy y(i)-(dy+height)]);
end
I have a set of Dicom images on matlab and i would like to add a midline going through all the images
I am outputting the images via imshow3d function
thanks
Edit: here's what i have, the random points are not in the middle they just run through the image
>> clc;
>>clear;
>>%imports dicom images
>>run DicomImport.m;
>>%random points for shortest distance test
>>a = [1 10 200];
>>b = [500 512 300];
>>ab = b - a;
>>n = max(abs(ab)) + 1;
>>s = repmat(linspace(0, 1, n)', 1, 3);
>>for d = 1:3
>> s(:, d) = s(:, d) * ab(d) + a(d);
>>end
>>s = round(s);
>>Z = 593;
>>N = 512;
>>X = zeros(N, N, Z);
>>X(sub2ind(size(X), s(:, 1), s(:, 2), s(:, 3))) = 1;
>>C = find(X);
>>ans.Img(C) = 5000;
>> %shows image
>>imshow3D(ans.Img);
So it looks like ans.Img contains the 3D matrix consisting of your image stack. It looks like you've got something going, but allow me to do this a bit differently. Basically, you need to generate a set of coordinates where we can access the image stack and draw a vertical line in the middle of the each image in the image stack. Do something like this. First get the dimensions of the stack, then determine the halfway point for the columns. Next, generate a set of coordinates that will draw a line down the middle for one image. After you do this, repeat this for the rest of the slices and get the column major indices for these:
%// Get dimensions
[rows,cols,slices] = size(ans.Img);
%// Get halfway point for columns
col_half = floor(cols/2);
%// Generate coordinates for vertical line for one slice
coords_middle_row = (1:rows).';
coords_middle_col = repmat(col_half, rows, 1);
%// Generate column major indices for the rest of the slices:
ind = sub2ind(size(ans.Img), repmat(coords_middle_row, slices, 1), ...
repmat(coords_middle_col, slices, 1), ...
reshape(kron(1:slices, ones(rows, 1)), [], 1));
%// Set the pixels accordingly
ans.Img(ind) = 5000;
This code is quite similar to the answer I provided to one of your earlier question; i.e. I don't use imshow3D but the framework is similar and simpler to modify in order to suit your need. In this case, upon pressing a pushbutton a line appears at the middle of the stack and you can scroll through it with the slider. I hope this can be of help.
function LineDicom(~)
clc
clear
close all
%// Load demo data
S = load('mri');
%// Get dimensions and number of slices.
ImageHeight = S.siz(1); %// Not used here
ImageWidth = S.siz(2); %// Not used here
NumSlices = S.siz(3);
S.D = squeeze(S.D);
%// Create GUI
hFig = figure('Position',[100 100 400 400],'Units','normalized');
%// create axes with handle
handles.axes1 = axes('Position', [0.2 0.2 0.6 0.6]);
%// create y slider with handle
handles.y_slider = uicontrol('style', 'Slider', 'Min', 1, 'Max', NumSlices, 'Value',1, 'Units','normalized','position', [0.08 0.2 0.08 0.6], 'callback', #(s,e) UpdateY);
handles.SlideryListener = addlistener(handles.y_slider,'Value','PostSet',#(s,e) YListenerCallBack);
%// Create pusbutton to draw line
handles.DrawLineButton= uicontrol('style', 'push','position', [40 40 100 30],'String','Draw line', 'callback', {#DrawLine,handles});
%// Flag to know whether pushbutton has been pushed
handles.LineDrawn = false;
%// Show 1st slice
imshow(S.D(:,:,1))
guidata(hFig,handles);
%// Listeners callbacks followed by sliders callbacks. Used to display each
%// slice smoothly.
function YListenerCallBack
handles = guidata(hFig);
%// Get current slice
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
%// If button was button, draw line
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
function UpdateY(~)
handles = guidata(hFig); %// Get handles.
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
%// Pushbutton callback to draw line.
function DrawLine(~,~,handles)
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
handles.LineDrawn = true;
guidata(hFig,handles);
end
end
Sample output:
and after moving the slider up:
Is this what you meant? If not I'll remove that answer haha and sorry.