How can I apply the jet-colormap to an image matrix with non-integer entries in an imwrite command?
18 views (last 30 days)
Show older comments
Hello everybody :-),
I am currently working on my master's thesis and in desperate need of some help.
I have 800 grey scale images of a bone which I imread (works fine) .
for z=1:800
filename = [num2str(z) '.tif'];
s=([folder_path filename]);
slice = imread(s);
dim_x=size(slice,1);
dim_y=size(slice,2);
data2D=zeros(dim_x,dim_y,'uint8');
data2D(:,:)=uint8(slice);
The grey values < GV_thr are 0 and the grey values GV_thr:256 define the osseous matter. Then, I want to replace values GV_thr:256 of the image matrix (='data2D') with values of the vector 'nu' which depend on the grey values, nu(GV); min(nu)=0.4544 and max(nu)=0.4657. (10200 is a factor to get rid of the decimal places and gain a certain range in respect of the integer-based colormap.) (works fine too, but very slowly)
nu_rounded=round(nu*10200) % factor to get certain range for the colormap
for i=GV_thr:256
data2D(data2D(:,:) == i) = nu_rounded(i)
end
maxVal = nu12_rounded(GV_thr); % (=4750)
minVal = nu12_rounded(256); % (=4635)
range = maxVal-minVal; % (=115)
Now, I want to save the image with the same dimensions and everything, but in color. That can be achieved with 'imwrite' defining a colormap. However, if I apply 'cmap = [zeros(minVal,3); jet(range)]' I get an error, because maxVal > 256. So, I employed a trick and re-replaced the entries of the 'nu'-Vector in the image matrix (='data2D') with new grey values. (see below) This new grey value distribution is based on the intensity of 'nu' this time, which is the whole point of this.
Vector_nu12=[minVal:maxVal]
Vector_GV=[GV_thr:256]
for ii=1:range
data2D(data2D(:,:) == Vector_nu12(ii)) = Vector_GV(ii)
end
minVal1 = min(Vector_GV); % (=141)
maxVal1 = max(Vector_GV); % (=256)
range1 = maxVal1-minVal1; % (=115)
The zeros of the image shall remain black and the bone tissue shall be demonstrated by the jet colormap.
cmap = [zeros(minVal1,3); jet(range1)];
% Imwrite new images
imwrite(data2D, colormap(cmap), [num2str(fpath),num2str(z),'.tiff'])
disp(['saved ',num2str(z),'/',num2str(num_images)])
end
However, the surrounding area of the bone is black as I wanted it to be, but the bone itself is just red and not in the jet color range. I don't understand what can be the reason for this as I already used this method applying only 1 replacement- step and it worked just fine.
I hope someone can spare some time to look through the code and can give me some hints. :-)
Thank you very much in advance!
8 Comments
Answers (3)
Image Analyst
on 5 Jan 2015
Try this:
minValue = 0.4544
maxValue = 0.4657
% Make image with values from minValue to maxValue.
grayImage = (maxValue - minValue) * rand(480, 640) + minValue;
% Make some 0's in it.
zeroLocations = randperm(numel(grayImage), 10000);
grayImage(zeroLocations) = 0;
% Now we have our starting image.
% It has some 0's with most values between .4544 and .4657.
% Map 0's to minValue so mat2gray will normalize over the range we want.
zeroLocations = grayImage == 0;
grayImage(zeroLocations) = minValue;
% Normalize the image to [0,255].
normalizedImage = uint8(255 * mat2gray(grayImage)); % Map to [0,255]
% Put zeros back in.
normalizedImage(zeroLocations) = 0;
% Convert to color image
rgbImage = ind2rgb(normalizedImage, jet(256));
imshow(rgbImage);
The first half is just to get an image with values in the "nu" range plus some scattered zeros. The second half does what you want I think.
Guillaume
on 5 Jan 2015
Edited: Guillaume
on 6 Jan 2015
Instead of replacing the values 140 with 4750... and finally 255 with 4635, Matlab took the highest integer 255 on every non-zero place
That would be because you've defined data2D as uint8. The maximum value of a uint8 is 255. If you convert data2D to uint16 (or double) beforehand, you won't have that problem
works fine too, but very slowly
Use matrix indexing instead, avoids the loop. With your first example:
nu_rounded=round(nu*10200)
rescaled = nu_rounded(data2D); %as simple as that!
%to restore the values below gv_thr to their original values:
belowthreshold = data2D < GV_thr
rescaled(belowthreshold) = data2D(belowthreshold);
%or if you want to set all the values below the threshold to 0:
nu_rounded=round(nu*10200)
nu_rounded(1:GV_thr-1) = 0;
rescaled = nu_rounded(data2D)
3 Comments
Guillaume
on 6 Jan 2015
Reading the values as uint8 is fine, but since you do this in a loop:
data2D(data2D(:,:) == i) = nu_rounded(i)
The values of nu_rounded are coerced to 8 bit. So prior to your loop you would need to convert data2D to uint16 or double.
If you use matrix indexing as in
data2D = nu_rounded(data2D);
it's not a problem anymore as data2D will be whatever type nu_rounded is. The problem as you found out is that values in data2D start at 0, which is not a valid subscript index. You would have run into the same problem with your original code if your GV_thr was set to 0 by the way.
One possible workaround:
nu_rounded = [0 round(nu*10200)]; %shift values by one index
nu_rounded(1:GV_thr) = 0; %to set everything below GV_thr to 0
%or
nu_rounded(1:GV_thr) = 0:GV_thr to keep everything below GV_thr the same
data2D = nu_rounded(uint16(data2D)+1); %widen data2D so 1 can be added without overflow. Add 1 to avoid index 0 (hence the shift on the first line)
See Also
Categories
Find more on Blue in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!