How can I apply the jet-colormap to an image matrix with non-integer entries in an imwrite command?

18 views (last 30 days)
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
Gwen
Gwen on 5 Jan 2015
Thank you! :-) I already read some of these pages and tried the range of one color, but my prof wants to have the jet color range and it would be consistent with my previous figures.
Gwen
Gwen on 5 Jan 2015
Edited: Gwen on 5 Jan 2015
However, I now know that the first replacement didn't work:
Instead of replacing the values 140 with 4750... and finally 255 with 4635, Matlab took the highest integer 255 on every non-zero place. So the jet colormap is successfully applied in the end and the bone is red, because there is only 1 integer left (255).
Summarizing that, my main problems here are that I can't replace the 8 bit grey values of the image matrix with values above 255 and that the jet colormap can't be applied to non-integers. Is there a solution to either of the two problems or another way around?

Sign in to comment.

Answers (3)

Image Analyst
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.
  1 Comment
Gwen
Gwen on 5 Jan 2015
Thank you so much for your efforts!!! I will take a closer look at it in the evening.
The crucial point is however that I have to imread the image of the bone, get the image matrix with the GVs and then I want to replace the i. grey value with the i. element of the vector nu. This is important to settle the places and intensities of the entries in the new image matrix.

Sign in to comment.


Image Analyst
Image Analyst on 5 Jan 2015
Why not just use intlut() and ind2rgb()?
  1 Comment
Gwen
Gwen on 5 Jan 2015
Edited: Gwen on 5 Jan 2015
The problem is that I don't have integer values in my image matrix any more but instead the values of nu = 0.4544 - 0.4657 (and 0). The reason why I replaced the GV with the nu- values at all is because the nu- values have a different distribution than the grey values: they are not linearly spaced like the grey values.

Sign in to comment.


Guillaume
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
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)

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!