I am writing a short Matlab script to use im2bw to calculate the area of objects in the image. I am trying to validate that the areas are being calculated correctly, but on the reference image I am using the last square's area is 2% off and I cannot figure out why.
myFolder = 'Your Directory';
% Get a list of all files in the folder with the desired file name pattern.
filePattern = fullfile(myFolder, '*.png'); % Change to whatever pattern you need.
theFiles = dir(filePattern);
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(theFiles(k).folder, baseFileName);
J = imread(fullFileName);
%J = imcrop(I,[500,200,4400,3500]);
BW = im2bw(J,0.3);
BW2 = imcomplement(BW);
BW3 = imfill(BW2,4,'holes');
%figure(1)
%imshowpair(I,BW3,'montage')
stats = regionprops(BW3,'area','PixelList','majoraxislength','minoraxislength');
area = zeros(size(stats));
for i = 1:size(stats,1)
area(i) = stats(i).Area;
end
scale = 1e-6;
%scale = 3.134755344e-8;
cutoff = 0;
area = area*scale;
stats(area<cutoff)=[];
area(area<cutoff)=[];
writematrix(area,'Your Directory','WriteMode','append')
end
figure(1)
imshowpair(J,BW3,'montage')
The image is 1000x1000 the squares are 20x20, 100x100, 100x200, 200x200 respectively.
I assumed the reference image in reality was 1mx1m and scaled accordingly, but the 200x200 square seems to not come out exactly right.
Related
I am trying to figure out how to make a program in Matlab to detect edges of flames so I can compare their flame shape. I have been able to get this program to work half of the time. The program reads the files, coverts it to black and white, and then I have been having issues with the bwboundaries function (I think).
It will work some times and not others depending on the picture, they can be seen below.
Any help anyone could give me would be appreciated. I am struggling here to figure out what I am doing wrong.
clear, clc , close all
%% Specify the folder where the files live.
%myFolder = 'D:\Try';
myFolder = 'D:\Try\PicNamed\SpTestTry\hope';
%% Check to make sure that folder actually exists.
if ~isdir(myFolder)
errorMessage = sprintf('Error: The following folder does not exist:\n%s', myFolder);
uiwait(warndlg(errorMessage));
return;
end
%% Get a list of all files in the folder with the pattern
filePattern = fullfile(myFolder, '*.jpg'); % Change to whatever need.
theFiles = dir(filePattern);
line = cell(length(theFiles), 1) ;
rValue = cell(length(theFiles),1);
baseFileName = theFiles(1).name;
fullFileName = fullfile(myFolder, baseFileName);
fprintf(1, 'Now reading %s\n', fullFileName);
imageArray = imread(fullFileName);
% getting the rectanglur cords to crop the images
[I2, rect] = imcrop(imageArray);
%% Run Loop
for k = 1 : length(theFiles)
%Pulling in multiple Images from folder
baseFileName = theFiles(k).name;
fullFileName = fullfile(myFolder, baseFileName);
fprintf(1, 'Now reading %s\n', fullFileName);
imageArray = imread(fullFileName);
%% Cropping Image with Rect Cords
Icrop = imcrop(imageArray,rect);
%% convert to bw
BW = im2bw(Icrop, graythresh(Icrop));
%% Get Boundries
boundaries = bwboundaries(BW);
% putting in x and y cord
x = boundaries{1}(:, 2);
y = boundaries{1}(:, 1);
%% Curve Fit
%pulling up picture of x,y plot to determing where base of flame is
figure
plot(x, y)
% cutting off bottom of flame edge so we can do curve fit
prompt = '(******) cut off line = ';
cutnum = input(prompt);
indices = find(abs(y)>cutnum);
y(indices) = NaN;
y(indices) = [];
x(indices) = [];
%% Looking for repate x values, averaging them together, and replacing with 1 x value
uc1 = unique( x ) ;
mc2 = accumarray( x, y, [], #mean ) ;
newData = [uc1, mc2(uc1)];
%% splitting AA into two sperate matricies, i.e. x/y cordinates
y = newData(:,2);
x = newData(:,1);
%% Creating a line Based off of the averaged x and y cords
[p,S] = polyfit(x,y,4); % 4th degree polynomail
line{k} = p;
rValue{k} = S.normr;
Rsquared{k}=1-S.normr^2/norm(y-mean(y))^2;
close all
clear BW
clear x
clear y
end
clear_all();
image_name = 'canny_test.png';
% no of pixels discarded on border areas
discard_pixels = 10;
% read image and convert to grayscale
input_image = gray_imread(image_name);
% discard border area
input_image = discard_image_area(input_image, discard_pixels);
% create a binary image
binary_image = edge(input_image,'canny');
imshow(binary_image);
Input
Expected Outcome
Actual Outcome
Here, we see that the borderlines of the image are being detected by the Canny Edge Detector which is not my expected outcome.
How can I achieve this?
Source Code
function [output_image] = discard_image_area( input_image, pixel_count)
output_image = input_image;
[height, width] = size(input_image);
% discard top
output_image(1:pixel_count, :) = 0;
% discard bottom
h = height - pixel_count;
output_image(h:height, :) = 0;
% discard left
output_image(:,1:pixel_count) = 0;
% discard right
output_image(:,(width-pixel_count):width) = 0;
end
function img = gray_imread( image_name )
I = imread(image_name);
if(is_rgb(I))
img = rgb2gray(I);
elseif (is_gray(I))
img = I;
end
end
Apply discard_image_area after applying the edge function. Otherwise the discarded area makes its boundary apparently. i.e. do this:
image_name = 'canny_test.png';
discard_pixels = 10;
input_image = rgb2gray(imread(image_name)); % there is no such this as gray_imread
% create a binary image
binary_image = edge(input_image,'canny');
% discard border area
binary_image = discard_image_area(binary_image , discard_pixels);
imshow(binary_image);
Output:
The answer is simple, your function discard_image_area changes the image value to 0 near the borders of the image.
Hence it creates Step between the image value and 0.
This is exactly what the Canny Edge Detector looks for.
You can easily see it if you display the image after applying the function.
Just don't use that function.
i have to extract each characters from a image here i am uploading the code it is segmenting the horizontal lines but not able to segment the each characters along with the horizontal line segmentation loop. some1 please help to correct the code
this is the previous code:
%%horizontal histogram
H = sum(rotatedImage, 2);
darkPixels = H < 100; % Threshold
% label
[labeledRegions, numberOfRegions] = bwlabel(darkPixels);
fprintf('Number of regions = %d\n', numberOfRegions);
% Find centroids
measurements = regionprops(labeledRegions, 'Centroid');
% Get them into an array
allCentroids = [measurements.Centroid];
xCentroids = int32(allCentroids(1:2:end));
yCentroids = int32(allCentroids(2:2:end));
% Now you can just crop out some line of text you're interested in, into a separate image:
hold off;
plotLocation = 8;
for band = 1 : numberOfRegions-1
row1 = yCentroids(band);
row2 = yCentroids(band+1);
thisLine = rotatedImage(row1 : row2, :);
subplot(7, 2, plotLocation)
imshow(thisLine, [])
%% Let's compute and display the histogram.
verticalProjection = sum(thisLine, 2);
set(gcf, 'NumberTitle', 'Off')
t = verticalProjection;
t(t==0) = inf;
mayukh=min(t);
% 0 where there is background, 1 where there are letters
letterLocations = verticalProjection > mayukh;
% Find Rising and falling edges
d = diff(letterLocations);
startingRows = find(d>0);
endingRows = find(d<0);
% Extract each region
y=1;
for k = 1 : length(startingRows)
% Get sub image of just one character...
subImage = thisLine(:, startingRows(k):endingRows(k));
[L,num] = bwlabel(subImage);
for z= 1 : num
bw= ismember( L, z);
% Construct filename for this particular image.
baseFileName = sprintf('templates %d.png', y);
y=y+1;
% Prepend the folder to make the full file name.
fullFileName = fullfile('C:\Users\Omm\Downloads\', baseFileName);
% Do the write to disk.
imwrite(bw, fullFileName);
pause(2);
imshow(bw);
pause(5)
end;
y=y+2;
end;
plotLocation = plotLocation + 2;
end
but not segmenting the whole lines
Why don't you simply use regionprops with 'Image' property?
img = imread('http://i.stack.imgur.com/zpYa5.png'); %// read the image
bw = img(:,:,1) > 128; %// conver to mask
Use some minor morphological operations to handle spurious pixels
dbw = imdilate(bw, ones(3));
lb = bwlabel(dbw).*bw; %// label each character as a connected component
Now you can use regionprops to get each image
st = regionprops( lb, 'Image' );
Visualize the results
figure;
for ii=1:numel(st),
subplot(4,5,ii);
imshow(st(ii).Image,'border','tight');
title(num2str(ii));
end
I am attempting to delete colored lines (specifically a yellow and blue line) within a series of images in Matlab. An example image can be found here:
I am able to segment out the blue line segments using basic thresholding. I am also able to segment out the bright yellow circles within the yellow line segment using thresholding. Finally, I am working on removing the remaining elements of the line segment using a hough transform w/ the houghlines function and a mask.
Is there a more elegant way to perform this, or am I stuck employing this combination of methods?
Thanks
Edit: I discovered that the hough transform is only removing single pixels from my image and not the entire yellow line. I was contemplating dilating around the detected pixels and checking for similarity, but I'm worried that the yellow line is too similar to the background colors (it's position could change such that it is not fully tracking the dark background it happens to be over now). Any suggestions would be greatly appreciated.
%% This block was intended to deal with another data
set this function has to analyze, but it actually ended up removing my
yellow circles as well, making a further threshold step unnecessary so far
% Converts to a binary image containing almost exclusively lines and crosshairs
mask = im2bw(rgb_img, 0.8);
% Invert mask
mask = ~mask;
% Remove detected lines and crosshairs by setting to 0
rgb_img(repmat(~mask, [1, 1, 3])) = 0;
%% Removes blue targetting lines if present
% Define thresholds for RGB channel 3 based on histogram settings to remove
% blue lines
channel3Min = 0.000;
channel3Max = 0.478;
% Create mask based on chosen histogram thresholds
noBlue = (rgb_img(:,:,3) >= channel3Min ) & (rgb_img(:,:,3) <= channel3Max);
% Set background pixels where noBlue is false to zero.
rgb_img(repmat(~noBlue,[1 1 3])) = 0;
%% Removes any other targetting lines if present
imageGreyed = rgb2gray(rgb_img);
% Performs canny edge detection
BW = edge(imageGreyed, 'canny');
% Computes the hough transform
[H,theta,rho] = hough(BW);
% Finds the peaks in the hough matrix
P = houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
% Finds any large lines present in the image
lines = houghlines(BW,theta,rho,P,'FillGap',5,'MinLength',100);
colEnd = [];
rowEnd = [];
for i = 1:length(lines)
% Extracts line start and end points from houghlines output
pointHold = lines(i).point1;
colEnd = [colEnd pointHold(1)];
rowEnd = [rowEnd pointHold(2)];
pointHold = lines(i).point2;
colEnd = [colEnd pointHold(1)];
rowEnd = [rowEnd pointHold(2)];
% Creates a line segment from the line endpoints using a simple linear regression
fit = polyfit(colEnd, rowEnd, 1);
% Creates index of "x" (column) values to be fed into regression
colIndex = (colEnd(1):colEnd(2));
rowIndex = [];
% Obtains "y" (row) pixel values from regression
for i = colIndex
rowHold = fit(1) * i + fit(2);
rowIndex = [rowIndex rowHold];
end
% Round regression output
rowIndex = round(rowIndex);
% Assemble coordinate matrix
lineCoordinates = [colIndex; rowIndex]';
rgbDim = size(rgb_img);
% Create mask based on input image size
yellowMask = ones(rgbDim(1), rgbDim(2));
for i = 1:length(rowIndex)
yellowMask(rowIndex(i), colIndex(i)) = 0;
end
% Remove the lines found by hough transform
rgb_img(repmat(~yellowMask,[1 1 3])) = 0;
end
end
I briefly tested the example given on
http://de.mathworks.com/help/images/examples/color-based-segmentation-using-k-means-clustering.html?prodcode=IP&language=en
using your image which is:
he = imread('HlQVN.jpg');
imshow(he)
cform = makecform('srgb2lab');
lab_he = applycform(he,cform);
ab = double(lab_he(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
pixel_labels = reshape(cluster_idx,nrows,ncols);
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = he;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
imshow(segmented_images{1}), title('objects in cluster 1');
this already pretty well identifies the blue line.
This post won't go into the image processing side of the problem, but rather just focuses on the implementation and would suggest ways to improve the existing code. Now, the code has polyfit calculation at each loop iteration, which I am not sure could be vectorized. So, rather let's try to vectorize rest of the codes inside the loop and hopefully that would bring in some speedup for the overall code. The changes I would like to propose are at two steps within the innermost loop.
1) Replace -
rowIndex=[]
for i = colIndex
rowHold = fit(1) * i + fit(2)
rowIndex = [rowIndex rowHold];
end
with -
rowIndex = fit(1)*colIndex + fit(2)
2) Replace -
yellowMask = ones(rgbDim(1), rgbDim(2));
for i = 1:length(rowIndex)
yellowMask(rowIndex(i), colIndex(i)) = 0;
end
rgb_img(repmat(~yellowMask,[1 1 3])) = 0;
with -
idx1 = (colIndex-1)*rgbDim(1) + rowIndex
rgb_img(bsxfun(#plus,idx1(:),[0:rgbDim(3)-1]*rgbDim(1)*rgbDim(2))) = 0;
It turns out that the answer involved converting the image into the Lab colorspace and performing treshholding. This segmented out the lines with minimal loss in the rest of the image. The code is below:
% Convert RGB image to L*a*b color space for thresholding
rgb_img = im2double(rgb_img);
cform = makecform('srgb2lab', 'AdaptedWhitePoint', whitepoint('D65'));
I = applycform(rgb_img,cform);
% Define thresholds for channel 2 based on histogram settings
channel2Min = -1.970;
channel2Max = 48.061;
% Create mask based on chosen histogram threshold
BW = (I(:,:,2) <= channel2Min ) | (I(:,:,2) >= channel2Max);
% Determines the eccentricity for regions of pixels; basically how line-like
% (vals close to 1) or circular (vals close to 0) the region is
rp = regionprops(BW, 'PixelIdxList', 'Eccentricity');
% Selects for regions which are not line segments (areas which
% may have been incorrectly thresholded out with the crosshairs)
rp = rp([rp.Eccentricity] < 0.99);
% Removes the non-line segment regions from the mask
BW(vertcat(rp.PixelIdxList)) = false;
% Set background pixels where BW is false to zero.
rgb_img(repmat(BW,[1 1 3])) = 0;
Suppose we take any image from Internet and then copy or move some part from that image to any other area inside that image the image should show from where that the part is copied / moved and then pasted. By using matlab.
a = imread('obama.jpg');
a = rgb2gray(a);
[x1 y1] = size(a);
b = uint8(imcrop(a, [170 110 200 150]));
[x2 y2] = size(b);
c = uint8(zeros(x1,y1));
for i = 1:x2
for j = 1:y2
c(i+169,j+109) = b(i,j);
end
end
[x3 y3] = size(c)
subplot(1,3,1),imshow(a);
subplot(1,3,2),imshow(b);
subplot(1,3,3),imshow(c);
Code
%%// Input data and params
a = imread('Lenna.png');
a = rgb2gray(a);
src_xy = [300,300]; %% Starting X-Y of the source from where the portion would be cut from
src_dims = [100 100]; %% Dimensions of the portion to be cut
tgt_xy = [200,200]; %% Starting X-Y of the target to where the portion would be put into
%%// Get masks
msrc = false(size(a));
msrc(src_xy(1):src_xy(1)+src_dims(1)-1,src_xy(2):src_xy(2)+src_dims(2)-1)=true;
mtgt = false(size(a));
mtgt(tgt_xy(1):tgt_xy(1)+src_dims(1)-1,tgt_xy(2):tgt_xy(2)+src_dims(2)-1)=true;
%%// If you would like to have a cursor based cut, explore ROIPOLY, GINPUT - e.g. - mask1 = roipoly(a)
mask1 = msrc;
a2 = double(a);
%%// Get crop-mask boundary and dilate it a bit to show it as the "frame" on the original image
a2(imdilate(edge(mask1,'sobel'),strel('disk',2))) = 0;
a2 = uint8(a2);
%%// Display original image with cropped portion being highlighted
figure,imshow(a2);title('Cropped portion highlighted')
figure,imshow(a);title('Original Image')
figure,imshow(mask1);title('Mask that was cropped')
img1 = uint8(bsxfun(#times,double(a),mask1));
figure,imshow(img1);title('Masked portion of image')
%%// Get and display original image with cropped portion being overlayed at the target coordinates
a_final = a;
a_final(mtgt) = a(msrc);
figure,imshow(uint8(a_final));title('Original image with the cut portion being overlayed')
Output
Please note that to use RGB images, you would need to tinker a bit more with the above code.