demo15 of Im2mesh package
demo15 - Edit polygonal boundary before meshing
Note
I suggest familiarizing yourself with Im2mesh_GUI before learning Im2mesh package. With graphical user interface, Im2mesh_GUI will help you better understand the workflow and parameters of Im2mesh package.
If you are using Im2mesh package in MATLAB, you need to install MATLAB Image Processing Toolbox and Mapping Toolbox because Im2mesh package use a few functions in these toolboxes.
Setup
Before we start, please set folder "Im2mesh_Matlab" as your current folder of MATLAB.
Set default image size.
x = 250; y = 250; width = 300; height = 300;
set(groot, 'DefaultFigurePosition', [x,y,width,height])
% set(groot, 'DefaultFigurePosition', 'factory')
Function bounds2mesh use a mesh generator called MESH2D (developed by Darren Engwirda). We can use the following command to add the folder 'mesh2d-master' to the path of MATLAB. addpath(genpath('mesh2d-master'))
Convert Image to polyshape
Load Image
im_o = imread('Circle.tif');
if size(im_o,3) == 3; im_o = rgb2gray( im_o ); end
thresh = multithresh( im_o, num_level-1 );
seg_im = imquantize( im_o, thresh );
im = uint8( mat2gray(seg_im)*255 );
imshow( im,'InitialMagnification','fit' );
Get boundries from image
We have demostrate how to do this in example3 of demo01.mlx
bounds = im2mesh( im, opt );
% bounds is the simplified polygonal boundaries
Polyshape
It's tedious to edit boundaries directly. Using polyshape object will make things easier. We have demostrated polyshape in demo14. Please take a look at demo14 before you move to demo15.
Here, we use function bound2polyshape to convert a cell array of polygonal boundaries 'bounds' to a cell array of polyshape 'psCell'.
psCell = bound2polyshape(bounds);
Plot cell array of polyshape.
for i = 1: length(psCell)
Coordinates of 4 corners
Before we edit polyshape, we want to know about the x y coordinates of 4 corners in in variable psCell.
First, let's get the image size. This is for comparison.
So the height and width of the input image is 88 and 90, respectively. The bottom left corner in the image is [0, 0]. The upper right corner in the image is [90, 88].
We use function xyRange to get the range of x y coordinates in boundary or polyshape.
[xmin,xmax,ymin,ymax] = xyRange( psCell )
xmin = 0.5000
xmax = 90.5000
ymin = 0.5000
ymax = 88.5000
So we can know the location of bottom left corner and upper right corner in the polygonal boundary.
xyBottomLeft = [ xmin, ymin ]
xyUpRight = [ xmax, ymax ]
Compared this with the size of the image, we notice a 0.5 shifting in x y coordinates. I forgot why there is 0.5 shifting in x y coordinates since some code in Im2mesh were written by me many years ago. Probably I want to be consistent with MATLAB built-in function bwboundaries.
Let's plot.
for i = 1: length(psCell)
plot( xy(1), xy(2), 'bo', 'MarkerFaceColor', 'b');
text( xy(1), xy(2), sprintf('(%.2f, %.2f)', xy(1), xy(2)), ...
'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'center' );
plot( xy(1), xy(2), 'bo', 'MarkerFaceColor', 'b');
text( xy(1), xy(2), sprintf('(%.2f, %.2f)', xy(1), xy(2)), ...
'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'center' );
Therefore, based on 4 corners, we can know the mid point of the upper boundary and the mid point of the right boundary. We will use them later.
% mid point of the upper boundary
% mid point of the right boundary
yMidRight = (ymin+ymax)/2;
Add a block
Create a block
Let's create a block near the left side of psCell.
vertex = [ -30, 0.5; 0.5, 0.5; 0.5, 88.5; -30, 88.5 ];
psBlock = polyshape(vertex);
for i = 1: length(psCell)
Append to the end of psCell
% append to the end of psCell
for i = 1: length(psCell)
Merge geometry
We have assumed the block is a new phase in the geometry.
What if the block and the background are in the same phase? We can merge the block into the background.
First, we plot them one by one so we would know which is which.
for i = 1: length(psCell)
plot( psCell{i} ); axis equal;
title(['psCell\{' num2str(i), '\}']);
We saw that psCell{1} is the background. psCell{3} is the block.
We merge the block into the background.
psCell{1} = union( psCell{1}, psCell{3} );
psCell{3} = []; % delete the block
The length of psCell is 3 although the 3-th element is [].
To avoid error in the following steps, we need to manually delete empty elements in the cell array.
% delete empty elements in cell array
psCell = psCell( ~cellfun('isempty', psCell) );
Plot
for i = 1: length(psCell)
Create interfacial transition zone
We can assume the circles are particles.
We can use Matlab built-in function polybuffer to create interfacial transition zone (ITZ) around particles. ITZ may be useful in the FEA of composite materials.
thickness = 1.5; % unit: pixel
psITZ = polybuffer( psParticle, thickness, 'JointType', 'miter','MiterLimit', 20 );
psITZ = subtract( psITZ, psParticle );
Boolean operation
We use boolean operations to remove overlapped regions between psITZ and psCell.
for i = 1: length(psCell)
psCell{i} = subtract( psCell{i}, psITZ );
% add to the end of psCell
for i = 1: length(psCell)
Add a notch
Let's add a oval-shape notch to the point [xMidUp, yMidUp].
Define a oval. The center of the oval is [xMidUp, yMidUp].
psNotch = polyshape(x1,y1);
plot( psNotch ); axis equal
Add a oval-shape notch (by boolean operation - subtract).
for i = 1: length(psCell)
psCell{i} = subtract( psCell{i}, psNotch );
for i = 1: length(psCell)
Add a small square
Let's add a small square to the mid point of the right boundary. The mid point is [xMidRight, yMidRight].
We define a square. The center of the square is [xMidRight, yMidRight].
vertex = [ 0 0; 1 0; 1 1; 0 1 ];
psUnitSq = polyshape(vertex); % unit square
psSq = scale( psUnitSq, [30, 30]);
% set the centroid to [xMidRight, yMidRight]
[xc,yc] = centroid(psSq);
vec = [ xMidRight - xc, yMidRight - yc];
psSq = translate( psSq, vec );
for i = 1: length(psCell)
We saw that they are overlapped.
Boolean operation
We use boolean operations to remove overlapped regions.
for i = 1: length(psCell)
psCell{i} = subtract( psCell{i}, psSq );
% add to the end of psCell
for i = 1: length(psCell)
Before mesh generation
Add intersect points
Polyshape objects are not able to find intersect points automatically. Therefore, we convert the cell array of polyshape to a cell array of polygonal boundaries, and use function addIntersectPnts to add intersect points to boundaries.
Note that if we don't add intersect points, mesh generation will fail.
boundsNew = polyshape2bound(psCell);
tol_intersect = 1e-6; % distance tolerance for intersect
boundsNew = addIntersectPnts( boundsNew, tol_intersect );
plotBounds( boundsNew, false, 'ko-' );
Zoom in
plotBounds( boundsNew, false, 'ko-' )
We notice there are a lot of vertices on the notch.
Simplify boundaries
We want to reduce the number of vertices on the notch and on the boundary.
boundsNewCtrlP = getCtrlPnts( boundsNew );
tolerance = 0.02; % for Douglas-Peucker polyline simplification
boundsNewSimplified = simplifyBounds( boundsNewCtrlP, tolerance );
plotBounds( boundsNewSimplified, false, 'ko-' );
Zoom in
plotBounds( boundsNewSimplified, false, 'ko-' );
Wonderful! We saw that the number of vertices on the notch reduced a lot.
Note that you need to adjust the value of tolerance to achieve your desired reduction.
Generate mesh
To generate mesh, we use function bounds2mesh.
Note that function bounds2mesh uses MESH2D (developed by Darren Engwirda) as mesh generator. [vert,tria,tnum] = bounds2mesh( boundsNewSimplified, hmax, grad_limit );
Refine triangulation...
-------------------------------------------------------
|ITER.| |CDT1(X)| |CDT2(X)|
-------------------------------------------------------
7 294 493
10 320 603
19 333 962
Refine triangulation...
-------------------------------------------------------
|ITER.| |CDT1(X)| |CDT2(X)|
-------------------------------------------------------
9 434 493
10 434 728
20 486 2853
22 486 2863
Smooth triangulation...
-------------------------------------------------------
|ITER.| |MOVE(X)| |DTRI(X)|
-------------------------------------------------------
10 96 2821
plotMeshes(vert,tria,tnum);
Zoom in
plotMeshes(vert,tria,tnum);
Wonderful!
We can also use open-source software Gmsh to generate mesh.
We saw that the mesh density in some region is low. It's possible to refine mesh locally. Please refer to demo17 and demo16.
set(groot, 'DefaultFigurePosition', 'factory')