Black line in GLCM result - matlab

It is the result of GLCM matrix. What is the meaning of black horizontal and vertical lines in GLCM image? Are they a problem?
N = numel(unique(img)); % img is uint8
glcm = graycomatrix(img, 'NumLevels', N);
imshow(glcm)

I suspect this is the problem: For the function graycomatrix, You have supplied a 'NumLevels' argument which is larger than the number of unique graylevels in your image. For instance, a 256-level (8-bit) image will have only 256 graylevels. Asking for 1000 levels in the output means 744 levels will have no data! i.e. Yes, this is a problem. You can check how many graylevels your image has using numel(unique(I)).
p.s. In the future, please attach the code you used to generate the problem.

graycomatrix calculates the GLCM from a scaled version of the image. Due to round-off errors in the scaling process the number of different intensity levels in the scaled image may be less than the number of different intensity levels in the original image .
Consider the following sample image:
img = uint8([ 48 161 209 64 133 240 166 227;
184 54 181 33 107 252 242 255
217 191 125 112 204 252 135 201
163 222 66 125 229 140 38 97
252 214 201 191 10 102 242 74
191 74 77 8 163 51 189 186]);
From the documentation (emphasis mine):
[glcms,SI] = graycomatrix(___) returns the scaled image, SI, used to calculate the gray-level co-occurrence matrix. The values in SI are between 1 and NumLevels.
If you set NumLevels to the number of different intensity levels (which in this example is 39)
N = numel(unique(img))
[glcm_scaled, img_scaled] = graycomatrix(img, 'NumLevels', N);
the returned GLCM has 39*39 elements. The issue is that the scaled image has only 28 different intensity levels:
>> img_scaled
img_scaled =
8 25 32 10 21 37 26 35
29 9 28 6 17 39 38 39
34 30 20 18 32 39 21 31
25 34 11 20 36 22 6 15
39 33 31 30 2 16 38 12
30 12 12 2 25 8 29 29
>> numel(unique(img_scaled))
ans =
28
As a consequence, the GLCM will have 11 rows and 11 columns in which all the entries are zero (black lines).
If you do not wish this to happen, you can map the intensity levels through a lookup table:
levels = unique(img);
N = numel(levels);
lut = zeros(256, 1);
for i=1:N;
index = uint16(levels(i)) + 1;
lut(index) = i;
end
img_lut = lut(uint16(img) + 1);
[glcm_mapped, img_mapped] = graycomatrix(img_lut, 'NumLevels', N, 'GrayLimits', []);
By doing so, img_mapped is exactly the same as img_lut and there is no black lines in the GLCM. Notice that by specifying empty brackets for the GrayLimits parameter, graycomatrix uses the minimum and maximum grayscale values in the input image as limits.

I was seeing the same behaviour under my own GLCM implementation.
The issue was that I was implementing the histogram equalization given a number of gray levels.
I compute the discretization of the image before dividing first and then enter to review if any row or column is given inly zeros values.

Related

imshow/imwrite changes all pixel values to 1

I have a Matlab dataset saved with .mat that I'm trying to process in Octave GUI. The data consist of images and I want to save them in a JPG format (or any other image format), but I'm having this strange behavior when trying to displaying or writing the images.
this is how part of the image displays as an array:
91 90 91 88 93
88 91 86 81 88
93 100 90 85 91
93 100 94 93 96
87 87 87 87 89
But when I write the image
imwrite(img, 'D:\image_test_1.jpg')
and read it again
img_read=imread('D:\image_test_1.jpg')
I end up with this:
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
I tried searching for the cause, but couldn't find a definitive answer or clarification to this problem. Even when I'm using imshow to display the image I end up with a blank image.
What happened to all the pixel values?
Configuring as uint8 Image
To indicate that this image is using an 8-bit scale/format we can caste the array as an uint8() (unsigned 8-bit integer). This format will assume the intensity values range from 0 to 255 (typical JPG format). I think the reason for the array showing up as 1s is that Octave is trying to parse the array as a double ranging from 0 to 1. Therefore the results of the array are reaching the ceiling of 1 since all the intensity values of the Image/img array are out of range (maxed out). Alternatively we can convert the array to double using the im2double() function or diving the original array by 255.
Image = [91 90 91 88 93;
88 91 86 81 88;
93 100 90 85 91;
93 100 94 93 96;
87 87 87 87 89];
Image = uint8(Image);
imwrite(Image, 'D:\image_test_1.jpg')
imshow(imread('D:\image_test_1.jpg'),'InitialMagnification','fit');
Ran using MATLAB R2019b

plot coordinate text file for regionprop usage - Matlab

Based on a previous question (read coordinate text file for regionprop usage - Matlab) I wish to plot the object with an extended boundaries (zeros+10) but it does not work. Any reason why?
Code:
clc;
clear;
filename = fullfile('E:/outline.txt');
fileID = fopen(filename);
C = textscan(fileID,'%d %d');
fclose(fileID);
xMax = double(max(C{1})-10)
yMax = double(max(C{2})+10)
bw=roipoly(zeros(xMax ,yMax ),C{1},C{2});
imshow(bw);
stats = regionprops(bw);
coordinate text file content is as follow:
88 10
87 11
87 12
88 13
88 14
92 21
93 22
93 23
94 24
95 25
100 33
101 34
102 34
103 34
103 33
103 32
103 31
103 30
103 29
103 28
103 27
102 26
102 25
101 24
101 23
100 22
100 21
100 20
99 19
99 18
94 12
93 12
92 12
91 11
90 11
xMax = double(max(C{1})-10)
That should probably be +10. This way you make the image smaller than your polygon.
If you want to extend the image on the left side also, add an offset to your polygon coordinates:
bw = roipoly(zeros(yMax, xMax), C{1}+5, C{2}+5);
Note also that I swapped xMax and yMax from your code, this might be another issue you're seeing. Matrix dimensions are specified as (height, width), as are indices into the matrix. But some functions such as roipoly take coordinates with x first and y second. This is a common pitfall with MATLAB syntax.
I just learned that the above is the same as
bw = roipoly(yMax, xMax, C{1}+5, C{2}+5);

MATLAB accessing conditional values and performing operation in single column

Just started MATLAB 2 days ago and I can't figure out a non-loop method (since I read they were slow/inefficient and MATLAB has better alternatives) to perform a simple task.
I have a matrix of 5 columns and 270 rows. What I want to do is:
if the value of an element in column 5 of matrix goodM is below 90, I want to take that element and and subtract it from 90.
So far I tried:
test = goodM(:,5) <= 90;
goodM(test) = 999;
It changes all goodM values within column 1 not 5 into 999, in addition this method doesn't allow me to perform operations on the elements below 90 in column 5. Any elegant solution to doing this?
edit:: goodM(:,5)(test) = 999; doesn't seem to work either so I have no idea to specify the target column.
I am assuming you are looking to operate on elements that have values below 90 as your text in the question reads, rather than 'below or equal to' as represented by '<=' as used in your code. So try this -
ind = find(goodM(:,5) < 90) %// Find indices in column 5 that have values less than 90
goodM(ind,5) = 90 - goodM(ind,5) %// Operate on those elements using indices obtained from previous step
Try this code:
b=90-a(a(:,5)<90,5);
For example:
a =
265 104 479 13 176
26 110 447 208 144
379 163 179 366 464
301 48 274 391 26
429 374 174 184 297
495 375 312 373 82
465 272 399 447 420
205 170 373 122 84
1 417 63 65 252
271 277 412 113 500
then,
b=90-a(a(:,5)<90,5);
b =
64
8
6

Selecting elements of a vector based on two vectors of starting and ending positions matlab

I would appreciate your help with the following problem in matlab:
I have a vector and I would like to select parts of it based on the following two vector of start and end indices of parts:
aa = [1 22 41 64 83 105 127 147 170 190 212 233]
bb = [21 40 63 82 104 126 146 169 189 211 232 252]
Basically I would like to perform some function on V(1:21), V(22:40),... V(233:252).
I have tried V(aa:bb) or V(aa(t):bb(t)) where t = 1:12 but I get only V(1:21), probably because V(22:40) has 19 elements compared to V(1:21) which has 22 elements.
Is there a fast way of programming this?
Put your selection in a cell array, and apply your function to each cell:
aa = [1 22 41 64 83 105 127 147 170 190 212 233]
bb = [21 40 63 82 104 126 146 169 189 211 232 252]
V = rand(252,1); % some sample data
selV = arrayfun(#(t) V(aa(t):bb(t)), 1:12,'uniformoutput',false);
result = cellfun(#yourfunction,selV)
% or
result = cellfun(#(selVi) yourfunction(selVi), selV);
If the function you want to apply has scalar output to every vector input, this should give you an 1x12 array. If the function gives vector output, you'll have to include the uniformoutput parameter:
result = cellfun(#(selVi) yourfunction(selVi), selV,'uniformoutput',false);
which gives you a 1x12 cell array.
If you want to run this in a highly condensed form, you can write (in two lines, for clarity)
aa = [1 22 41 64 83 105 127 147 170 190 212 233]
bb = [21 40 63 82 104 126 146 169 189 211 232 252]
V = rand(252,1); % some sample data borrowed from #Gunther
%# create an anonymous function that accepts start/end of range as input
myFunctionHandle = #(low,high)someFunction(V(low:high));
%# calculate result
%# if "someFunction" returns a scalar, you can drop the 'Uni',false part
%# from arrayfun
result = arrayfun(myFunctionHandle(low,high),aa,bb,'uni',false)
Note that this may run more slowly than an explicit loop at the moment, but arrayfun is likely to be multithreaded in a future release.

Adding multiple nth elements of a matrix repeatedly

I have a matrix 63 rows x 7 columns
I want to select every 7th,8th,9th ongoing value in each column and add them to create a new value.
i.e.
7 8 9th added to a new value
16 17 18th added to a new value...etc
25 26 27th
34 35 36th
43 44 45th
52 53 54th
61 62 63th
So I should end up with a 7x7 matrix.
Without doing this manually, is there a simple command so that if the dimensions of the matrix changes, the output will always be correct?
You can do that easily with a bit of reshaping.
originalMatrix = (1:63)'*(1:7); %'
[nRows,nCols] = size(originalMatrix); %# =63 in this example
stepSize = 9;
nTriplets = floor(nRows/stepSize); %# =7 in this example
%# create index list
idx = bsxfun(#minus,stepSize:stepSize:nRows,[2 1 0]'); %'
idx = idx(:); %# reshape to a vector
%# create 3-by-7-by-7 array from original matrix
tmpMatrix = reshape(originalMatrix(idx,:),3,nTriplets,nCols);
%# sum along dim 1 (to sum e.g. the 7th, 8th, and 9th value)
result = squeeze(sum(tmpMatrix,1));
result =
24 48 72 96 120 144 168
51 102 153 204 255 306 357
78 156 234 312 390 468 546
105 210 315 420 525 630 735
132 264 396 528 660 792 924
159 318 477 636 795 954 1113
186 372 558 744 930 1116 1302
matrix=(1:63)'*(1:7);
n=7;
startind = n:(n+2):size(matrix,1);
endind = (n+2):(n+2):size(matrix,1);
tmp=cumsum(matrix);
tmp(endind,:)-tmp(startind,:)
This will, of course, only work if startind and endind have the same length, which would not be the case for, say, a matrix of size 62x7.
If I had understood your question properly, this slip of code should do what you want. But I admit, maybe it's not the most efficient Matlab code ever-written...
k = 9; n = 7; m = k*n; % 63
A = randi(5,m,n);
startIdx = k*(1:n)+n-k;
endIdx = k*(1:n);
B = zeros(n,n);
for i = 1:n
tmp = A(startIdx(i):endIdx(i),:);
B(i,:) = sum(tmp,1);
end