error in MATLAB regarding dimensions mismatch - image

Actually i am trying to implement the code on the following website http://www.mathworks.com/matlabcentral/fileexchange/28300 but this works only when two images given have the same dimensions , i want to make this code work where one image has some dimension and other has some other dimension, if i do this with current code, it gives the error
??? Sub scripted assignment dimension mismatch. Error in ==> example2 at 27
Line 27:
I(:,1:size(I1,2),:)=I1; I(:,size(I1,2)+1:size(I1,2)+size(I2,2),:)=I2;
can you resolve this for me?

You can try padding the smaller image with zeros so that is has the same dimensions as the larger image. For example
%Start with rows:
if size(I1,1) > size(I2,1) %I1 has more rows so pad I2
pad = zeros (size(I1,1) - size(I2,1), size(I2,2));
I2 = [I2 ; pad]; %Append the rows of zeros to the bottom of I2
else %I2 has more rows so pad I1
pad = zeros (size(I2,1) - size(I1,1), size(I1,2));
I1 = [I1 ; pad]; %Append the rows of zeros to the bottom of I1
%Pad the columns
if size(I1,2) > size(I2,2) %I1 has more rows so pad I2
pad = zeros (size(I2,1), size(I1,2) - size(I2,2));
I2 = [I2 , pad]; %Append the columns of zeros to the left of I2
else %I2 has more rows so pad I1
pad = zeros (size(I1,1), size(I2,2) - size(I1,2));
I1 = [I1 , pad]; %Append the columns of zeros to the left of I1
I haven't tested that though so you might need to fiddle a bit to get the dimension perfect, like maybe size(I2,2) - size(I1,2) + 1 instead of size(I2,2) - size(I1,2), that sort of thing.
But you need to first figure out the logic of what you are trying to do. Padding with zeros might not make sense in your application. Also my code pads on the bottom and the left but you might want to pad all the way around so your image is in the centre of the new image.

Related

matlab - Find a bounding box which can cover a character in image

An image represents a Korean character. All values of the image are composed of 0 or 255.
Then I wanna get a bounding box which can perfectly cover the character in the image.
For example:
Input image
Output image(What I want is to get the vertices of the red box.)
I have an idea to do this but I think that is not good:
Step 1. Find the leftmost and uppermost index in the image, say (l, up)
Step 2. Find the rightmost and lowermost index in the image, say (r, low)
Step 3. Then the square(bounding box) whose one of vertices is (l, up) and (r, low) can cover a character in an image.
Is there a good idea or matlab library for this?
Even without the Matlab image processing toolbox, you could extract the left,right,top,bottom boundary indices of the input image using find.
Assuming the image is a binary matrix (logical 1 or 0) called "input":
leftBoundary = find(input,1,'first');
rightBoundary = find(input,1,'last');
topBoundary = find(input',1,'first');
BotBoundary = find(input',1,'last');
Keep in mind these are linear indices. You can use other summoning methods of find to get normal subscripts if needed
[row,col] = find(___)
You can accomplish this by using the function any to find logical indices for the rows and columns that contain any part of your character, then find to get the row and column indices of the extremities:
img = imread('Y2ZIW.png'); % Load RGB image you posted
bw = ~im2bw(img); % Convert to binary and negate
rowIndex = any(bw, 2); % N-by-1 logical index for rows
colIndex = any(bw, 1); % 1-by-N logical index for columns
boundBox = [find(colIndex, 1, 'first') find(rowIndex, 1, 'first'); ...
find(colIndex, 1, 'last') find(rowIndex, 1, 'last')];
This gives us the following 2-by-2 matrix for boundBox, which we can use as indices into your image to crop just the region containing the character:
boundBox =
71 57 % Left and upper corner index
214 180 % Right and lower corner index
subRegion = bw(boundBox(1, 2):boundBox(2, 2), boundBox(1, 1):boundBox(2, 1));
imshow(subRegion);
And here's the plot of the cropped region:
If you want a minimum one-pixel border around your cropped region, you can modify the calculation for boundBox like so:
boundBox = [find(colIndex, 1, 'first')-1 find(rowIndex, 1, 'first')-1; ...
find(colIndex, 1, 'last')+1 find(rowIndex, 1, 'last')+1];
I1 = imread('Y2ZIW.png') ;
I = rgb2gray(I1) ;
[y,x] = find(I==0) ;
%% Bounding box
x0 = min(x) ; x1 = max(x) ;
y0 = min(y) ; y1 = max(y) ;
B = abs(x1-x0) ;
L = abs(y1-y0) ;
BB = [x0 y0 ; x0 y0+L ; x0+B y0+L ; x0+B y0 ; x0 y0] ;
imshow(I1) ;
hold on
plot(BB(:,1),BB(:,2),'r')

Histogram of an image but without considering the first k pixels

I would like to create a histogram of an image but without considering the first k pixels.
Eg: 50x70 image and k = 40, the histogram is calculated on the last 3460 pixels. The first 40 pixels of the image are ignored.
The order to scan the k pixels is a raster scan order (starting from the top left and proceeds by lines).
Another example is this, where k=3:
Obviously I can't assign a value to those k pixels otherwise the histogram would be incorrect.
Honestly I have no idea how to start.
How can I do that?
Thanks so much
The vectorized solution to your problem would be
function [trimmedHist]=histKtoEnd(image,k)
imageVec=reshape(image.',[],1); % Transform the image into a vector. Note that the image has to be transposed in order to achieve the correct order for your counting
imageWithoutKPixels=imageVec(k+1:end); % Create vector without first k pixels
trimmedHist=accumarray(imageWithoutKPixels,1); % Create the histogram using accumarray
If you got that function on your workingdirectory you can use
image=randi(4,4,4)
k=6;
trimmedHistogram=histKtoEnd(image,k)
to try it.
EDIT: If you just need the plot you can also use histogram(imageWithoutKPixels) in the 4th row of the function I wrote
One of the way can be this:
histogram = zeros(1,256);
skipcount = 0;
for i = 1:size(image,1)
for j = 1:size(image,2)
skipcount = skipcount + 1;
if (skipcount > 40)
histogram(1,image(i,j)+1) = histogram(1,image(i,j)+1) + 1;
end
end
end
If you need to skip some exact number of top lines, then you can skip the costly conditional check and just start the outer loop from appropriate index.
Vec = image(:).';
Vec = Vec(k+1:end);
Hist = zeros(1, 256);
for i=0:255
grayI = (Vec == i);
Hist(1, i+1) = sum(grayI(:));
end
First two lines drop the first k pixels so they are not considered in the computation.
Then you check how many 0's you have and save it in the array. The same for all gray levels.
In the hist vector, in the i-th cell you will have the number of occurance of gray level (i-1).

Inpaint an image matlab [duplicate]

This question already has an answer here:
Efficient inpaint with neighbouring pixels
(1 answer)
Closed 6 years ago.
I am trying to replace all pixels with certain value in an image with the average values of the neighbors. Can interp2 be useful here? I tried this -
I = imread('test_image.JPG');
[r c] = size(I);
class_of_image = class(I);
[xi,yi] = meshgrid(1:0.5:c,1:0.5:r);
I1 = cast(interp2(double(image),xi,yi,'linear'),class_of_image);
[x_z,y_z] = find(I1==0);
I1(x_z,y_z) = I1(x_z-1,y_z)+I1(x_z+1,y_z)+I1(x_z,y_z-1)+I1(x_z,y_z+1);
This fails spectacularly with an error message - Index exceeds matrix dimensions.
I realize that the error is in trying to access I1 indices beyond r and c. Is there a generic way to incorporate this in the code?
Please help!
If you are trying to replace pixels in an image that are at a certain value to be the average of its 4 neighbours, then you don't have to use interp2. It looks like you are doubling the size of the image and then sampling from that image when you're done.
If you want to do what you're asking, you need to use column-major indices to facilitate the vectorized access of pixels. Specifically, you need to use sub2ind to help determine the locations you need to access in your matrix.
However, you will need to account for pixels that go out of bounds. There are many ways to accommodate this, but what I will implement is known as zero-padding where the border pixels are simply set to 0. I would create a zero-padded image where the top and bottom rows as well as the left and right values are all some sentinel value (like -1), use find on this image to find the coordinates then do the inpainting. Make sure you set the border pixels back to 0 before doing this so that you don't use -1 as part of the inpainting. You would then crop the border pixels of this new image when you're done to obtain the final output image.
Therefore, if you want to perform your "inpainting" try this instead:
% Read in image
I = imread('test_image.JPG');
% Create padded image with border pixels set to -1
Ipad = -ones(size(I) + 2);
% Place image in the middle
Ipad(2:end-1,2:end-1) = I;
% Find zero pixels
[r,c] = find(I == 0);
% Now set border pixels to 0
Ipad(Ipad == -1) = 0;
% Find column major indices for those elements that are 0
% as well as their 4 neighbours
ind = sub2ind(size(I), r, c);
ind_up = sub2ind(size(I), r-1, c);
ind_down = sub2ind(size(I), r+1, c);
ind_left = sub2ind(size(I), r, c-1);
ind_right = sub2ind(size(I), r, c+1);
% Perform the inpainting by averaging
Ipad(ind) = (Ipad(ind_up) + Ipad(ind_down) + Ipad(ind_left) + Ipad(ind_right))/4;
% Store the output in I1 after removing border pixels
I1 = Ipad(2:end-1,2:end-1);
However, a possibly shorter way to do this even though you would operate on the entire image would be to perform 2D convolution using a 3 x 3 kernel whose elements are 1 in the cardinal directions and ensuring that you divide by 4 to find the average value per location. After, you would simply copy over those values in the output that are 0 in the original image. You can use conv2 to do that and make sure you specify the 'same' flag to ensure that the output size is the same as the input size. The behaviour of conv2 when you approach the border elements is to zero-pad, which is what I did already in the first implementation:
% Read in image
I = imread('test_image.JPG');
% Specify kernel
kernel = [0 1 0; 1 0 1; 0 1 0] / 4;
% Perform convolution - make sure you cast image to double
% as convolution in 2D only works for floating-point types
out = conv2(double(I), kernel, 'same');
% Copy over those values from the output that match the value
% to be inpainted for the input. Also cast back to original
% data type.
I1 = I;
I1(I == 0) = cast(out(I == 0), class(I));

Matlab- Improve code in image cropping black border

I have this code that crop the black borders in my picture.
I don't know why the border still exists.
I1=im2double(imread('dart.jpg'));
sizeI = size(I1);
zeros = floor((sizeI(2) - min(sum(any(I1))))/2);
I2 = I1(:, zeros : sizeI(2)-zeros, :);
nonZero = sum(any(I1,2));
sizeI2 = size(I2);
zerosRows = floor((sizeI(1) - min(sum(any(I2, 2))))/2);
I3 = I2(zerosRows : sizeI2(1)-zerosRows, :, :);
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I3);title('Figure 3');
How can I change this code ?
This code works for me, assuming that your black border pixels are all zero. Should there be non-zero pixels in the black borders of your image (probably due to quantization and compression artifacts - your image is JPEG after all...), then this code will not work. What this code is doing is checking all of the columns first to see if there are any non-zero pixels. It then figures out where to crop by determining the first non-zero column and going to the last non-zero column. This code also assumes that the non-zero columns are symmetric, which is why you're dividing by 2 in your zeros statement. By the way, zeros is a built-in function in MATLAB. I don't recommend you create a variable that has this name, as your later code may require this function and you are unintentionally shadowing over this function with a variable.
Nevertheless, here's what I did to test to see if your code works. I used a built-in image from MATLAB's system path cameraman.tif, and created a 10 pixel border surrounding the image. I then ran your code to see what I would get:
im = imread('cameraman.tif');
I1 = padarray(im2double(im), [10 10]);
Running your code, this is the figure I get:
There exist certain preconditions when running that code so bear this in mind before using it:
This assumes an entirely symmetric black border around the image.
This assumes that all black border pixels are zero.
If your border has non-zero pixels, even though it may visually look like there are non-zero pixels, then this code will not work.
As such, I suggest you threshold your image by a small amount (perhaps intensity 10) to ensure that the borders are zero before you proceed. You would then use this image to calculate how many border pixels you have. As such, do something like this.
I1=im2double(imread('dart.jpg')); %// Read in the image
I1thresh = I1 >= (10/255); %// As an example - Note the division by 255 as you did im2double
sizeI = size(I1);
zeros = floor((sizeI(2) - min(sum(any(I1thresh))))/2); %// Note the change in any
I2 = I1(:, zeros : sizeI(2)-zeros, :);
I2thresh = I1thresh(:, zeros : sizeI(2)-zeros, :); % // Note new variable
nonZero = sum(any(I1thresh,2)); %// Note the change in any
sizeI2 = size(I2);
zerosRows = floor((sizeI(1) - min(sum(any(I2thresh, 2))))/2); %// Note change in any
I3 = I2(zerosRows : sizeI2(1)-zerosRows, :, :);
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I3);title('Figure 3');
Edit - Non-uniform black borders
From your comments, you have said that your black borders may not be symmetric. In that case, you need to have logic that determines the beginning of where the black borders are to where the end of the black borders are. You apply this for both the rows and the columns of the black borders. In that case, I would use the find command, and use the any operation along the rows and columns and determine the smallest and largest indices where the rows and columns are non-zero. This exactly corresponds to the minimum and maximum operations in MATLAB with respect to your code. I'm going to use the modified algorithm with thresholding to circumvent any quantization or compression artifacts. As such:
I1=im2double(imread('dart.jpg')); %// Read in the image
I1thresh = I1 >= (10/255); %// As an example - Note the division by 255 as you did im2double
%// Removed as this is no longer needed
%// sizeI = size(I1);
nonZeroCols = find(any(I1thresh)); %// Change
minCol = min(nonZeroCols); %// Change
maxCol = max(nonZeroCols); %// Change
I2 = I1(:, minCol : maxCol, :);
I2thresh = I1thresh(:, minCol : maxCol, :); % // Note new variable
%// Commented out. Don't see this being used anywhere
%//nonZero = sum(any(I1thresh,2)); %// Note the change in any
%// Removed as this is no longer needed
%//sizeI2 = size(I2);
nonZeroRows = find(any(I2thresh, 2)); %// Change
minRow = min(nonZeroRows); %// Change
maxRow = max(nonZeroRows); %// Change
I3 = I2(minRow : maxRow, :, :); %// Change
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I3);title('Figure 3');
The above code should now work for any size black border.

How to ignore Black border in MATLAB

i make some compare between 2 very similar images , (by code RANSAC) and after it i rotate one of the images to the angle of the first image .
the problem is that in some images you have a black border, that Distorted the compere and the rotate
how i make that the compere will be only on the image without black border (ignore it)?
function [ output_args ] = ransac( )
%frames( filename)
global numFrames
a=sprintf('Ransac begin');
disp(a);
for i=1:numFrames
file_name = sprintf('frames/%0.3i.jpg', i);
file_name2 = sprintf('frames/%0.3i.jpg', i+1);
%file_name = sprintf('frames/008.jpg', i);
%file_name2 = sprintf('frames/049.jpg', i+1);
I1=im2double(imread(file_name2));
I2=im2double(imread(file_name));
% Get the Key Points
Options.upright=true;
Options.tresh=0.0001;
Ipts1=OpenSurf(I1,Options);
Ipts2=OpenSurf(I2,Options);
% Put the landmark descriptors in a matrix
D1 = reshape([Ipts1.descriptor],64,[]);
D2 = reshape([Ipts2.descriptor],64,[]);
% Find the best matches
err=zeros(1,length(Ipts1));
cor1=1:length(Ipts1);
cor2=zeros(1,length(Ipts1));
for i=1:length(Ipts1),
distance=sum((D2-repmat(D1(:,i),[1 length(Ipts2)])).^2,1);
[err(i),cor2(i)]=min(distance);
end
% Sort matches on vector distance
[err, ind]=sort(err);
cor1=cor1(ind);
cor2=cor2(ind);
% Make vectors with the coordinates of the best matches
Pos1=[[Ipts1(cor1).y]',[Ipts1(cor1).x]'];
Pos2=[[Ipts2(cor2).y]',[Ipts2(cor2).x]'];
Pos1=Pos1(1:30,:);
Pos2=Pos2(1:30,:);
% Show both images
I = zeros([size(I1,1) size(I1,2)*2 size(I1,3)]);
I(:,1:size(I1,2),:)=I1; I(:,size(I1,2)+1:size(I1,2)+size(I2,2),:)=I2;
% Calculate affine matrix
Pos1(:,3)=1; Pos2(:,3)=1;
M=Pos1'/Pos2';
% Add subfunctions to Matlab Search path
functionname='OpenSurf.m';
functiondir=which(functionname);
functiondir=functiondir(1:end-length(functionname));
addpath([functiondir '/WarpFunctions'])
% Warp the image
I1_warped=affine_warp(I1,M,'bicubic');
% Show the result
%figure,
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I1_warped);title('Warped Figure 1');
imwrite(I1_warped,file_name2);
if (mod(i,20)==0 )
disp(sprintf('he make a %d',i));
end
end
sprintf('finish');
aaa();
end
Count black columns - this question. Just remove column if
there is not any non-zero pixels.
Do the same trick with rows.
Do what your need with the rest.
This will fail if black borders are not really black - for example, very dark gray. In this case apply threshold on detecting black.
Also it will be bad solution if there are any black columns in the main part of this picture. In this case you should check position of the black column and remove only columns relatively close to borders.
Here is simple version of deleting symmetric black box without black rows inside the epic
I1=im2double(imread('dart.jpg'));
sizeI = size(I1);
zeros = floor((sizeI(2) - min(sum(any(I1))))/2);
I2 = I1(:, zeros : sizeI(2)-zeros, :);
nonZero = sum(any(I1,2));
sizeI2 = size(I2);
zerosRows = floor((sizeI(1) - min(sum(any(I2, 2))))/2);
I3 = I2(zerosRows : sizeI2(1)-zerosRows, :, :);
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I3);title('Figure 3');
Applied to "good" input:
Applied to image with inner black lines - not so good result.
In case you need precise detecting here is a plan:
Check columns from the most left to the first with color and
remove all black.
Check columns from the most right backwards to the last with color and remove black
Do the same with rows.
I will not provide code for this one because it's just some matrix operations OP can do by himself.

Resources