Checking Pixels in Matlab - matlab

I have an image with 3 colors in matlab which value 0, 128, and 255. for example:
255 255 255 255 128 255 0 255 255 128 0 255
255 0 255 255 128 255 255 0 255 128 255 255
255 0 255 0 128 255 255 255 255 128 255 0
255 255 0 255 128 255 255 0 255 128 255 255
255 0 0 255 128 0 255 255 0 128 255 0
First, I want to check the pixels of the index (1,1) to (1,5).
If there is pixel value 0 (black), then the pixels of the index (1,1) to (1,5) is changed to 128 (gray), if none, then the pixels are changed to 0 (white).
Second, I want to do these steps again, checking of the index (2,1) to (2,5), (3,1) to (3,5), through to the bottom, then continue to the next, to the index (1,6) to (1,10), (2,6) to (2,10), through to the bottom, then went to the index (1,11) to (1,end), (2,11) to (2,end).

Do you absolutely need to do this sequentially? It sounds like you need to do this for each group of the form (n, (5*m : 5*m +1)). If so, you can do all of the tests simultaneously by reshaping the matrix into a 3d matrix of blocks which are 5 elements wide. Also I am assuming that you meant "if none, then the pixels are changed to 255 (white)", not 0.
Suppose your image is called myImage, then
numBlocks = numel(myImage)/(5*size(myImage,1));
% Generate a 3D matrix each of which is 5 elements long in dimension 2. Note reshape will throw an error if numblocks is fractional
foo = reshape(myImage,size(myImage,1),5,numBlocks);
blackTest = any(foo==0,2);
result = blackTest * 128 + ~blackTest*255; % result for each block
output = reshape(repmat(result,[1 5 1]),size(myImage));
This reorganises your image into a 3d matrix, where each submatrix corresponding to each "layer" of the 3d matrix is 5 elements wide. For the whole 3d matrix it checks whether any of the elements in dimension 2 are zero, leaving a logical matrix foo of length 1 in dimension 2. foo consists of logical ones and zeros, which in MATLAB can also be treated as numerical ones and zeros. So it multiplies foo by 128 (for grey output value) and adds the logical inverse of foo multiplied by 255, to get your white output values. Finally it repeats the matrix back to 5-element-wide blocks and restores it to its original dimensions.
Edit: Note that as mentioned in the code comment, this code won't work if your original image isn't a multiple of 5 pixels wide. To fix this you'd have to create a special case, or use a loop to step through each 5-element-wide block. In fact that might be a better approach all round:
index = 1;
output = zeros(size(myImage));
while index < size(myImage,2)
blockEnd = min(index+4,size(myImage,2));
blackTest = any(myImage(:,index:blockEnd)==0,2);
blackTest = blackTest(:,ones(1,5));
output(1:end,index:blockEnd) = blackTest * 128 + ~blackTest*255;
index = index+5;
end

% generate matrix
rand_data = randi(10,10);
I = zeros(10);
I(rand_data < 6 & rand_data > 3) = 128;
I(rand_data >= 6) = 255;
% here's the code
I = reshape(I',5,[])';
mask = repmat(any(I == 0,2),5,1);
I(mask) = 128;
I(~mask) = 255;
I = reshape(I',10,[])';

Related

Creating gray-level co-occurrence matrix from 16-bit image

I have a data set of images that are 16-bit and I want to create GLCM matrix from them to extract GLCM features.
However, the resulting matrix shows one value (as shown in the picture below), I wonder why.
I tried using the same image but converted to 8-bit, the resulted GLCM show several values.
Note: I used the following Matlab function:
glcm_matrix = graycomatrix(image.tif);
Here is a cropped sample from the 16-bit image:
Note: The image used in the computations can be downloaded from here. The original image is very low contrast and looks totally dark. The image shown above has its contrast stretched and is intended only for visualization purposes.
EDIT:
I used
glcm_matrix = graycomatrix(image.tif, 'GrayLimits', []);
and it gives me the following results:
It was a binning/scaling problem.
Let's take a peek inside:
edit graycomatrix
In this case we're interested in the two options, 'NumLevels' and 'GrayLimits'
% 'NumLevels' An integer specifying the number of gray levels to use
% when scaling the grayscale values in I. For example,
% if 'NumLevels' is 8, GRAYCOMATRIX scales the values in
% I so they are integers between 1 and 8. The number of
% gray levels determines the size of the gray-level
% co-occurrence matrix (GLCM).
%
% 'NumLevels' must be an integer. 'NumLevels' must be 2
% if I is logical.
%
% Default: 8 for numeric
% 2 for logical
%
% 'GrayLimits' A two-element vector, [LOW HIGH], that specifies how
% the values in I are scaled into gray levels. If N is
% the number of gray levels (see parameter 'NumLevels')
% to use for scaling, the range [LOW HIGH] is divided
% into N equal width bins and values in a bin get mapped
% to a single gray level. Grayscale values less than or
% equal to LOW are scaled to 1. Grayscale values greater
% than or equal to HIGH are scaled to NumLevels. If
% 'GrayLimits' is set to [], GRAYCOMATRIX uses the
% minimum and maximum grayscale values in I as limits,
% [min(I(:)) max(I(:))].
So in other words the function was binning your data into 8x8 bins and assuming that the scaling range was the full uint16 range (0-65535). However that sample image I you gave has a minimum of 305 and a maximum of 769, making it fall into the first bin (0-8192 or so). When I call A = graycomatrix(I) it gives me the following matrix :
A =
6600 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
However when A = graycomatrix(I,'GrayLimits', []) is called the scaling range is taken as min(I) - max(I), and the function works as expected :
A =
4 2 1 0 0 0 0 0
1 1 2 2 0 0 0 0
2 2 4 7 1 0 0 0
0 1 7 142 72 1 0 0
0 0 0 65 1711 252 0 0
0 0 0 0 230 3055 178 0
0 0 0 0 0 178 654 8
0 0 0 0 0 0 8 9
In your original example the single value is in the middle of the 8x8 matrix most likely because your original images are int16 and not uint16, so the graycomatrix is symmetric to take into account the possibility of negative values.
You can also of course scale the original images to fit their datatypes. For example percentile scaling might be a good idea if you expect outliers etc.
I'd just like to build on #Tapio's excellent answer.
The GLCM yielded by graycomatrix when you use the name/value pair GrayLimits', [] in the function call looks good. However, this approach might not be valid for your application. If you compute the GLCMs for a set of images in this way, the same elements of two different GLCMs corresponding to two different images are likely to have a different meaning. Indeed, as the intensity is being rescaled differently for each image, the components of the GLCM are actually encoding different co-occurrences from one image to another.
To avoid this you could first calculate the minimum and maximum intensities over the whole image dataset (for example minImgs and maxImgs) and then use those values to rescale the intensity of all the images that make up the dataset in the exact same way:
glcm_matrix = graycomatrix(image_tif, 'GrayLimits', [minImgs maxImgs]);

Search and replace for a specific string in multiple lines of a text file in matlab

I have a text file in which I want to search for the number 255 in every line to replace it with the number 0. It is to be noted that the number are written in the text file as strings. I want to skip the first 13 lines, since there is text in these 13 lines.
A part of the text file is shown below:
F2G_DIM 3
F2G_VERSION 1
F2G_LOCATION 0 0 0.5
F2G_ROTATION 0
F2G_ORIGIN 0 0 0
F2G_NB_NODES 300 150 50
F2G_LAGS 10 10 1
F2G_ORDER +Y +X +Z
F2G_NB_VARIABLES 1
F2G_VARIABLE_1 Facies
F2G_UNDEFINED_1 255
F2G_VALUES
2
1
2
255
2
255
2
2
5
9
How can I solve this problem?
For your first questions you can use logical indexing to find and substitute the 255
pattern = 255; %Number to find
array = randi(10,10,1); %Some array
array([4,8,9]) = 255;
array(array==pattern) = 0; %Substitute values
For the second question, you can use dlmread to load in the data. It allows you to specify a header to ignore.
data = dlmread('file.csv',' ',13,0);
where 13 is the number of rows to ignore and 0 is the number of columns to ignore.
In total you have something like:
pattern = 255; %Pattern
data = dlmread('file.csv',' ',13,0); %Load
data(data==pattern) = 0; %Substitute values

Matlab - euclidean distance of specific elements between two vectors

I'm trying to find the coordinates/index that has the minimum distance of an element in a 2d array to another same element 2d array. I have a binary image from my edge detection problem and a ground truth image. For example, I have A as my binary image and B as the ground truth image:
A = [0 255 255 255;255 255 255 255;255 255 255 255;255 255 255 255 ]
B = [255 255 255 255;255 255 255 255; 255 255 0 255; 255 255 0 0]
0 is black and 255 is white. My algorithm goes like this:
for n=1:maxindex
if(A(n)==0&&B(n)==0)
distance(n) = 0;
elseif(A(n)==0&&B(n)==255)
for m=1: maxindex
if(B(m)==0&&m~=n)
translate index to subscripts
compute euclidean distance
store value in temporary vector
end
end
find minimum in temporary vector
distance(n) = minimum found
end
end
The algorithm really takes a long time for large images, since it's exhaustive when there's a mismatch. Is there a function in Matlab that would make this faster?

Initialization of population for genetic algorithm in matlab

I randomly generated initial 10 population(let each of size n) of genetic algorithm as follows
for i = 1:10
for j=1:n
population(i,j)=randi([MinIntensity,MaxIntensity]);
end
end
Assume that I have the values of one population.For example let the first population of size 10 is [100 110 120 130 140 150 160 170 180 190].Is it possible to generate the remaining 9 population such that the values are near to the first population?(It is for the quick convergence of genetic algorithm).Also each population is a grayscale image with intensity values represented in row major order.Hence the intensity values should be in the range of 0 - 255.
Please help.Thanks in advance
You can do one thing. Use the first string as it is for the rest of the 9 strings except randomly generate an index (between 1 to n) and assign a random integer only to that positions with that random index.
population(1,:) = [100 110 120 130 140 150 160 170 180 190];
for i = 2:10
idx = randi([1 10]);
population(i,:) = population(1,:);
population(i,idx) = randi([0 255]);
end
With this you will get ten strings differing in only one position.
Edit: Image.
Assuming you have a MXN image. Create a mask for example
randi([-10 10], M , N)
Now add this to your original image. Now you get a new image whose all the pixels are modified but only within the range of -10 to 10. Some of the pixel values might go out of range in that case just modify as below
x(find(x < 0)) = 0 %Here X is your new image.
x(find(x > 255)) = 255

Error while trying to use polyval

I have the following vector
vec = [ 255 0 255 0 255 0 255 0 255 0 255 0 255 0 255 0]
vec 1x16 double
and using the following command
polyval(vec', 256);
I get
ans = 3.3896e+038
but when I try to get back my original vector
vec2 = decimal2base(ans, 256)
I get
vec2 = 255 0 255 0 255 1 0 0 0 0 0 0 0 0 0 0
and this is clearly not my original vector.
Whats more if again I run polyval in this vector
polyval(vec2', 256);
I get
ans=
3.3896e+038
I am not entirely sure what sort of mistake I am making as I know that my conversion functions are ok, so it must be a number precision thing.
Ah, large numbers. The value 3.3896e+038 is higher than the maximum integer that can be represented by a double without loss of accuracy.
That maximum number is 2^53 or
>> flintmax('double')
ans =
9.0072e+15
So you are losing accuracy and you cannot reverse the computation.
Doing the computations with uint64 values only:
>> pows = uint64(fliplr(0:numel(vec)-1));
>> sum(uint64(vec).*(uint64(256).^pows),'native')
ans =
18446744073709551615
That's about 1.84e+19. Just a little different from what you get if you use doubles. But wait... that number looks familiar:
>> intmax('uint64')
ans =
18446744073709551615
So, you've maxed out unsigned 64-bit integers too:
>> uint64(256).^pows
ans =
Columns 1 through 5
18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615
Columns 6 through 10
18446744073709551615 18446744073709551615 18446744073709551615 72057594037927936 281474976710656
Columns 11 through 15
1099511627776 4294967296 16777216 65536 256
Column 16
When you get above 255^8 or so, you're passing intmax('uint64') and you can't manage numbers this large, at least not with MATLAB's built-in data types.
see if this returns '1':
polyval(vec(6:end),256)==polyval(vec2(6:end),256);
If so, then it's just a property of '255+1' for that special 'vec'.