I'm trying to do some image analysis in Matlab. What I have is an image which I first convert into an binary image using a threshold and then I use bwlabel to get the BLOBs of the image. I then find the indexes of the first BLOB and tries to show only the RGB values of this BLOB I(row,column,:). However this obviously does not work and I don't know how to index the original image and get the corresponding RGB values based on the row, column data in the binary image. I suppose I could use a for-loop but the image is 4032 x 3024 and I want to do this kind of processing on a lot of images.
I = imread('someimg.jpg');
Ired = I(:,:,1);
Igreen = I(:,:,2);
Iblue = I(:,:,3);
% threshold
IBinary = Ired > 200 & Igreen > 150 & Iblue > 50;
IBinary = imopen(ISigns,strel('square',9));
% get labbelled BLOBs
IBinaryLabelled = bwlabel(IBinary,8);
% find index of the first label image
[row,column] = find(IBinaryLabelled == 1);
% Get RGB of the BLOB with label 1
RGB = I(row,column,:)
My question is therefore: How to get RGB values based on row,column data of binary image in an efficient manner?
Related
This is a follow up to my previous post here
I'm using the following lines of code to convert the data type(from uint16 to uint8) of z-stack images in MATLAB
%Multiple image tiff conversion%
File_Name = "Test_Image.tiff";
Image_Data = imfinfo(File_Name);
Number_Of_Images = length(Image_Data);
Tiff_Structure = struct('Image_File',[]);
for Image_Index = 1: Number_Of_Images
Image = imread(File_Name,Image_Index);
Uint8_Image = im2uint8(Image);
%For more information and plotting individual images%
Tiff_Structure(Image_Index).Image_File = Uint8_Image;
%Saving the converted images to one tiff file%
imwrite(Uint8_Image,'Converted_Image.tiff','WriteMode','append');
end
In the documentation available here it is mentioned that
im2uint8(I) converts the grayscale, RGB, or binary image I to uint8,
rescaling or offsetting the data as necessary
I would like to know if it is possible to rescale the data before converting the datatype to uint8 and how this rescaling can be done.
Test_Image.Tiff
Suggestions will be really helpful.
EDIT:
Plotting the histogram of the image data gives the following
img_data = imfinfo(f);
n_img = length(img_data);
imgs = cell(1, numel(img_data));
for i = 1:numel(img_data)
imgs{i} = imread(f, i);
end
imgs = cat(3, imgs{:});
figure(1)
imhist(imgs(:), 256)
Assuming Image has values in the range 0-65535 (16bit)
to scale the values into an 8bit image:
first divided the image by 65535 (2^16) - this will normalize value range to 0-1
now you need to rescale to 8bit range of values, multiplying the image by 255
so basically:
scaled_image = uint8(double(Image)./65535*255)
Note: To preserve the dynamic range of the image it might be better to choose a different value to normalize with, e.g some max value across all stack
When using the function regionprops in MATLAB, there is an option to extract the binary image of each connected component. The size of the binary image is reduced to the size of the connected component. I don't want the size of the binary image to reduce. I want the size of the binary image to retain its original size while only showing the selected connected component at its corresponding location in the original image size. How can I extract the connected component in the original image size?
Simply create a blank image that's the same size as your original image and instead of extracting the image per blob, extract the actual pixel locations with reference to the original image for each blob then populate the blank image by setting these locations to binary true in this blank image. Use the PixelIdxList attribute from regionprops to obtain the column major locations of your desired component, then use these to set the output image at these same locations to true.
Assuming your regionprops structure is stored in S and you want to extract out the kth component and the original image is stored in A, do the following:
% Allocate blank image
out = false(size(A, 1), size(A, 2));
% Run regionprops
S = regionprops(A, 'PixelIdxList');
% Determine which object to extract
k = ...; % Fill in ID here
% Obtain the indices
idx = S(k).PixelIdxList;
% Create the mask to be the same size as the original image
out(idx) = true;
imshow(out); % Show the final mask
If you have multiple objects and want to create this mask that is the original size of the image separately per object, you can use a for loop to do that for you:
% Run regionprops
S = regionprops(A, 'PixelIdxList');
% For each blob...
for k = 1 : numel(S)
out = false(size(A, 1), size(A, 2)); % Allocate blank image
% Extract out the kth object's indices
idx = S(k).PixelIdxList;
% Create the mask
out(idx) = true;
% Do your processing with out ...
% ...
end
i have image that contain many blobs . my problem is that how to test each blob individually by masking it up on the original image?!
i tried this code but i did not know how to complete it
labelledImage = bwconncomp(segmentedimage);
stats = regionprops(labelledImage, 'all');
centroids = cat(1, stats.Centroid);
[row ,col] = size(centroids);
for i = 1 : row
areaMatr(i) = stats(i).Area; % gives area for each blob in your image
% what i have to put here for testing the blob and masking it out over the
% original image? any help?
end
It may be more prudent to use bwlabel instead, which assigns a unique ID to each unique blob in your image. The first output gives you this labelling and the second output gives you the total number of unique IDs / blobs in the image. Bear in mind that this image needs to be binary, but given your choice of variable name, I'm assuming this to be true.
Once you find all unique IDs, you can loop through each unique ID, mask out the blob and apply regionprops to this blob.
Something like this:
%// Apply bwlabel to the image
[labelledImage, numLabels] = bwlabel(segmentedimage);
%// For each label...
for idx = 1 : numLabels
%// Create a mask for this particular blob
mask = labelledImage == idx;
%// Apply regionprops on this mask only
stats = regionprops(mask, 'all');
%// Use stats and mask in however way you see fit
%// ...
%// ...
end
'stats.BoundingBox' will give you the coordinates of each blob. You can use the coordinates to mask the blob onto the original image.
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'm using the following code to convert an image into binary form.
% lets suppose that the name of image file is caption with an extension .jpg
X=imread('caption.jpg');
g=reshape((dec2bin(typecast(X(:),'uint8'),8)-'0').',1,[])
After running the code, I'm getting 1xn matrix of type double, having a series of 0's and 1's.
Now I want to convert this matrix g back into an image.
The converted image should be similar to caption.jpg.
You will need the number of rows and number of cols in the initial image to get the color image back.
rowsize = size(X,1);
colsize = size(X,2);
final_image = uint8(reshape(bi2de(reshape(g,8,[])',2,'left-msb'),rowsize,colsize,[]));
imwrite(final_image,'caption.jpg');