I have a jpg image I want to crop by an arbitrary polygon. I'm trying to do it by imcrop: imcrop(X, map, rect), but it only allows to specify a rectangular area in rect and I have more complex polygons... In detail, I want to extract some features from an ortho-image by the polygons of the relative shapefile, here my code:
%%read orthophoto
[X cmap] = imread('orthophoto_1.jpg');
R = worldfileread('orthophoto_1.jgw');
%%read shapefile buildings
[s, a] = shaperead('buildings.shp');
s is:
61555x1 struct array with fields:
Geometry
BoundingBox
X
Y
and if I take s(1,1) for instance I have my polygon, which I want to crop:
Geometry: 'Polygon'
BoundingBox: [2x2 double]
X: [1x11 double]
Y: [1x11 double]
I would like to do something like:
%%crop the feature
feature_1 = imcrop(X, map, s(1,1).X, s(1,1).Y);
and then save it to new jpg.
Maybe I could use roipoly or impoly to pass the polygon to imcrop?
Any help would be extremely appreciated! Thanks in advance!
Luca
I agree I can crop it that way, but it doesn't solve my problem as I want to extract the exact area of a general-shaped polygon (which is not a rectangle). This would be the starting point, extracting a submatrix of the bounding box, but then I have to go one more step to keep the matrix elements within my shape and "remove" the rest.. roipoly could be good, but requires knowledge of matrix indices to contruct the shape..I have x and y coordinates instead (obviously in consistent geo-reference system)..
a hint:
doc poly2mask
% Change the current folder to the folder of this m-file.
if(~isdeployed)
cd(fileparts(which(mfilename)));
end
clc; % Clear command window.
clear; % Delete all variables.
close all; % Close all figure windows except those created by imtool.
imtool close all; % Close all figure windows created by imtool.
workspace; % Make sure the workspace panel is showing.
fontSize = 20;
% Read in standard MATLAB gray scale demo image.
grayImage = imread('cameraman.tif');
subplot(2, 2, 1);
imshow(grayImage, []);
title('Original Grayscale Image', 'FontSize', fontSize);
set(gcf, 'Position', get(0,'Screensize')); % Maximize figure.
message = sprintf('Left click and hold to begin drawing.\nSimply lift
the mouse button to finish');
uiwait(msgbox(message));
hFH = imfreehand();
% Create a binary image ("mask") from the ROI object.
binaryImage = hFH.createMask();
% Display the freehand mask.
subplot(2, 2, 2);
imshow(binaryImage);
title('Binary mask of the region', 'FontSize', fontSize);
% Calculate the area, in pixels, that they drew.
numberOfPixels1 = sum(binaryImage(:))
% Another way to calculate it that takes fractional pixels into
account.
numberOfPixels2 = bwarea(binaryImage)
% Get coordinates of the boundary of the freehand drawn region.
structBoundaries = bwboundaries(binaryImage);
xy=structBoundaries{1}; % Get n by 2 array of x,y coordinates.
x = xy(:, 2); % Columns.
y = xy(:, 1); % Rows.
subplot(2, 2, 1); % Plot over original image.
hold on; % Don't blow away the image.
plot(x, y, 'LineWidth', 2);
% Burn line into image by setting it to 255 wherever the mask is true.
burnedImage = grayImage;
burnedImage(binaryImage) = 255;
% Display the image with the mask "burned in."
subplot(2, 2, 3);
imshow(burnedImage);
title('New image with mask burned into image', 'FontSize', fontSize);
% Mask the image and display it.
% Will keep only the part of the image that's inside the mask, zero
outside mask.
maskedImage = grayImage;
maskedImage(~binaryImage) = 0;
subplot(2, 2, 4);
imshow(maskedImage);
title('Masked Image', 'FontSize', fontSize);
% Calculate the mean
meanGL = mean(maskedImage(binaryImage));
% Report results.
message = sprintf('Mean value within drawn area = %.3f\nNumber of
pixels = %d\nArea in pixels = %.2f', ...
meanGL, numberOfPixels1, numberOfPixels2);
msgbox(message);
im_crop is your image
vertex_x is the vector of x-coordinates of your polygon
vertex_y is the vector of y-coordinates of your polygon
im_crop_size=size(im_crop);
mask = poly2mask(vertex_x,vertex_y,im_crop_size(1,1),im_crop_size(1,2));
Split your RGB image in bands, mask each of them and re-build the image (set background to black):
R=im_crop(:,:,1);
G=im_crop(:,:,2);
B=im_crop(:,:,3);
R(~mask)=0;
G(~mask)=0;
B(~mask)=0;
masked_im = cat(3,R,G,B);
Cya!
You could also do this with bsxfun or repmat. Just for your knowledge:
masked_im2 = bsxfun(@times,im_crop,cast(mask,class(im_crop)))
masked_im3 = im_crop.*repmat(cast(mask,class(im_crop)),[1 1 3]);
hi,
i want to say thanks for your question and the solution. because i'm trying to do this veryy very long time and i can't do it. then tonight i find your message, i apply it to my code and it works. Thank you...
i apologize you for my english.