How to split an image into several curved shape small images?
2 views (last 30 days)
Show older comments
I have an image and I want to divide it into small curved shape image without using manual cropping. For example the attached input will be splited into curved shape small region which are indicated by the line.
Thanks for the help in advance.
1 Comment
Bjorn Gustavsson
on 11 Aug 2021
My code snippet were an example for how you would calculate/extract one such curved segment - provided that the boundary had a shape proportional to cos(x*2*pi/n_hor_pix) and of a known width. For you to use that snippet, you would have to come up with a way to generate the segment boundaries in a neat fashion - I expect that you don't want the lines you have drawn (I guess) in red above and that those are more representative of what you want, If you can model those with some kind of simple sin/bell-type curve you could modify the generation of the y-coordinate in my example reasonably easy. If I've interpreted your question wrong then you might have to explain more precisely what you want.
Accepted Answer
Image Analyst
on 11 Aug 2021
Try this:
% Demo to find layers in a cross sectional image.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
grayImage = imread('C2_down5um_246.jpg');
% Get the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
% Extract the red channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 1);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
hFig = gcf;
hFig.WindowState = 'maximized'; % May not work in earlier versions of MATLAB.
drawnow;
% Binarize
lowThreshold = 35;
highThreshold = 255;
% [lowThreshold, highThreshold] = threshold(lowThreshold, highThreshold, grayImage);
mask = grayImage > lowThreshold;
% Take largest blob
mask = bwareafilt(mask , 1);
% Display the image.
subplot(2, 2, 2);
imshow(mask, []);
axis('on', 'image');
title('Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Scan to get the top row.
[rows, columns] = size(mask);
% Find top curve first.
topRows = nan(1, columns);
for col = 1 : columns
t = find(mask(:, col), 1, 'first');
if ~isempty(t)
topRows(col) = t;
end
end
hold on;
plot(topRows, 'r-', 'LineWidth', 3)
% Display the image.
subplot(2, 2, 3);
imshow(grayImage, []);
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
drawnow;
hold on;
% Make a bunch of them, each lower than the previous.
deltay = round(rows/8)
allCurves = nan(7, columns);
nonObjectIndexes = isnan(topRows);
for k = 1 : 7
% Get this curve.
thisRow = topRows + (k-1) * deltay;
% Clip it to the bottom of the image.
thisRow = min(thisRow, rows);
% Make columns where there was no object NaN again - they were 365.
thisRow(nonObjectIndexes) = nan;
allCurves(k, :) = thisRow;
plot(thisRow, 'r-', 'LineWidth', 3)
end
Not sure what you want to do after that though. And is it really necessary to extend the curves all the way to the left and right edge of the image when there's nothing there? If so, we could fit the curve to a quadratic with polyfit() and extend it that way.
17 Comments
Image Analyst
on 13 Aug 2021
I think you could have done it if you had actually tried. But anyway, the solution is attached.
More Answers (2)
Bjorn Gustavsson
on 11 Aug 2021
Edited: Bjorn Gustavsson
on 11 Aug 2021
You should be able to do that with interp2, you just have to select the coordinates of your curved regions to use for interpolating points. Something like this:
Im = peaks(234);
y = 1:23;
x = 1:234;
[x,y] = meshgrid(x,y);
y = y + 130 -30*cos(x*2*pi/234); % This is just an illustrating example for your curve
subplot(2,2,1)
imagesc(Im)
hold on
plot(x(1,:),y(1,:),'k.')
plot(x(end,:),y(end,:),'k.')
peaksCurved = interp2(1:234,1:234,Im,x,y);
subplot(2,2,2)
imagesc(peaksCurved)
caxis([-6.5493, 8.106])
subplot(2,2,3)
pcolor(x,y,peaksCurved),caxis([-6.5493, 8.106]),shading flat
axis ij
axis([1 234 1 234])
HTH
6 Comments
Bjorn Gustavsson
on 12 Aug 2021
"indicated by test.jpg" is not specific enough for us to understand by what criteria you want your region boundaries to be determined.
Image Analyst below guesses that it is some gray-level intesity-boundary for the topmost region and then shifts it downward. I guessed that you could use some kind of functional form for the boundaries and get the intensities in the curved regions by interpolation.
You will have to understand that in order to get a solution that gives you precisely what you want you will have to precisely specify what it is you want. Your hand-scribbled boundaries can be used to generate boundaries but that is: a a hassle, and b seems rather imprecise and arbitrary.
Repeating your reference to the image with your scribbly lines will not give us any new and more precise information.
Image Analyst
on 11 Aug 2021
Please attach your original image.
What I'd do is to try to get the upper surface/curve first since that is the brightest. You might be able to just threshold and then scan across finding the first pixel above the threshold. Then for the lower curves, just subtract some number from the top one. Something like
mask = grayImage > someValue;
mask = bwareafilt(mask, 1); % Take largest to try to get rid of noise.
[rows, columns] = size(mask);
% Find top curve first.
topRows = nan(1, columns);
for col = 1 : columns
t = find(mask(:, col), 1, 'first')
if ~isempty(t)
topRows(col) = col;
end
end
hold on;
% Make a bunch of them, each lower than the previous.
deltay = round(rows/8)
allCurves = zeros(7, columns);
for k = 1 : 7
allCurves(k, :) = topRows + (k-1) * deltay;
plot(allCurves(k, :), 'r-', 'LineWidth', 3)
end
% Clip to bottom of image
allCurves = min(allCurves, rows);
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!