Image pre-processing and Connected Components - matlab

I have a comics image, and I want to extract panels and text balloons from it.
I am using connected component algorithm for this purpose,"bwconncomp".
Knowing that "bwconncomp" requires a binary image as an argument, I am using "im2bw" to binarize my image followed by some morphological filtering.
Ibw = im2bw(I,graythresh(I)); % also tried the default threshold along with all values in the % range [0 1]
Imr = bwmorph(Ibw,'skel'); % also tried 'close' and 'clean'
Icc = bwareaopen(Imr,100);
The problem is that I am getting a drastic change in the number of detected connected components as I change the binarization threshold and some changes upon morphological operation. None of the combinations I have tried gave me all available major objects of the image, there is always some missing.
Can anyone please guide me with that?

You can try detecting text, rather than simply binarizing the image. If you have a recent version of MATLAB with the Computer Vision System Toolbox, you can try this example of text detection.

Related

Plot true color Sentinel-2A imagery in Matlab

Through a combination of non-matlab/non-native tools (GDAL) as well as native tools (geoimread) I can ingest Sentinel-2A data either a indiviual bands or as an RGB image having employed gdal merge. I'm stuck at a point where using
imshow(I, [])
Produces a black image, with apparently no signal. The range of intensity values in the image are 271 - 4349. I know that there is a good signal in the image because when I do:
bit_depth = 2^15;
I = swapbytes(I);
[I_indexed, color_map] = rgb2ind(I, bit_depth);
I_double = im2double(I_indexed, 'indexed');
ax1 = figure;
colormap(ax1, color_map);
image(I_double)
i.e. index the image, collect a colormap, set the colormap and then call the image function, I get a likeness of the region I'm exploring (albeit very strangely colored)
I'm currently considering whether I should try:
Find a low-level description of Sentinel-2A data, implement the scaling/correction
Use a toolbox, possibly this one.
Possibly adjust ouput settings in one of the earlier steps involving GDAL
Comments or suggestions are greatly appreciated.
A basic scaling scheme is:
% convert image to double
I_double = im2double(I);
% scaling
max_intensity = max(I_double(:));
min_intensity = min(I_double(:));
range_intensity = max_intensity - min_intensity;
I_scaled = 2^16.*((I_double - min_intensity) ./ range_intensity);
% display
imshow(uint16(I_scaled))
noting the importance of casting to uint16 from double for imshow.
A couple points...
You mention that I is an RGB image (i.e. N-by-M-by-3 data). If this is the case, the [] argument to imshow will have no effect. That only applies automatic scaling of the display for grayscale images.
Given the range of intensity values you list (271 to 4349), I'm guessing you are dealing with a uint16 data type. Since this data type has a maximum value of 65535, your image data only covers about the lower 16th of this range. This is why your image looks practically black. It also explains why you can see the signal with your given code: you apply swapbytes to I before displaying it with image, which in this case will shift values into the higher intensity ranges (e.g. swapbytes(uint16(4349)) gives a value of 64784).
In order to better visualize your data, you'll need to scale it. As a simple test, you'll probably be able to see something appear by just scaling it by 8 (to cover a little more than half of your dynamic range):
imshow(8.*I);

Unite endpoints of edge with line

I'm trying to make an object recognition program using a k-NN classifier. I've got a bunch of images for the training part of the classifier and a bunch of images to recognize. Those images are in grayscale and there's an object (only its edge) per image. I need to calculate their center of mass so I use
img=im2bw(img)
and then regionprops(img,'centroid').
The problem is that some of those edges aren't closed so regionprops doesn't work then. I tried eroding the image (the edge is black, white background) but the endlines of those edges are too apart from eachother. I tried using bwmorph function to do so but still can't make it work.
Any ideas?
EDIT
I'm adding some images in case anyone wants to try:
Use morphological operation
Use a closing operation to make your structures filled.
1. As first step prepare your image data
im = imread('your image.jpg');
% Get first channel as gray scale information
im = im(:,:,1);
% Threshold it for simplicyty, you may work on grayscale too.
im1 = logical(im > 128);
2. Use a simple block shaped structuring element
The structuring element is defined by:
strel=ones(3,3);
You may use disk shaped elements or whatever gives the best result to you.
3. Apply structuring element a couple of times
Apply the strel a couple of times with an erosion operator to your original image to close your figure:
for i=1:20
im1 = imerode(im1,strel);
end
4. Dilate the image to get back to original shape
Next step is to dilate the image to get back to your original outer shape:
for i=1:20
im1 = imdilate(im1,strel);
end
Final result
The final result should be suitable to get a sufficiently precise center or gravity.

Why no feature is being tracked using KLT-tracking in Matlab?

I am trying to track some features (extracted using multiscale-harrys detector) between two frames using the Kanade-Lucas-Tomasi (KLT) algorithm using the functions you can find here (Mathworks documentation).
I cannot understand what goes wrong. None of the points can be tracked. I tried making bigger the number of iterations and changing the size of the window around the features but the result is always the same, no feature is tracked.
Is it a problem in the data (images resolution is too low (240x180 pixels))?
Is the problem in the selected features?
These are the two images I am using:
This is my code:
img = single(imread('img.png'));
end_img = single(imread('end_img.png'));
coord_first = [24,21;25,97;29,134;37,25;37,55;37,64;38,94;38,103;40,131;41,139;43,14;44,22;44,54;44,63;46,93;46,101;47,111;49,131;49,140;52,166;55,52;62,151;76,51;78,89;81,151;81,165;83,13;92,165;111,18;111,96;155,42;155,62;155,81;155,100;156,129;163,133;168,126;170,40;170,65;172,26;173,134;174,59;174,84;174,103;174,116;175,73;178,97;186,142;186,149;190,119;190,132;194,75;209,99;210,42;210,66;212,133;212,152;215,61;215,79;218,119];
% display of the target image and all the features I want to track
figure
imshow(img,[]),
colormap gray
hold on
plot(coord_first(:,1), coord_first(:,2), 'r*');
% point tracker creation
% the paramters reported here are the default ones
pointTracker = vision.PointTracker('MaxIterations', 30, 'BlockSize', [31,31]);
% point tracker initialization
initialize(pointTracker,coord_first,img);
% actual tracking
[coord_end, point_validity] = step(pointTracker, end_img);
% display of all the correctly tracked featrures
figure
imshow(end_img,[]),
colormap gray
hold on
plot(coord_end(point_validity,1), coord_end(point_validity,2), 'r*');
Actually I have just solved the problem. Of course the problem was the fact that no point was tracked.
The problem is that the images given in input must have grayscale values in [0, 1] and not in [0, 255] (as I was doing).
There is no specific need to tune any of the parameter once the data are passed the right way (at least in my case with these low resolution grayscale images).
Check the contents of point_validity. If all elements of points_validity are false, then you would not see any points. If that is the case, the next question is why points were not tracked.
For an image of this size, try setting 'NumPyramidLevels' to 1.

Determine the orientation of a triangle in Matlab

I am working on a project to perform automatically the landing of a quadrotor by visual recognition on a target. I have the code to detect the target through HOG features. Now the idea is to find the triangle, which is isosceles, and measure the lines so that I can determine the orientation that way. I have tried Hough, but I cannot manage to succeed.
The target is a proposed one
, and it consists of an isosceles triangle inside a circle. But if you can think of a better one, please let me know.
Please, ask any questions if anything is unclear. Thank you very much
Update 1:
#McMa 's idea works well when I deal only with the target as an image. This is the code:
clc; close all;
im=imread('target.bmp');
im=rgb2gray(im);
im2=imcrop(im,[467.51 385.51 148.98 61.98]);
im2=imcomplement(im2);
im2=imrotate(im2,0);
s=regionprops(im2,'Area','Centroid','Extrema','Orientation');
[imH,imW]=size(im2);
if imH-s(end).Centroid(2) < imH/2
state=1; % Upright
else
state=2; % Upside down
end
imshow(im2);hold on
plot(s(end).Centroid(1), s(end).Centroid(2), 'b*')
if s(end).Orientation>0
degrees=s(end).Orientation;
else
degrees=s(end).Orientation+180;
end
if (0<degrees)&&(degrees<89.99) && state==2
degrees=degrees+180;
elseif (90<degrees) && (degrees<179) && state==1
degrees=degrees+180;
end
fprintf('The orientation is %g degrees\n',degrees)
Update 2:
Now I have another problem: I need to know somehow whether the camera is seeing the whole target or only the small circle+triangle. I need this before computing the orientation.
I have tried many options. For example, I wanted to count the number of circles, so if there are 2, it is seeing the big target, and if there is 1, just the small one. But they are not well detected. Even if I play with the sensitivity, it's not going to be a robust method.
Image: https://www.dropbox.com/s/7mbpna3xfquq5n7/P0016.bmp?dl=0
Classifer: https://www.dropbox.com/s/236vm3romw56983/Cascade1Matlab.xml?dl=0
im=imread('P0016.bmp');
detector = vision.CascadeObjectDetector('Cascade1Matlab.xml');
bbox = step(detector, im); % Detect the target.
detectedImg = insertObjectAnnotation(im, 'rectangle', bbox, 'target'); % Insert bounding boxes and return marked image.
imshow(detectedImg)
BW=rgb2gray(im);
BW=imcrop(BW,bbox(1,:) +[0 0 10 10]);
[imH,imW]=size(im);
centers = imfindcircles(im,[1 round(imH)]);
figure;hold on;
imshow(im);
plot(centers(:,1),centers(:,2),'r*','LineWidth',4)
I also tried with other approaches such as the Euler number, but with no success, I can't find anything that works properly.
I think the easiest and fastest way would be finding your target and binarize the image. Afterwards use regionprops() and read the "Orientation" property to read the orientation.
If you can't use that toolbox the function is very easily implement by calculating the covariance matrix of your region. Let me know if you need some tips on this.
Edit:
I just so happend to have some nicely vectorized functions around here ;) so if speed is a top priority, you can easily write your own regionprops() trimmed to the bare minimum like this:
function M=ImMoment(Image,ii,jj)
ImSize=size(Image);
K=repmat((1:ImSize(1))',1,ImSize(2)).^ii;
J=repmat(1:ImSize(2),ImSize(1),1).^jj;
M=K.*J.*Image;
M=sum(M(:));
end
for the image moments and
function [Matrix,Centroid,Angle]=CovMat(Image)
Centroid=[ImMoment(Image,0,1)/ImMoment(Image,0,0),...
ImMoment(Image,1,0)/ImMoment(Image,0,0)];
Miu20=ImMoment(Image,0,2)/ImMoment(Image,0,0)-Centroid(1)^2;
Miu02=ImMoment(Image,2,0)/ImMoment(Image,0,0)-Centroid(2)^2;
Miu11=ImMoment(Image,1,1)/ImMoment(Image,0,0)-Centroid(1)*Centroid(2);
Matrix=[Miu20,Miu11 %Covariance Matrix in case you need it for anything...
Miu11,Miu02];
Angle=1/2*atand(2*Miu11/(Miu20-Miu02)); %Your orientation
end
for your orientation and covariance matrix. more about it here.
Image moments are very might, have fun!
I have a very blunt solution in mind. It may work. I have not actually tried it, since there is no image to work on. So if it fails, post the error.
Assumptions:- You have filtered the image and obtained the binary image that contains only triangle "OR" with uniform noise.
Now you can take a 0 degree image (image1). Filter it and obtain binary image (bw1).
So when you are trying to land your quadrotor, take image (image2), convert it binary (bw2).
Now find the correlation between these two images {corr2(bw1, bw2)}. Store this in a variable.
Rotate image with a step angle. Let angle be 5 degrees. {imrotate(bw2, 5)}
Now again find correlation between these two images.
Do this for all angles.
The orientation would the angle (no. of rotation * 5) where the correlation is maximum.
The term maximum signifies that, you may not find the correlation to be 1 as this highly depends on your filtering techniques to obtain perfect binary image.
I also accept that computing the correlation for all the angles requires high computation speed as well as long time. This would be really difficult to achieve in real time if you do not have high computation speed. (In this case you can look into Parallel Computing Toolbox) specially parfor.
Hope this was useful to you. Post a comment if you face any error.
Finally good luck. Nice project.
P.S. Pad white or black pixels depending on your binary image while rotating image.

Face Detection with using Computer Vision Toolbox(Viola Jones) in Matlab

I have a final project about face detection. I decided to do this project using Matlab and the Computer Vision Toolbox because as you know, this toolbox uses Viola Jones Algorithm for object detection.
I wrote the code below but the code matches a face with the a non-face object.
Question
How can I change the code so that it matches faces only?
clear all
clc
% Read input image
I = imread('C:\imageprocessingwithMatlab\Image001.jpg');
figure,imshow(I);
%% Detect Faces in the image
% Create a detector object
faceDetector = vision.CascadeObjectDetector('FrontalFaceCART');
% Detect faces
bbox = step(faceDetector, I);
% Draw boxes around detected faces and display results
IFaces = insertObjectAnnotation(I, 'rectangle', bbox, 'Face');
figure, imshow(IFaces), title('Detected Faces');
Unfortunately, there is no guaranteed way to eliminate all false detections. However, you may be able to tweak some parameters to make the face detection work better on your particular image.
The first thing I would do is look at your false detections. If they tend to be larger or smaller than a typical face in your image, then you can try to adjust the MinSize and MaxSize parameters to get rid of them.
You can also try to use a different model, i. e. 'FrontalFaceLBP' instead of 'FrontalFaceCART'.
If that doesn't work, you can try a more clever trick. First detect the upper bodies of people using the 'UpperBody' classification model. Then detect the faces, and only keep the faces that are contained within upper bodies. This is likely to cut down on false detections, but you are also running a risk of missing real faces.
Finally, you can train your own face detector using the trainCascadeObjectDetector function. But that is definitely beyond the scope of your project.