Take a text line in an image file to create a new image file MATLAB - matlab

I need to take each line of text from an image file and create a new separate image for each of the lines. i already have a way to count how many lines are in the image file.
if anybody has any suggestions it would be a huge help because i'm not too good with images. im not allowed to use the image processing toolbox.
This is the code:
function out = countLines( imgFile )
% count the number of lines in the image file
im = imread(imgFile);
im = 255 - im;
imbw = uint8(0.33*im(:,:,1) + 0.34*im(:,:,2) + 0.33*im(:,:,3)) > 127;
imwrite(imbw, 'temp.jpg');
rvec = sum(imbw');
rvec1 = [0 rvec 0];
svec = [rvec 0 0];
out = sum(rvec1 == 0 & svec ~= 0);

I tried this method on a test image I found on the internet and it seemed to work alright provided the text is straight. Basically you look for entries in your rvec vector whose neighbouring entries are both smaller than them. That is to say you look for the local maximum entries (first image). After that you group the clusters of lines together to decide where to split the image (second image).
clear; clc;
im = imread('text.png'); % load the image
[Nrows,Ncols,~] = size(im); % get the size
imgray = rgb2gray(im); % convert to grayscale
vec = mean(imgray,2); % average intensities of each row
localMax=[]; % list of local maximum entries
for i = 2:Nrows-1 % accept local max rows that do not have text
hasText = sum( imgray(i,:)<100 )>0;
if vec(i)>vec(i-1) && vec(i)>vec(i+1) && ~hasText
localMax = [localMax;i];
end
end
numMax = length(localMax);
% get distances between local max rows
distances = localMax(2:end) - localMax(1:end-1);
thresh = mean(distances); % the average distance will be our threshold
splitRows = []; % rows where we will split the image
cluster = localMax(1); % start a cluster with the first local max row
for i = 1:numMax-1;
if distances(i) < thresh % if rows are close together, keep them in a cluster
cluster = [cluster;localMax(i+1)];
else % average the cluster to get the row where we split the image
newSplit = round(mean(cluster));
splitRows = [ splitRows ; newSplit ];
cluster = localMax(i+1);
end
end
newSplit = round(mean(cluster)); % add the last cluster as well
splitRows = [ splitRows ; newSplit ];

Related

Updating histogram in a for-loop without growing y-data

I have had zero luck finding this elsewhere on the site, so here's my problem. I loop through about a thousand mat files, each with about 10,000 points of data. I'm trying to create an overall histogram of this data, but it's not very feasible to concatenate all this data to give to hist.
I was hoping to be able to create an N and Bin variable each loop using hist (y), then N and Bin would be recalculated on the next loop iteration by using hist(y_new). And so on and so on. That way the source data doesn't grow and when the loop finally ends, I can just use bar(). If this method wouldn't work, then I am very open-minded to other solutions.
Also, it is probably not safe to assume that the x data will remain constant throughout each iteration. I'm using 2012a.
Thanks for any help!!
I think the best solution here is to loop through your files twice: once to set the bins and once to do the histogram. But, if this is impossible in your case, here's a one shot solution that requires you to set the bin width beforehand.
clear; close all;
rng('default') % for reproducibility
% make example data
N = 10; % number of data files
M = 5; % length of data files
xs = cell(1,N);
for i = 1:N
xs{i} = trnd(1,1,M);
end
% parameters
width = 2;
% main
for i = 1:length(xs)
x = xs{i}; % "load data"
range = [min(x) max(x)];
binsPos = 0:width:range(2)+width;
binsNeg = fliplr( 0:-width:range(1)-width );
newBins = [binsNeg(1:end-1) binsPos];
newCounts = histc(x, newBins);
newCounts(end) = []; % last bin should always be zero, see help histc
if i == 1
counts = newCounts;
bins = newBins;
else
% combine new and old counts
allBins = min(bins(1), newBins(1)) : width : max(bins(end), newBins(end));
allCounts = zeros(1,length(allBins)-1);
allCounts(find(allBins==bins(1)) : find(allBins==bins(end-1))) = counts;
allCounts(find(allBins==newBins(1)) : find(allBins==newBins(end-1))) = ...
allCounts(find(allBins==newBins(1)) : find(allBins==newBins(end-1))) + newCounts;
bins = allBins;
counts = allCounts;
end
end
% check
figure
bar(bins(1:end-1) + width/2, counts)
xFull = [xs{:}];
[fullCounts] = histc(xFull, bins);
fullCounts(end) = [];
figure
bar(bins(1:end-1) + width/2, fullCounts)

Spheroids detction from Images

I need to find the blobs from the below image.
The major problem is background. background doesn't have uniform intensity. I tried couple of things like thresholding and edge detection in MATLAB but couldn't able to find a better ways to segment out all spheroids. I need to extract the blobs and I need to find the area of each blobs. Does anyone know how to work-around with this kind of background?
Edit (07/02/17):
As suggested by Spektre I tried Following things in MATLAB.
Method 1:
img_original = imread('~/my_image.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
g = fspecial('gaussian',200,100); %Kernel matrix to make the img blurr
con_img = conv2(img_ch,g,'same'); %2D convolution, this wil make the img blurr
sub_img = (con_img - img_ch); %Simple matrix subtraction
sub_img(sub_img <= 10) = 0; %Thresholding
sub_img(sub_img ~= 0) = 1;
fil_sub = imfill(sub_img,'holes'); %Fill the regions
imgfilt = imfilter(fil_sub, ones(3)); %run filter using 3by3 matrx
imgfilt(imgfilt < 8) = 0; %Reduce noisy pixels by thresholding
mfilt_img = (medfilt2(imgfilt)); %reduce unwanted pixels
img = img_ch;
img(mfilt_img ~= 0) = 255;
img2 = img_ch;
img2(img2 < 70) = 0; %Threshold for darker pixels which are left out from above methode.
img(img2 ==0) = 255;
disp_img = img_original(:,:,1);
disp_img(img ==255) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
I got the segments but still not good enough I think. This method gave good segments in the high intensity background, Even if I reduce the threshold value segments are not clear in the darker background and brightest pixels in the blobs are excluded.
Method 2:
img_original = imread('~/cancer_cells/Snap-10234.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
clear new_matcel cur_img matcel avg_matrx
s=3; % Set size of the square window
mat_img = img_ch; % Working image channel
% resize the working matrix so that the dimensions matches
resize_img = resizem(mat_img,round(size(mat_img)/s)*s);
% convert matrix into small s x s matrix and save each in cells
window_c = ones(1,size(resize_img,1)/s) * s;
window_r = ones(1,size(resize_img,2)/s) * s;
mat_cel = mat2cell(resize_img,window_c,window_r);
new_matcel = cell(size(mat_cel)); % initialize new variable
% get the average value for each window and replace the actual by avg value
for i = 1:size(mat_cel,1)
for j = 1:size(mat_cel,2)
cur_img = mat_cel{i,j};
avg_value = mean(mean(cur_img));
new_matcel{i,j} = ones(s) * avg_value;
end
end
avg_matrx = cell2mat(new_matcel); % convert cells to matrix
image_sub = (abs(resize_img - avg_matrx)); % take the absolute difference
image_sub(image_sub < 7) = 0; % thresholding
image_sub(image_sub~=0) = 1;
image_sub = bwmorph(image_sub,'bridge');% fill gaps
image_sub = imfill(image_sub,'holes'); % fill the bounded regioons
% image_sub(image_sub == 1) = 255;
image_sub = resizem(image_sub,size(img_ch)); % resize to original size
disp_img = img_original(:,:,1);
disp_img(image_sub == 1) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
Much better segmented image:
even brighter pixels are included in the segment. Thanks to Spektre.
Is there a way to improve the above code? or any other idea to get more precise segments?
Thanks.

Dimensions issus

Finding maximum values of wave heights and wave lengths
dwcL01 though dwcL10 is arrays of <3001x2 double> with output from a numerical wave model.
Part of my script:
%% Plotting results from SWASH
% Examination of phase velocity on deep water with different number of layers
% Wave height 3 meters, wave peroid 8 sec on a depth of 30 meters
clear all; close all; clc;
T=8;
L0=1.56*T^2;
%% Loading results tabels.
load dwcL01.tbl; load dwcL02.tbl; load dwcL03.tbl; load dwcL04.tbl;
load dwcL05.tbl; load dwcL06.tbl; load dwcL07.tbl; load dwcL08.tbl;
load dwcL09.tbl; load dwcL10.tbl;
M(:,:,1) = dwcL01; M(:,:,2) = dwcL02; M(:,:,3) = dwcL03; M(:,:,4) = dwcL04;
M(:,:,5) = dwcL05; M(:,:,6) = dwcL06; M(:,:,7) = dwcL07; M(:,:,8) = dwcL08;
M(:,:,9) = dwcL09; M(:,:,10) = dwcL10;
%% Finding position of wave crest using diff and sign.
for ii=1:10
Tp(:,1,ii) = diff(sign(diff([M(1,2,ii);M(:,2,ii)]))) < 0;
Wc(:,:,ii) = M(Tp,1,ii);
L(:,ii) = diff(Wc(:,1,ii))
end
The loop
for ii=1:10
Tp(:,1,ii) = diff(sign(diff([M(1,2,ii);M(:,2,ii)]))) < 0;
Wc(:,:,ii) = M(Tp,1,ii);
L(:,ii) = diff(Wc(:,1,ii))
end
Works fine for ii = 1 Getting the following error for ii = 2
Index exceeds matrix dimensions.
Error in mkPlot (line 19)
Wc(:,:,i) = M(Tp,:,i);
Don't have the same number of wave crests for the different set ups, naturally M(Tp,1,ii) will have different dimensions. How do I work around this issue? Can it be done in a for loop? please feel free to email me or other wise ask for further information.
The problem is that Tp is a three dimensional array. I need to call the Tp(:,:,ii) corresponding to the present scenario. Together with this and defining Wc as a cell I solve my issue.
for ii = 1:10
Tp(:,1,ii) = diff(sign(diff([M(1,2,ii);M(:,2,ii)]))) < 0;
Wc{:,:,ii} = M(Tp(:,:,ii),1,ii);
L{:,ii} = diff(cell2mat(Wc(ii)));
end

Rolling window for averaging using MATLAB

I have the following code, pasted below. I would like to change it to only average the 10 most recently filtered images and not the entire group of filtered images. The line I think I need to change is: Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;, but how do I do it?
j=1;
K = 1:3600;
window = zeros(1,10);
Yout = zeros(10,column,row);
figure;
y = 0; %# Preallocate memory for output
%Load one image
for i = 1:length(K)
disp(i)
str = int2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{i}(:,:) = A(:,:);
%Go through the columns and rows
for p = 1:column
for q = 1:row
if(mean2(D{i}(p,q))==0)
x = 0;
else
if(i == 1)
meanvalue = mean2(D{i}(p,q));
end
%Calculate the temporal mean value based on previous ones.
meanvalue = (meanvalue+D{i}(p,q))/2;
x = double(D{i}(p,q)/meanvalue);
end
%Filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
end
end
end
% for k = 2:10
% subplot(5,2,k)
% subimage(Yout(k)*5000, [0 100]);
% colormap jet
% end
% pause(0.01);
end
disp('Done Loading...')
The best way to do this (in my opinion) would be to use a circular-buffer to store your images. In a circular-, or ring-buffer, the oldest data element in the array is overwritten by the newest element pushed in to the array. The basics of making such a structure are described in the short Mathworks video Implementing a simple circular buffer.
For each iteration of you main loop that deals with a single image, just load a new image into the circular-buffer and then use MATLAB's built in mean function to take the average efficiently.
If you need to apply a window function to the data, then make a temporary copy of the frames multiplied by the window function and take the average of the copy at each iteration of the loop.
The line
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
calculates a kind of Moving Average for each of the 10 bands over all your images.
This line calculates a moving average of meanvalue over your images:
meanvalue=(meanvalue+D{i}(p,q))/2;
For both you will want to add a buffer structure that keeps only the last 10 images.
To simplify it, you can also just keep all in memory. Here is an example for Yout:
Change this line: (Add one dimension)
Yout = zeros(3600,10,column,row);
And change this:
for q = 1:row
[...]
%filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(i,k,p,q) = y.^2;
end
YoutAvg = zeros(10,column,row);
start = max(0, i-10+1);
for avgImg = start:i
YoutAvg(k,p,q) = (YoutAvg(k,p,q) + Yout(avgImg,k,p,q))/2;
end
end
Then to display use
subimage(Yout(k)*5000, [0 100]);
You would do sth. similar for meanvalue

Kmean plotting in matlab

I am on a project thumb recognition system on matlab. I implemented Kmean Algorithm and I got results as well. Actually now I want to plot the results like here they done. I am trying but couldn't be able to do so. I am using the following code.
load training.mat; % loaded just to get trainingData variable
labelData = zeros(200,1);
labelData(1:100,:) = 0;
labelData(101:200,:) = 1;
k=2;
[trainCtr, traina] = kmeans(trainingData,k);
trainingResult1=[];
for i=1:k
trainingResult1 = [trainingResult1 sum(trainCtr(1:100)==i)];
end
trainingResult2=[];
for i=1:k
trainingResult2 = [trainingResult2 sum(trainCtr(101:200)==i)];
end
load testing.mat; % loaded just to get testingData variable
c1 = zeros(k,1054);
c1 = traina;
cluster = zeros(200,1);
for j=1:200
testTemp = repmat(testingData(j,1:1054),k,1);
difference = sum((c1 - testTemp).^2, 2);
[value index] = min(difference);
cluster(j,1) = index;
end
testingResult1 = [];
for i=1:k
testingResult1 = [testingResult1 sum(cluster(1:100)==i)];
end
testingResult2 = [];
for i=1:k
testingResult2 = [testingResult2 sum(cluster(101:200)==i)];
end
in above code trainingData is matrix of 200 X 1054 in which 200 are images of thumbs and 1054 are columns. actually each image is of 25 X 42. I reshaped each image in to row matrix (1 X 1050) and 4 other (some features) columns so total of 1054 columns are in each image. Similarly testingData I made it in the similar manner as I made testingData It is also the order of 200 X 1054. Now my Problem is just to plot the results as they did in here.
After selecting 2 features, you can just follow the example. Start a figure, use hold on, and use plot or scatter to plot the centroids and the data points. E.g.
selectedFeatures = [42,43];
plot(trainingData(trainCtr==1,selectedFeatures(1)),
trainingData(trainCtr==1,selectedFeatures(2)),
'r.','MarkerSize',12)
Would plot the selected feature values of the data points in cluster 1.