13 Feb 2013 05:49 AM |
|
Hi,
I'm a chemist and at work we use IDL to make programs to visualize our data. One of such data visualizations are Red Green Blue overlay images, where each color represents a different element/compound and the total image shows the distribution of these elements in a sample. Below you can see the code we use to create these RGB images (I start off here with generation of some random data, just to give you an idea):
;Create image data
a=fltarr(500,500,3)
for i=0,499 do if i lt 300 and i gt 200 then a(i,*,0)= i
for i=0,499 do if i lt 300 and i gt 200 then a(*,i,0)= i
for i=0,499 do if i lt 100 and i gt 0 then a(i,*,1)= i
for i=0,499 do if i lt 100 and i gt 0 then a(*,i,1)= i
for i=0,499 do if i lt 500 and i gt 400 then a(i,*,2)= i
for i=0,499 do if i lt 500 and i gt 400 then a(*,i,2)= i
; scale image
a= bytscl(a)
; plot image
b = image(a)
As one can see, the lowest intensities (0) will be plotted as black points. This greatly reduces the visibility of the images when printing them on paper. For this reason we're looking for a way to make sure a color table is used that has white as lowest intensity and black as highest. We have tried many things, some of which are:
- invert bytscl : this does set lowest intensity as white and highest intensity as black, yet the colors (R,G and B) are inverted as well, resulting in not-nice-looking images
- set background white: this may seem the most obvious choice, yet it doesn't help anything as the black points with lowest intensity are simply plotted on top of the white background, resulting as exactly the same image as before.
- plot each color seperately, defining an appropriate colortable running from white to black over the color: this would work, except that either the different colors are plotted in other windows, or are overplotted in the same window yet only showing the last plotted colorimage. The red and green are simply not visible then. One could use transparency here, but I'm afraid this is too much data manipulation in my opinion (indeed, with different transparancies the image would look completely different).
I'm wondering whether you have some ideas on how I can create these images? Important things are that the RGB signals should be scaled from white (lowest intensity) to black (highest intensity) as in the Brewer colortables 49,53 and 62, the data should be scaled in some way to take concentration effects into account and a point containing both R and G signals, yet no B, should be colored yellow etc.
I hope you can help me out with my problem and thanks in advance for thinking about this, to me, difficult problem.
|
|
|
|
Deleted User New Member
Posts:  
28 Feb 2013 05:56 AM |
|
Does anyone know the code IDL runs through when the image function is called? I ask this because I believe the colortable is reset to the standard red green and blue values when a 3D array is defined to the image function. If I would have the code of the image function, maybe I could find a place in there where they define the colortable and I could choose a different colortable instead...
In the meantime I also tried to set
tvlct, newred, newgreen, newblue
before plotting the 3D array using the image function or tv procedure, where newred = reverse(red), newgreen=reverse(green) and newblue = reverse(blue) (red green and blue were found by using tvlct, red, green, blue, /get before plotting anything). This also does not change the image.
All help is appreciated, as I'm nearing the end of my IDL-Latin...
|
|
|
|
Deleted User New Member
Posts:  
28 Feb 2013 09:26 AM |
|
These are apples and oranges. TVLCT, LOADCT, XLOADCT, etc., are part of the older graphics systems called "Direct" graphics. The IMAGE(), PLOT(), CONTOUR(), etc. functions are part of IDL's new Graphics system and will not honor color tables defined by the older graphics routines. However, you can still use color tables with the IMAGE() function in the following way:
i = image(dist(255, 255), RGB_TABLE=39)
The color table numbers are the same, you can still use all of the same color tables that are available to the older graphics system. In addition, you can define your own color table as a 3XN array and supply that to the RGB_TABLE keyword. See the following link for details:
http://www.exelisvis.com/docs/IMAGE.html
Hopefully this helps. When spelunking into the new Graphics system your best friend will be the graphics examples located at the link below. Good luck!
http://www.exelisvis.com/docs/visualize.html
-Josh
Exelis VIS
|
|
|
|
Deleted User New Member
Posts:  
28 Feb 2013 09:48 AM |
|
Hi Ptack,
Also, in your example, you are already using your "color table", because you are giving to the IMAGE() function a triplet that contains an array of bytes, in this case of dimentions [500, 500, 3], that when you give it to IMAGE() it will use it as an RGB triplet. See the IDL help for IMAGE:
http://www.exelisvis.com/.../IMAGE.html#RGB_TABL
It says this:
"If Data is three-dimensional, then if any one of the dimensions is 3, it is assumed to represent the red, green, and blue channels. "
So you need to change your data?. I think the best is what Josh said, use color tables with RGB_TABLE keyword, or create your own color table.
Cheers
fernando
|
|
|
|
Deleted User New Member
Posts:  
01 Mar 2013 06:37 AM |
|
Thanks for your answers Josh and Fernandos!
I realized the tv procedures are old-school and the image function is the new way to go, but I tried both as the image function did not solve my problems. So I realize they're different, yet if any of the two could help me get an answer, I'd be more than happy to use it (even if it is the old procedure)
In any case, using a different colortable, as josh suggests, does not work because I'm working with a 3D array where the image function automatically considers each data point to give the RGB values, which correspond to a certain color.
The data I want to visualize is an intensity image, which can range from 0 to a few million counts. Each 2D array (in the 3D array) represents the intensity distribution of a different element in a sample (say Zn, Fe and Cu). Before plotting I would scale the values to give values between 0 and 255 using the bytscl function, so this makes the pixel values in the correct color range.
Now I want to create an image which shows the Zn distribution in red, Fe in green and Cu in blue, in such a way that when all three elements (Fe, Cu and Zn) are present in the same pixel, this pixel is plotted as black. When none of the elements are present in a pixel, it should be plotted as white. When only Fe and Zn are found in a pixel, but no Cu, I'd want the pixel to show the color equal to 155*green+200*red if the scaled intensity of Fe=155 and the scaled intensity of Zn=200 (does this make sense?).
In the end I'd want an image that looks like this: http://ars.els-cdn.com/content/image/1-s2.0-S0003267010001546-gr7.jpg (this is actually an image from one of the researchers in the same group as I work in) but instead of scaling from black to white, I want it inverted, yet I want to keep the nice red, blue and green colors. (because I tried reversing my image array by subtracting my data values from 255 - so 255-bytscl(a) - yet this drew the image in the pink, yellow and light blue, which I do not like very much).
This means that as long as I want to supply a 3D array to the image function, I'd have to change my data values in some way (as fernandos suggests) to get the proper color scaling as RGB_table does not work in this case.
In the past I also tried simply drawing the red image first, then green followed by blue using specific colortables (using the RGB_TABLE keyword). Problem here is that this will by default plot each image in a different window, or when I also use the /overplot keyword only the last (blue in this case) image is displayed. One could argue I could set a certain transparancy to make each layer visible, yet this is not really the data visualisation I'm after (see above).
So in the end I believe I'm rather... stuck, and I have to find a way to modify my original 3D data running from 0-255, where each 2D array represents the R, G and B channel in such a way that plotting it using the image function will show the correct colors I want to use. Problem is: how on earth could I do this?
A second option would be to convert my 3D array to a 2D array in some way, and plot this one with a personally built color table. But again my problem is that I have no idea how to do this properly.
So all ideas are still very much welcome :)
|
|
|
|
Deleted User New Member
Posts:  
01 Mar 2013 09:09 AM |
|
Cool, ok, I think I understand now. One approach would be to start with the 3D array that you already have as you mentioned, where the Red, Green, and Blue channels represent each element. Then after that, loop through the array marking the pixels that meet the conditions you want as certain colors (black, white, etc.). For example (say for a 10,10,3 array):
for i=0, 9 do begin
for j=0, 9 do begin
if (Total(array[j,i,*] eq 0) eq 3) then begin ;none present, all zeros
array[j,i,*] = 255 ; set to white
endif else if (Total(array[j,i,*] eq 0) eq 0) then begin ;all present, no zeros
array[j,i,*] = 0 ; set to black
endif else if (... some other condition ...) then begin
etc....
endif
endfor
endfor
i = image(array)
Then just plot your image without a color table, as an RGB image. I think this may be more what you are looking for. In this way you can mark the pixels of interest as whatever color you want. In the above example, "array[j,i,*] eq 0" gives a 3 element boolean array, which is "true" only when the "eq 0" condition is met. So for the all zero case, [1,1,1]. Then "Total([1,1,1])" is 3.
Of course, you could have any number of conditions in that if-else block to set pixel values the way that you need. Hopefully this helps.
-Josh
Exelis VIS
|
|
|
|
Deleted User New Member
Posts:  
04 Mar 2013 03:38 AM |
|
Yes, I do believe this is as good as it'll get as far as the imaging goes.
It's not quite sufficient to just swap black (0,0,0) to white (255,255,255) and the other way around for my purposes, as there would still be a lot of points like (0,3,5) that are still nearly black which I'd want to be nearly white as well. Furthermore, I'd also want the green, blue and red to be scaled from light to dark as well (instead of dark to light as is the case now). In the end this would come down to re-defining every color in the spectrum (some 17million options) which is too much to be bothered with to me :)
So I think I'll just work with a cut-off that should not be plotted (to remove the black pixels) or else way simply keep on using the black background images.
Thanks for the help and assistance in any case!
|
|
|
|