![](/profiles/wavemetrics/themes/wavemetrics/logo.png)
Rescaling image contrast: excluding outlier pixel values
![](/sites/default/files/styles/thumbnail/public/sjr51/profile-images/2018-07/cube.png?itok=iXDZATA2)
Hello,
I am working with some images and need to rescale the contrast on those image for visualisation. If I scale to the min-max for the image, it still appears quite dark because I have a handful of extremely bright pixels in the image. In ImageJ the way around this is a button called Auto which seems to trim the top (and bottom) 0.35% of pixels according to the shape of the image histogram. I have coded something similar in Igor* and it works, but it is slow. I'm wondering if there is a faster way to get these values. Is there a function to specify the 99.65th (or Xth) percentile of an image and use that for the scaling? Maybe a histogram function would work? Any help or other ideas welcome.
* I calculate the Min and Max like this and store them in a wave to then do the rescaling in the calling function. It's slow because I duplicate-redimension-sort for each channel and for each z-position.
STATIC Function MakeMinMaxWave(ImageMat,rCh,gCh,bCh) Wave ImageMat Variable rCh,gCh,bCh // index of chunk for each channel. -1 means blank String rgbList = num2str(rCh) + ";" + num2str(gCh) + ";" + num2str(bCh) + ";" Variable nZ = DimSize(ImageMat,2) Make/O/N=(nZ,2,3) minMaxW // rows for z, columns min and max, layers r g b Variable totalOrigPix = DimSize(ImageMat,0) * DimSize(ImageMat,1) Variable chSelect Variable i,j for(i = 0; i < nZ; i += 1) for(j = 0; j < 3; j += 1) chSelect = str2num(StringFromList(j,rgbList)) if(chSelect == -1) continue endif Duplicate/O/FREE/RMD=[][][i][chSelect] ImageMat, tempW Redimension/N=(totalOrigPix) tempW Sort tempW,tempW minMaxW[i][0][j] = tempW[0] minMaxW[i][1][j] = tempW[floor(totalOrigPix-(totalOrigPix * 0.003))] // ImageJ does something like 0.35% endfor endfor End
Are you mainly interested in thresholding for display within Igor? If so, it's not necessarily useful to change the values in the original image. As far as thresholding for display, Igor seems to have better transformations for display of single color images than it does three color images. For example, "ctab" and "cindex", which can respectively implement thresholding and non-linear transforms like gamma functions, don't appear to be available for RGB images.
A sort of work around that I have used is to split the RGB layers into 3 separate 2D matrices and then overlay them (with newImage then appendImage). This approach only became viable with the implementation transparency in Igor 7. One has to append them and then assign an appropriate 4-column custom color table to each, with all alpha values set to 1/3rd of maximum.
This allows the following much faster thresholding for each image. For example, here is how you would threshold the red channel:
ModifyImage originalImage_red ctab= {lowerThreshold,upperThreshold,myRedsWithTransparency,0}
With single color images, there are some helpful built in functions like the "Image Range Adjustment" dialog in the Image menu, which modifies the ctab thresholds.
If you really do want to modify the original data values, you can do the following (among other possibilities). Say you wanted to quickly apply thresholds set with the "Image Range Adjustment" Dialog. You can click "Save Range" in this dialog, save as "MIP_Range0" and then run:
In case you still want to determine the lower and upper thresholds as % pixel values: once you have each color component in separate 2D waves you could run the following (though there may be a less involved approach I am not aware of):
You may also want to look at the "imageThreshold" function
July 24, 2018 at 05:52 am - Permalink
Thanks aoa this is really helpful! The overlay approach is nice since I only want to change the contrast of the images as displayed. Possibly breaking each image into channels as 2D waves might not be needed. It looks like it is possible to display/append each layer using /G=1 and specify the trace instance to be a specific layer, but I need to investigate further.
July 24, 2018 at 08:59 am - Permalink
Hi sjr51,
Could you perhaps supply a sample image.
Best,
_sk
July 25, 2018 at 12:55 am - Permalink
@_sk I am attaching a zipped tif file. This is one channel and one z-layer that I'm dealing with. This channel is the most difficult to scale.
July 25, 2018 at 07:00 am - Permalink
sjr51,
I tried something like this on your image.
And idk if it works, but I think it does more or less what you wanted, unless I have misunderstood (which is quite possible).
Best,
_sk
edit: I am including some before and after images
July 25, 2018 at 08:19 am - Permalink
@_sk
Thank you for your help. I think this combined with the overlay approach suggested by aoa should work.
July 25, 2018 at 08:49 am - Permalink
In reply to @_sk Thank you for your… by sjr51
Yes, it seems like it will do what you wanted. Also note, that if you attach different images (i.e. different channels) to the same graph the above code will run through them, namely, the do.. while loop.
July 26, 2018 at 12:29 am - Permalink
I thought I would leave another comment here to help anyone searching the forum for this topic.
aoa's code for thresholding worked great and was much faster than my code. I also looked at the way Igor does Image Range adjustment. I didn't know about this function when I wrote my question. It's similar to aoa's suggestion, the function is WMCont94ButtonProc in case anyone is interested.
While I liked the idea of using three planes and changing the display range, I couldn't get this to work. Three layers of one-third opacity did not sum correctly for me (see code below for an example). This left a greyish colour where there should have been black. Maybe this is because of the background of the graph window? In the end I was happy to make a copy of the images and adjust their values directly. So I didn't pursue further.
The second function below shows how to make the RGBA waves for display as mentioned above.
August 3, 2018 at 07:05 am - Permalink
In reply to I thought I would leave… by sjr51
Looking at the three image overlay idea again, I agree that it's imperfect. I edited your code, sjr, to see what different color combinations look like. I think the main issue is that in this design is that each component is at most 1/3rd its maximum value.
I think it would be really nice if Igor would allow control of each color component with a dedicated wave. I don't think that's currently possible.
August 3, 2018 at 11:15 am - Permalink