I am writing a Matlab program to segment an image and then put a bounding box around the segmented image. My code was previously working, however I am now getting the error:
Error using rectangle
Value must be a 4 element vector
The array in question is BoundingBox created by regionprops, which should contain only four elements, however is for some reason containing more. Here is my code (the defaultSegment function returns a binary image):
function [ boundImage ] = boundSegment( input_image )
image = defaultSegment(input_image);
clear s;
s = regionprops(image, 'Area', 'BoundingBox');
numObj = numel(s);
index = 1;
for k = 1: numObj-1
if s(k+1).Area > s(index).Area
index = k+1;
else
index = index;
end
end
figure, imshow(input_image);
rectangle('Position',s(index).BoundingBox);
boundImage = null;
(I would actually prefer if my code could could directly put the bounding box on the image instead of subplotting it, but I haven't found a way to do that without the vision toolbox)
Thanks!
I suspect that image has more than two dimensions. Check that using size(image). BoundingBox will have four elements only if image has two dimensions. From Matlab's regionprops help:
'BoundingBox' — The smallest rectangle containing the region, a 1-by-Q *2 vector, where Q is the number of image dimensions: ndims(L), ndims(BW), or numel(CC.ImageSize).
The reason an image would have a third dimension is for multiple color channels. If you want to convert to grayscale for processing, use rgb2gray.
Continuing #shoelzer's answer regarding image with three channels,
I suspect you get color image because of your segmentation algorithm (defaultSegment) that paints each segment in a different color. try rgb2ind to convert image to a segmentation label 2D matrix
Related
As the title says, the output I’m getting out of this function is incorrect. By incorrect I mean that the data are overflowing. How do I normalise the matrix correctly? Currently almost all of the pictures I get are white.
I called the function from another MATLAB file like this:
mask = [3,10,3;0,0,0;-3,-10,-3];
A = imread(“football.jpg”);
B = ConvFun(A,mask);
function [ image ] = ConvFun( img,matrix )
[rows,cols] = size(img); %// Change
%// New - Create a padded matrix that is the same class as the input
new_img = zeros(rows+2,cols+2);
new_img = cast(new_img, class(img));
%// New - Place original image in padded result
new_img(2:end-1,2:end-1) = img;
%// Also create new output image the same size as the padded result
image = zeros(size(new_img));
image = cast(image, class(img));
for i=2:1:rows+1 %// Change
for j=2:1:cols+1 %// Change
value=0;
for g=-1:1:1
for l=-1:1:1
value=value+new_img(i+g,j+l)*matrix(g+2,l+2); %// Change
end
end
image(i,j)=value;
end
end
%// Change
%// Crop the image and remove the extra border pixels
image = image(2:end-1,2:end-1);
imshow(image)
end
In a convolution, if you want the pixel value to stay in the same range
, you need to make the mask add up to 1. Just divide the mask by sum(mask(:)) after defining it. This is however, not the case you are dealing with.
Sometimes that is not the needed. For example if you are doing edge detection (like the kernel you show), you don't really care about maintaining the pixel values. In those cases, the plotting of unnormalized images is more the problem. You can always set the imshow function to auto select display range: imshow(image,[]).
Also, I hope this is homework, as this is the absolutely worst way to code convolution. FFT based convolution is about 100 times faster generally, and MATLAB has an inbuilt for it.
I have been assigned recently a task related to image processing. The thing is that I have no prior experience to this subject so I face some difficulties.
The concept is to create a 3D image from a 2D image by initially extracting the R,G,B components and combine them after shifting the red one according to some sort of a formula (i.e. calculate the pixel which has to be shifted by applying the formula a = x(i,j,k)*40/max(Rcomponent(:)) to each element of the red image and replace element x(i,j-a,k) by the value of x(i,j,k)).
Here is my current progress:
original = imread(nameofimag); % read file
imaginfos = imfinfo(nameofimag); % identify colortype
coltype = imaginfos(1).ColorType;
truecol = 'truecolor';
if strcmp(coltype,truecol) == 1 % convert to grayscale if needed
originalgray = rgb2gray(original);
else
originalgray = original;
end
Z = zeros(size(originalgray,1),size(originalgray,2));
% create red, blue, green parts
imagR = cat(3,originalgray,Z,Z);
imagG = cat(3,Z,originalgray,Z);
imagB = cat(3,Z,Z,originalgray);
imagRshifted = zeros(size(originalgray,1),size(originalgray,2));
h = waitbar(0,'Please wait...');
% shift red image
for i = 1:size(imagR,1)
for j = 1:size(imagR,2)
for k = 1:size(imagR,3)
imagRshifted(i,j,k) = imagR(i,j,k);
pixeltochange = round((imagRshifted(i,j,k)*40)...
/max(original(:)));
if pixeltochange < j
imagRshifted(i,j-pixeltochange,k) =...
imagRshifted(i,j,k);
end
end
end
waitbar(i/size(imagR,1));
end
imagRshifted = uint8(imagRshifted);
% combine R,G,B to create 3D image
imag3D = imfuse(imagRshifted,imfuse(imagG,imagB));
% plot the desired images
if depictrgb == 0;
figure;imshow(imag3D);
else
figure;imshow(imag3D);
figure;imshow(imagR);
figure;imshow(imagB);
figure;imshow(imagG);
end
close(h);
end
As you can see the result is quite confusing (at least to me). At first there is a line splitting the final image in two parts (it seems like the formula has been applied only on the left part of the line leaving the right part untouched). Additionally the produced image is more like a reconstruction of random pixels rather than a combination of the R,G,B components.
Any ideas would be more than appreciated.
Thank you in advance.
My friend, you have 2 main problems: You don't know exactly what you are doing and you are using Matlab extremely inefficiently.
So lets go to what you need, and how to do it.
You described your problem relatively OK. Lets re-describe it.
Starting from a grayscale image, create a color image with the red channel shifted by an amount given by the following equation: shift = x_ij*40/max(x(:)) .
There are missing things here, like: what to do if the shift goes out of the image? In this case we will assume that if the shift is too big, then make it zero.
lets start: First we are going to load an image, and if it is not grayscale, convert it to grayscale. I am using the following image:
% // same as you had
nameofimag='https://2.bp.blogspot.com/-db3zQg7geYA/UYqnvBriBeI/AAAAAAAAAHo/cv3Dy40mUFo/s1600/Meteosat_grid.jpg'
original = imread(nameofimag); % read file
imaginfos = imfinfo(nameofimag); % identify colortype
coltype = imaginfos(1).ColorType;
truecol = 'truecolor';
if strcmp(coltype,truecol) == 1 % convert to grayscale if needed
originalgray = rgb2gray(original);
else
originalgray = original;
end
Now we want to compute the shift per pixel we can do that in one line:
% compute shifts
shift=-round( double(originalgray) *40./double(max(originalgray(:))));
And we want to make sure that we don't go over the iamge, so we will compute the actual index (indY+shift) and check if that's inside the image
% get indexes
[indY,~]=meshgrid(1:size(originalgray,2),1:size(originalgray,1));
% Make sure we dont go out of the image
shift(indY+shift<=0)=0;
Now we have a proper shift, that we know its not going out. Realize, shift is a matrix size(image), thus we have all we need.
Now, lets take the R channel and shift it. Realize, that the image is grayscale, thus R G and B are exactyl equal. we will then shift the original image.
% allocate memory
redshifted = zeros(size(originalgray,1),size(originalgray,2));
% actually shift red
for ii=1:size(originalgray,1)
redshifted(ii,:)=originalgray(ii,indY(ii,:)+shift(ii,:));
end
Now that we have the red shifted, lets create a new image, that has RGB values, where GB are the original image and R the shifted image
colorImg=cat(3,redshifted,originalgray,originalgray);
imshow(colorImg)
This gives:
Conclusion: This code applies the shift to a grayscale image (or truecolor converted to grayscale) and generates a color image with the red shifted. Modifications need to be done if the original image is actually truecolor without the grayscale conversion, but these modifications will be minor, and mainly relate to changing originalgray in different places to proper RGB chanel access (e.g. original(:,:,2) is G).
As a final note: Realise that this will only look good with 3D glasses if the image is a depthmap. Else, you will get weird visual effect, as the color of an image has nothing to do with the depth of it (thus displacement of red)
I'm trying to read the values in this image into variables using OCR in MATLAB. I'm having trouble doing so, so I tried to split up this image into smaller parts using the white boundary lines then trying to read it, but I dont know how to do this. Any help would be appreciated, thanks.
If the blocks are always delimited by a completely vertical line, you can find where they are by comparing the original image (here transformed from RGB to grayscale to be a single plane) to a matrix that is made of repeats of the first row of the original image only. Since the lines are vertical the intensity of the pixels in the first line will be the same throughout. This generates a binary mask that can be used in conjunction with a quick thresholding to reject those lines that are all black pixels in every row. Then invert this mask and use regionprops to locate the bounding box of each region. Then you can pull these out and do what you like.
If the lines dividing the blocks of text are not always vertical or constant intensity throughout then there's a bit more work that needs to be done to locate the dividing lines, but nothing that's impossible. Some example data would be good to have in that case, though.
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
imshow(img);
imgGray = rgb2gray(img);
imgMatch = imgGray == repmat(imgGray(1,:), size(imgGray, 1), 1);
whiteLines = imgMatch & (imgGray > 0);
boxes = regionprops(~whiteLines, 'BoundingBox');
for k = 1:6
subplot(3,2,k)
boxHere = round(boxes(k).BoundingBox);
imshow(img(boxHere(2):(boxHere(2)+boxHere(4)-1), boxHere(1):(boxHere(1)+boxHere(3)-1), :));
end
You can sum along the columns of a binary image corresponding to that input image and find peaks from the sum values. This is precisely achieved in the code here -
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
BW = im2bw(img,0.1); %// convert to a binary image with a low threshold
peak_sum_max = 30; %// max of sum of cols to act as threshold to decide as peak
peaks_min_width = 10; %// min distance between peaks i.e. min width of each part
idx = find( sum(BW,1)>=peak_sum_max );
split_idx = [1 idx( [true diff(idx)>peaks_min_width ] )];
split_imgs = arrayfun(#(x) img(:,split_idx(x):split_idx(x+1)),...
1:numel(split_idx)-1,'Uni',0);
%// Display split images
for iter = 1:numel(split_imgs)
figure,imshow(split_imgs{iter})
end
Please note that the final output split_imgs is a cell array with each cell holding image data for each split image.
If you would like to have the split images directly without the need for messing with cell arrays, after you have split_idx, you can do this -
%// Get and display split images
for iter = 1:numel(split_idx)-1
split_img = img(:,split_idx(iter):split_idx(iter+1));
figure,imshow(split_img)
end
There is now a built-in ocr function in the Computer Vision System Toolbox.
I have an image of licence plate and the numbers is marked with black squares.
what I want is to get all the coordinates of the squares, and with it to cut them from the plate.
for example this is the original image:
and this is after marking the numbers:
any help will be greatly appreciated.
Here's one way to do it in Matlab
%# read the first image
img = imread('http://i.stack.imgur.com/s9A4m.jpg');
%# convert it to a binary image
img = rgb2gray(img);
img = img > 200;
%# remove the connecting lines
img = imclose(img,strel('disk',5));
%# use bwlabel to replace the black squares with a index (1,2,3...)
lblImg = bwlabel(~img);
%# read the second image, make it binary
img2 = imread('http://i.stack.imgur.com/PtKzw.jpg');
img2 = img2 > 200;
%# create the output - each number is now labeled with an index
out = double(~img2).*lblImg;
%# visualize all
figure,imshow(label2rgb(out,'jet','k','shuffle'))
%# extract and show label #1
firstNumber = out==1;
imshow(firstNumber);
I don't do Matlab, but I can show you how to do it in Mathematica. Hopefully you can translate!
Have a look at the image processing toolbox.
The functions bwdist, imregionalmin and bwselect should be able to get you the square coordinates.
Sketch answer as I'm in a rush. You have some white dots in the squares and some black streaks connecting the squares. Look up the morphological operations such as:
http://www.mathworks.com/help/toolbox/images/ref/imclose.html
Close the image with a small structuring element (3x3 square or similar) to get rid of the bits of noise in the squares.
Open the image with a larger structuring element (10x10 square or bigger) get rid of the connecting streaky bits.
Then use a function like bwlabel to segment/label the remaining pixels. This is a little imprecise as the squares will lose some of the structure at the edges.
How to draw a grid over an image. It should become part of that image itself.
It should be able to show some rows and columns over the image itself. The lines for rows and columns can be specified.
Actually I was encouraged by the way some research paper discusses about the results they have about image warping. One of the links is this: http://www.hammerhead.com/thad/morph.html
There are a number of related questions on SO that discuss ways to modify an image. Here are the two general approaches:
1. Modify the image data directly: I discuss this in my answer to this other SO question. Since image data can be 2-D or 3-D, you can use multidimensional indexing to modify the raw image data, creating lines along given rows and columns. Here's an example that changes every 10 rows and columns in the image to black:
img = imread('peppers.png'); %# Load a sample 3-D RGB image
img(10:10:end,:,:) = 0; %# Change every tenth row to black
img(:,10:10:end,:) = 0; %# Change every tenth column to black
imshow(img); %# Display the image
And now the image data in the variable img has black lines on it, and you can write it to a file or do whatever other processing you want to it.
2. Plot the image and the lines, then turn the axes/figure into a new image: The link to Steve Eddins' blog in zellus' answer shows an example of how you can plot an image and add lines to it. However, if you want to save or perform processing on the displayed image, you will have to save the displayed image as an image matrix. How you can do this has been discussed in these other SO questions:
How can I save an altered image in MATLAB?
Turn Matlab plot into image
Superimposing line plots on images from the blog 'Steve on Image Processing' has a nice example on overlaying a grid over an image.
Actually I watched this question after doing this code by my own .... the code reads an image and draw grid on the image every input parameter
I hope it would do any good :)
Watch the matlab code :
function [ imageMatdouble ] = GridPicture( PictureName , countForEachStep )
%This function grid the image into counts grid
pictureInfo = imfinfo(PictureName); %load information about the input
[inputImageMat, inputImageMap] = imread(PictureName); % Load the image
if (pictureInfo.ColorType~='truecolor')
warning('The function works only with RGB (TrueColor) picture');
return
end
%1. convert from trueColor(RGB) to intensity (grayscale)
imageMat = rgb2gray(inputImageMat);
%2. Convert image to double precision.
imageMatdouble =im2double(imageMat);
% zero is create indicated to black
height = pictureInfo.Height ;
width = pictureInfo.Width
i=1;j=1;
while (i<=height )
for j=1:width
imageMatdouble(i,j)=1;
end
j=1;
if (i==1)
i=i+countForEachStep-1;
else
i=i+countForEachStep;
end
end
i=1;j=1;
while (i<=width )
for j=1:height
imageMatdouble(j,i)=1;
end
j=1;
if (i==1)
i=i+countForEachStep-1;
else
i=i+countForEachStep;
end
end
imwrite(imageMatdouble,'C:\Users\Shahar\Documents\MATLAB\OutputPicture.jpg')
end