cropping manually and automatic using matlab
Show older comments
i want to seperate every scene in the comic, but the problem is not all of the scene are rectangle and there are so many details.
can u guys tell me the way to cropping manually or automatic after edge detection? and what the first thing i have to do before edge detection?
thanks..
6 Comments
Ryan
on 6 Jul 2012
Can you post a sample image that you are trying to segment? It is difficult to advise you with out an appropriate visual aid.
Image Analyst
on 6 Jul 2012
Who said you have to do edge detection? Can't you just threshold, call imfill(), call regionprops(), and then call imcrop()?
shara
on 7 Jul 2012
Image Analyst
on 7 Jul 2012
That image does not have separate scenes - everything is overlapped so even if you were to artificially chop it into "scenes" there would be clutter from adjacent scenes (parts of elements) that would mess up the scene. What good would that be? Why do you want to do that anyway?
shara
on 7 Jul 2012
Image Analyst
on 7 Jul 2012
Yes. that would make them connected but you can try to do imopen() to break that connection.
Answers (3)
Image Analyst
on 8 Jul 2012
Edited: Image Analyst
on 8 Jul 2012
Do you still need the manual method? I'd use rbbox or imrect - see the help for examples. For the automatic one, I probably did too much for you, but here is the code for the "depressingcomic" image.
% function to crop out panels of a cartoon/comic.
clc;
clearvars;
close all;
workspace;
fontSize = 14;
% Read in a standard MATLAB color demo image.
folder = 'C:\Users\shara\Documents\Temporary';
baseFileName = 'depressingcomicweek3cya.jpg';
fullFileName = fullfile(folder, baseFileName);
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
% Didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
rgbImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows columns numberOfColorBands] = size(rgbImage);
% Display the original color image.
subplot(2, 3, 1);
imshow(rgbImage);
title('Original Color Image', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Erase copyright.
rgbImage(552:end, 202:430, :) = 255;
% Erase title.
rgbImage(1:25, :, :) = 255;
% Display the color image.
subplot(2, 3, 2);
imshow(rgbImage);
title('Copyright and Title Erased', 'FontSize', fontSize);
% Binarize to find black pixels
% Find where either red, green, or blue channel is dark.
thresholdValue = 55;
binaryImage = rgbImage(:,:, 1) < thresholdValue | rgbImage(:,:, 2) < thresholdValue | rgbImage(:,:, 3) < thresholdValue;
% Display the image.
subplot(2, 3, 3);
imshow(binaryImage);
title('Binary Image', 'FontSize', fontSize);
% Fill the image
filledImage = imfill(binaryImage, 'holes');
% Display the image.
subplot(2, 3, 4);
imshow(filledImage);
title('Filled Binary Image', 'FontSize', fontSize);
drawnow;
% Label the image - find connected components.
[labeledImage numberOfBlobs] = bwlabel(filledImage);
% Get bounding boxes for all the regions.
measurements = regionprops(labeledImage, 'BoundingBox');
% Create colors for all the boxes.
boxColors = lines(numberOfBlobs);
% Fill in the bounding boxes to mask the "broken" panels.
for k = 1 : numberOfBlobs
x1 = measurements(k).BoundingBox(1);
y1 = measurements(k).BoundingBox(2);
width = measurements(k).BoundingBox(3);
height = measurements(k).BoundingBox(4);
x2 = x1 + width;
y2 = y1 + height;
% Plot the boxes in different colors in a separate subplot.
subplot(2, 3, 5);
hold on;
set(gca, 'ydir', 'reverse');
thisColor = boxColors(k, :);
rectangle('Position', [x1 y1 width height], 'EdgeColor', thisColor);
drawnow;
title('All the Bounding Boxes', 'FontSize', fontSize);
x1 = ceil(x1); % Get rid of the 0.5
y1 = ceil(y1); % Get rid of the 0.5
x2 = floor(x2); % Get rid of the 0.5
y2 = floor(y2); % Get rid of the 0.5
filledImage(y1:y2, x1:x2) = true;
% Display the image.
subplot(2, 3, 6);
imshow(filledImage);
title('Filled Binary Image', 'FontSize', fontSize);
end
% Call bwlabel again. This time there shoudl be 5 objects.
[labeledImage numberOfBlobs] = bwlabel(filledImage);
% Get bounding boxes for all the regions.
measurements = regionprops(labeledImage, 'BoundingBox');
% Inform user.
message = sprintf('We have now found the %d panels.\nNow we will crop them out', numberOfBlobs);
uiwait(msgbox(message));
% Create a new figure for this.
figure;
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Crop out the individual panels.
for k = 1 : numberOfBlobs
x1 = measurements(k).BoundingBox(1);
y1 = measurements(k).BoundingBox(2);
width = measurements(k).BoundingBox(3);
height = measurements(k).BoundingBox(4);
subImage = imcrop(rgbImage, [x1 y1 width height]);
% Display the image.
subplot(2, 3, k);
imshow(subImage);
caption = sprintf('Panel #%d', k);
title(caption, 'FontSize', fontSize);
if k < numberOfBlobs
message = sprintf('That was panel #%d.\nDo you want to continue and show panel #%d?', k, k+1);
% Inform user - allow to bail out if desired.
button = questdlg(message, 'Continue?', 'Yes', 'No', 'Yes');
drawnow; % Refresh screen to get rid of dialog box remnants.
if strcmpi(button, 'No')
break;
end
end
end
msgbox('Thank you ImageAnalyst!');
13 Comments
shara
on 9 Jul 2012
Image Analyst
on 9 Jul 2012
Did you try putting rbbox or imcrop into a loop like I suggested? I could do that for you but I think it's within your capabilities.
shara
on 9 Jul 2012
shara
on 28 Jul 2012
Walter Roberson
on 28 Jul 2012
No change. The code is already written to handle arbitrary numbers of panels.
shara
on 28 Jul 2012
Image Analyst
on 28 Jul 2012
The code was designed to handle the one demo image you gave. That image had a title that needed to be erased and a copyright panel at the bottom that needed to be erased. Then it had several cartoon panels which were all well separated. Obviously, you may have to edit the part about erasing title and copyright if your new image doesn't have those or they are in a different place. But after that, the code is general enough to handle any number of panels as long as they are separated. But if they are not well separated, like some of your prior images, then you're either going to havde to employ a much more complicated automatic algorithm, which may cause you to lose some of the parts of a panel that penetrate into another panel, or you're going to have to do it manually. Stuff from one panel that overlaps or penetrates into another panel will cause those panels to be connected and be considered as a single panel, according to the very simple code I gave you. The automatic way will be much, much harder than just using imrect() or rbbox(), so I'm really puzzled as to why you refuse to use them since it would be easier. Maybe you can explain why. At first you seemed to say you needed a manual way then when I tell you what functions to use to do it manually, you won't do it. Why not?
shara
on 29 Jul 2012
Image Analyst
on 29 Jul 2012
What are you trying to do? Automatic or manual? I already gave you an automatic method and I'm not going to make it more sophisticated for you to handle every possible kind of comic where panels connect to each other. Ryan gave you a manual method that I'm sure you could adapt. So, what is left to help you on? You'll have to be more explicit, plus, realize that I can't spend hours and hours to do your work for you. If I can't bang it out in a few minutes, then I leave it to you. I can give you some tips and pointers but you'll have to do the majority of coding for your project.
shara
on 29 Jul 2012
shara
on 30 Jul 2012
Image Analyst
on 30 Jul 2012
I don't know, especially without seeing the line of code it refers to. Why don't you set a breakpoint there and look at the values of all the indexes on that line, as well as the size of the array. That will tell you which index is out of range.
shara
on 30 Jul 2012
Image Analyst
on 7 Jul 2012
Just crop it.
width = col1 - col2 + 1;
height = row2 - row1 + 1;
onePanel = imcrop(originalImage, [row1 col1 width height]);
Where col1, row1, col2, and row2 are is obviously a judgement call - you and I might not agree on where they are.
9 Comments
shara
on 7 Jul 2012
Image Analyst
on 7 Jul 2012
Why don't you crop it and show us how you'd like it to be cropped? Because I have no idea. And explain why you chose the cropping locations where you did.
Walter Roberson
on 7 Jul 2012
You cannot maintain the outside shape when you crop. crop is always along rectangular boundaries. This is because MATLAB cannot store arrays with irregular boundaries.
shara
on 8 Jul 2012
Edited: Walter Roberson
on 8 Jul 2012
Walter Roberson
on 8 Jul 2012
Yes, I do mean that MATLAB can only crop into rectangular shapes.
You can use a combination of rectangular shapes and "masks", where the masks give information about which part of the rectangle are used. It is also common (but not always practical) to use rectangular shapes but to set the irrelevant information to a background color such as pure black.
The difficulty of finding only the objects relevant to a particular frame depends upon how complicated the edges are. It would be difficult for the first comic you showed, the one about recycling; it might be practical for the second comic you showed.
shara
on 8 Jul 2012
Walter Roberson
on 8 Jul 2012
Sorry, I am not experienced in this kind of analysis, and I do not have access to MATLAB to experiment with. Perhaps Image Analyst will have suggestions. You should indicate, though, whether you want to proceed by rectangular regions only, or by rectangular regions and masks, or by rectangular regions and a background color.
Image Analyst
on 8 Jul 2012
Can we assume that the copyright box will be in the same location for all your images? Because that's the only thing that would complicate the algorithm. Otherwise it's really simple, but that copyright connects the bottom three panels together. If I can assume that it will always be in the same place, I can erase it, threshold, fill, find bounding boxes, mask, then regionprops again to find bounding boxes again, and it will get the rectangular panels. But if the copyright box is sometimes there and sometimes not, or it's in different locations, then it would be a much more complicated algorithm.
shara
on 8 Jul 2012
Manual method:
scenenum = input('Please enter the number of scenes you wish to crop: ')
for m = 1:scenenum
mask = roipoly(Img);
segment{m} = immultiply(Img,mask);
Img = immultiply(Img,~mask);
figure, imshow(segment{m})
end
12 Comments
Image Analyst
on 8 Jul 2012
image is the name of a built in MATLAB function. It's best to use another name for that variable so you don't destroy that function.
Walter Roberson
on 8 Jul 2012
Fix the obvious typing mistake so that it is immultiply
shara
on 8 Jul 2012
Walter Roberson
on 8 Jul 2012
What is the error message?
Ryan
on 8 Jul 2012
what class is your image and what is its size?
shara
on 8 Jul 2012
Ryan
on 29 Jul 2012
What version of matlab are you using? (since you're asking about this again).
shara
on 29 Jul 2012
Ryan
on 29 Jul 2012
I'm not sure why you're getting an immultiply not being compatible with uint8 error... does 7.8 have the immultiply function? If not, you'll need to use .* and multiply the mask to each individual layer of Img.
Walter Roberson
on 29 Jul 2012
7.8... that's R2009a if I remember correctly.
We have not been told what the error message is. Possibly it is complaining that the two inputs are of different classes.
Image Analyst
on 29 Jul 2012
This is not what shara wants to do anyway, which is cropping. This would mask, not crop. Masking blackens inside or outside some area, while cropping extracts the bounding box of the region into a new smaller image.
Categories
Find more on Scripts 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!