Overlay png image with transparent regions on another image in MATLAB - matlab

I have a set of 450 jpg images, each approximately 1200x1500 pixels. I want to apply a black border to every image to make them all 1500x1500 pixels.
Here is an example image: test01.jpg
And I want to turn it into as image that looks like this: 1500x1500 image with border
The way I have been trying to do it is by superimposing a png image of a black border on top of the original image. However, this hasn't worked very well :( Here's my code so far:
A = imread('test01.jpg'); %open image
A2 = imresize(A,[1500 1200]); %resize image to 1500 x 1200 just to make sure it is correct height
RA = imref2d(size(A2));
B = imread('cropper_and_outline_1500x1500.png'); %open cropper
RB = imref2d(size(B));
C = imfuse(A2,B,'blend','Scaling','joint'); %fuse images
imshow(C)
Here's my current output.
There are a few errors... a) the black border is not opaque, b) transparent colour is set to green not transparent, c) the two images are aligned at the top-left corner but I need them centre aligned.
I have been playing with the alpha level to try and fix the green but I didn't really understand what it meant so didn't get far! I also know this might not be the simplest way to do it so if anyone has any other ideas I would really love to hear them. I am trying to do this in MATLAB because I already have a script for renaming the files and I would ideally like to combine both into a single script.
Thanks a lot!

Why not just add black lines to the original image?
I = imread(yourfile);
expectedSize = [1500, 1500];
% Add horizontal lines of pixels (if needed)
line1 = zeros(1, size(I, 2));
Im = [repmat(line1, [(expectedSize(1) - size(I, 1))/2, 1, 3]); ... % add lines on top
I; ...
repmat(line1, [(expectedSize(1) - size(I, 1))/2, 1, 3])]; % add lines on the bottom
% Add vertical lines of pixels (if needed)
line2 = zeros(size(Im, 1), 1);
Im = [repmat(line2, [1, (expectedSize(2) - size(Im, 2))/2, 3]), ... % add lines to the left
Im, ....
repmat(line2, [1, (expectedSize(2) - size(I, 2))/2]), 3]; % add lines to the right
Well, this was done assuming that the result of expectedSize(i) - size(I, i) is divisible by 2, but you get the idea...

Related

Getting the coordinates of vertices of an A4 sheet with coins on it, for its further projective transformation and coin detection

I need to transform my tilted image in a way I can find coins on an A4 paper. So far, I have been getting four coordinates of edges of my paper by manually selecting them with ginput.
targetImageData = imread('coin1.jpg');
imshow(targetImageData);
fprintf('Corner selection must be clockwise or anti-clockwise.\n');
[X,Y] = ginput(4);
Is there a way to automate this process, say, apply some edge detector and then find coordinates of each vertex and then pass them as the coordinates needed for transformation?
Manual selection:
Result:
You can try using detectHarrisFeatures on the S color channel of HSV color space:
I was looking for a color space that gets maximum contrast of the paper.
It looks like the saturation color channel of HSV makes a good contrast between the paper and the background.
Image is resized the image by a factor of 0.25, for removing noise.
detectHarrisFeatures finds the 4 corners of the paper, but it might not be robust enough.
You may need to find more features, and find the 4 correct features, using some logic.
Here is a code sample:
%Read input image
I = imread('im.png');
%Remove the margins, and replace them using padding (just because the image is a MATLAB figure)
I = padarray(I(11:end-10, 18:end-17, :), [10, 17], 'both', 'replicate');
HSV = rgb2hsv(I);
%H = HSV(:, :, 1);%figure;imshow(H);title('H');
S = HSV(:, :, 2);%figure;imshow(S);title('S');
%V = HSV(:, :, 3);%figure;imshow(V);title('V');
%Reduce image size by a factor of 0.25 in each axis
S = imresize(S, 0.25);
%S = imclose(S, ones(3)); %May be requiered
%Detect corners
corners = detectHarrisFeatures(S);
imshow(S); hold on;
plot(corners.selectStrongest(4));
Result:
Different approach you may try:
Take a photo without the coins.
Mark the corners manually, and extract features of the 4 corners.
Use image matching techniques to match the image with the coins with the image without the coins (mach basted on the 4 corners).

how to stretch the first left, right, top, and bottom row/column of image?

I have a satellite image and I want to show an example of multi-scale.
so what I did is, add zeros (black pixels) around the image and put the image in the centre. now how can I fill the zeros from the first left, right, top, and bottom pixel row/column?
Matlab code:
img=imread ('example.jpg');
padcam = padarray(img,[1000 1000],'both');
EDIT:
Maybe it is easy explain from this image. Is this image what I want is to repeat the sea part in such a ways at the black area that it looks like we have large empty sea and small ships at the centre. That's why I have made red lines that I want to repeat/make copy/extend first left, right, top, and bottom pixel row/column so that make image at centre and black will be converted to pixels values of first left, right, top, and bottom pixel row/column.
I don't know if this is what you have meant...
Instead of fill zeros, start from the highest resolution, and place lower resolution images at the center of each other.
Here is my code sample (you may use a for loop instead):
I0 = imread('peppers.png');
I0 = padarray(I0,[16 16],'both'); %I0 - full resolution.
I1 = imresize(I0, 0.5); %I1 - half resolution.
I2 = imresize(I0, 0.25); %I2 - quarter resolution.
J = I0;
%Place I1 at the center of J.
J(1+(end-size(I1,1))/2:(end+size(I1,1))/2, 1+(end-size(I1,2))/2:(end+size(I1,2))/2, :) = I1;
%Place I2 at the center of J.
J(1+(end-size(I2,1))/2:(end+size(I2,1))/2, 1+(end-size(I2,2))/2:(end+size(I2,2))/2, :) = I2;
figure;imshow(J);
Result:
Check the following:
The example is basted on Matlab documentation of imtransform
I = imresize(imread('peppers.png'), 0.5);
A = [1, 0, 0; 0, 1, 0; 0, 0, 1];
T = maketform('affine', A);
R = makeresampler({'cubic', 'nearest'}, 'replicate');
J = imtransform(I, T, R, 'XData', [-size(I,2), size(I,2)*2], 'YData', [-size(I,1), size(I,1)*2]);
figure;imshow(J);
Result:
I think you are looking for 'replicate' padding option:
padcam = padarray(img,[1000 1000],'both', 'replicate');
resulting with:
If you are looking for smoother result, consider using regionfill.

How to remove horizontal and vertical lines

I need to remove horizontal and vertical lines in a binary image. Is there any method for filtering these lines? bwareaopen() is not good method to remove these lines and also Dilation and Erosion are not good for these cases.
Does any one know a solution?
Example image:
EDIT:(added more example images:
http://s1.upload7.ir/downloads/pPqTDnmsmjHUGTEpbwnksf3uUkzncDwr/example%202.png
source file of images:
https://www.dropbox.com/sh/tamcdqk244ktoyp/AAAuxkmYgBkB8erNS9SajkGVa?dl=0
www.directexe.com/9cg/pics.rar
Use regionprops and remove regions with high eccentricity (meaning the region is long and thin) and orientation near 0 or near 90 degrees (regions which are vertical or horizontal).
Code:
img = im2double(rgb2gray(imread('removelines.jpg')));
mask = ~im2bw(img);
rp = regionprops(mask, 'PixelIdxList', 'Eccentricity', 'Orientation');
% Get high eccentricity and orientations at 90 and 0 degrees
rp = rp([rp.Eccentricity] > 0.95 & (abs([rp.Orientation]) < 2 | abs([rp.Orientation]) > 88));
mask(vertcat(rp.PixelIdxList)) = false;
imshow(mask);
Output:
If all of your images are the same where the horizontal and vertical lines are touching the border, a simple call to imclearborder will do the trick. imclearborder removes any object pixels that are touching the borders of the image. You'll need to invert the image so that the characters are white and the background is dark, then reinvert back, but I'm assuming that isn't an issue. However, to be sure that none of the actual characters get removed because they may also be touching the border, it may be prudent to artificially pad the top border of the image with a single pixel thickness, clear the border, then recrop.
im = imread('http://i.stack.imgur.com/L1hUa.jpg'); %// Read image directly from StackOverflow
im = ~im2bw(im); %// Convert to black and white and invert
im_pad = zeros(size(im,1)+1, size(im,2)) == 1; %// Pad the image too with a single pixel border
im_pad(2:end,:) = im;
out = ~imclearborder(im_pad); %// Clear border pixels then reinvert
out = out(2:end,:); %// Crop out padded pixels
imshow(out); %// Show image
We get this:
You can firstly find the horizontal and vertical lines. Since, the edge map will also be binary so you can perform a logical subtraction operation in between the images. To find vertical lines, you can use (in MATLAB)
BW = edge(I,'sobel','vertical');
For horizontal lines, you can use
% Generate horizontal edge emphasis kernel
h = fspecial('sobel');
% invert kernel to detect vertical edges
h = h';
J = imfilter(I,h);

Can we rotate an image in MATLAB filled with background color of original image?

By default, MATLAB function imrotate rotate image with black color filled in rotated portion. See this, http://in.mathworks.com/help/examples/images_product/RotationFitgeotransExample_02.png
We can have rotated image with white background also.
Question is, Can we rotate an image (with or without using imrotate) filled with background of original image?
Specific to my problem: Colored image with very small angle of rotation (<=5 deg.)
Here's a naive approach, where we simply apply the same rotation to a mask and take only the parts of the rotated image, that correspond to the transformed mask. Then we just superimpose these pixels on the original image.
I ignore possible blending on the boundary.
A = imread('cameraman.tif');
angle = 10;
T = #(I) imrotate(I,angle,'bilinear','crop');
%// Apply transformation
TA = T(A);
mask = T(ones(size(A)))==1;
A(mask) = TA(mask);
%%// Show image
imshow(A);
You can use padarray() function with 'replicate' and 'both' option to interpolate your image. Then you can use imrotate() function.
In the code below, I've used ceil(size(im)/2) as pad size; but you may want bigger pad size to eliminate the black part. Also I've used s and S( writing imR(S(1)-s(1):S(1)+s(1), S(2)-s(2):S(2)+s(2), :)) to crop the image where you can extract bigger part of image just expanding boundary of index I used below for imR.
Try this:
im = imread('cameraman.tif'); %// You can also read a color image
s = ceil(size(im)/2);
imP = padarray(im, s(1:2), 'replicate', 'both');
imR = imrotate(imP, 45);
S = ceil(size(imR)/2);
imF = imR(S(1)-s(1):S(1)+s(1)-1, S(2)-s(2):S(2)+s(2)-1, :); %// Final form
figure,
subplot(1, 2, 1)
imshow(im);
title('Original Image')
subplot(1, 2, 2)
imshow(imF);
title('Rotated Image')
This gives the output below:
Not so good but better than black thing..

Matlab fill shapes by white

As you see, I have shapes and their white boundaries. I want to fill the shapes in white color.
The input is:
I would like to get this output:
Can anybody help me please with this code? it doesn't change the black ellipses to white.
Thanks alot :]]
I = imread('untitled4.bmp');
Ibw = im2bw(I);
CC = bwconncomp(Ibw); %Ibw is my binary image
stats = regionprops(CC,'pixellist');
% pass all over the stats
for i=1:length(stats),
size = length(stats(i).PixelList);
% check only the relevant stats (the black ellipses)
if size >150 && size < 600
% fill the black pixel by white
x = round(mean(stats(i).PixelList(:,2)));
y = round(mean(stats(i).PixelList(:,1)));
Ibw = imfill(Ibw, [x, y]);
end;
end;
imshow(Ibw);
Your code can be improved and simplified as follows. First, negating Ibw and using BWCONNCOMP to find 4-connected components will give you indices for each black region. Second, sorting the connected regions by the number of pixels in them and choosing all but the largest two will give you indices for all the smaller circular regions. Finally, the linear indices of these smaller regions can be collected and used to fill in the regions with white. Here's the code (quite a bit shorter and not requiring any loops):
I = imread('untitled4.bmp');
Ibw = im2bw(I);
CC = bwconncomp(~Ibw, 4);
[~, sortIndex] = sort(cellfun('prodofsize', CC.PixelIdxList));
Ifilled = Ibw;
Ifilled(vertcat(CC.PixelIdxList{sortIndex(1:end-2)})) = true;
imshow(Ifilled);
And here's the resulting image:
If your images are all black&white, and you have the image processing toolkit, then this looks like what you need:
http://www.mathworks.co.uk/help/toolbox/images/ref/imfill.html
Something like:
imfill(image, [startX, startY])
where startX, startY is a pixel in the area that you want to fill.