Issue operations on RGB layers

Hi all,

I have an RGB image with bluish particles. To see them better, I am extracting the blue and red layers, then subtract blue from red. It works perfectly in ImageJ but somehow it doesn't in IgorPro. I even tried to import the imageJ image in Igor and run some checks pixel by pixel, and sometimes there is a difference indeed, small but enough to mess up the final result.

I attach some images of the final comparison to show the issue.

Any help much appreciated!

 

Code used is (I didn't use ImageTransform/P=... to keep the door open to working with other c1,c2,c3 combinations):

function analyse()
wave image

variable c1 = 1
variable c2 = 0
variable c3 = 0
Duplicate/O/R=[][][0] image, red2DWave
Redimension/N=(-1, -1, 0) red2DWave
red2DWave=c1*image[p][q][0]+c2*image[p][q][1]+c3*image[p][q][2]

c1 = 0
c2 = 0 
c3 = 1 
Duplicate/O/R=[][][0] image, blue2DWave
Redimension/N=(-1, -1, 0) blue2DWave   
blue2DWave=c1*image[p][q][0]+c2*image[p][q][1]+c3*image[p][q][2]

Duplicate/O blue2DWave, result
result=blue2DWave-red2DWave
Display;AppendImage result

end

 

Original Image Result with Image J Result with my Igor function

The 3rd image looks correct to me. If you subtract the red channel from the blue, all the red features should still be there, only as negative features.

Try result[][] = blue2DWave[p][q] > red2DWave[p][q] to display only pixels where the blue channel is larger than the red channel? That could be what you are looking at in the 2nd image.

 

PS

Also be careful that you are not working with unsigned byte waves /B/U when you are subtracting two values from each other that may end up being negative

Thanks Olelytken,

the unsigned byte suggestion was good, indeed this way the "result" image was better but not good yet.

I tried to use the line you suggested and also used blue-red if blue2DWave[p][q] > red2DWave[p][q], else 0.

There's far too much white in the Igor image, where it should be black

 

If it helps, here is the ImageJ code. There's a contrast enhancement too but that does little, the starting difference image is very good already:

 

setBatchMode(true);

fPath = getDirectory("Pick a directory to analyse");
fList = getFileList(fPath);
File.makeDirectory(fPath+"results");

for (f=0;f<lengthOf(fList);f++){

open(fPath+fList[f]);
run("Split Channels");      // Split the active image into R G B channels, ImageJ adds a " (blue)", " (green)" etc to the name of the original image etc
imageCalculator("Subtract create", fList[f]+" (blue)", fList[f]+" (red)");  // just subtracts red from blue
run("Enhance Contrast...", "saturated=0.35");

saveAs("tif",fPath+"results/"+"subtracted_"+fList[f]);
close();
}

If you are willing, please post an experiment containing the image (or the original image), and identify what the result should look like.

I offer a few thoughts about your processing.

* You should likely transform the three r, g, b images to floating point before subtracting any one from any other one. After subtraction, add back the negative offset to bring the lowest value to zero. Finally, convert the resultant image back to 8-bit (or 16-bit) as desired.

* If you are using the red to define the background and the background is (mostly) constant, you may be better off when you simply subtract a constant background from the blue channel rather than subtracting the red from the blue.

* You should be able to accentuate the particles in the blue channel if you use a thresholding method on the (background corrected) blue channel and then use the resultant threshold as a mask on the blue channel.

Finally, I suggest my Image Tools package as an option. With Image Tools, if your original image is a TIFF rgb, you can load it directly split as three channels and perform a host of UI-driven operations on any one of the three planes, including subtracting a background, thresholding, and masking.

https://www.wavemetrics.com/node/21002

Hello DavideT,

You got some sound advice above but I would like to add a few suggestions:

// Replace this
variable c1 = 1
variable c2 = 0
variable c3 = 0
Duplicate/O/R=[][][0] image, red2DWave
Redimension/N=(-1, -1, 0) red2DWave
red2DWave=c1*image[p][q][0]+c2*image[p][q][1]+c3*image[p][q][2]

// with
MatrixOP/O red2DWave=image[][][0]

// Replace this
c1 = 0
c2 = 0
c3 = 1
Duplicate/O/R=[][][0] image, blue2DWave
Redimension/N=(-1, -1, 0) blue2DWave  
blue2DWave=c1*image[p][q][0]+c2*image[p][q][1]+c3*image[p][q][2]

// with
MatrixOP/O blue2DWave=image[][][2]

// replace this
Duplicate/O blue2DWave, result
result=blue2DWave-red2DWave

// with
MatrixOP/O result=blue2DWave-red2DWave

Note that the last MatrixOP command will create a result wave of an appropriate type (if the blue and red waves are unsigned byte then result will be signed 16 bit.  This allows you to implement jjweimer's first suggestion without going into single precision float.

Note that depending on the source of your image sometimes the RGB channels are not "pure", i.e., the spectral response of some channels is not unimodal.  Some years back I dealt with a camera where it made sense to rotate the hue before splitting into RGB channels.

 

Thanks a lot everyone. I will try the suggestions above (thanks Igor for the shortcut, I thought of avoiding MatrixOP to be more free to run other changes with c1, c2, c3 but never know if it fired back heavily!) asap and I will post a full experiment with the waves in, if still it doesn't work.

Sure I will try the package from JJweimer too, very curious about it.

I will let you know of the results

Motivated by your posting, I have added split math operations to the Image Tools package. The processing that you defined by your function would be as follows:

  • load the rgb TIFF image using the options to extract the red and blue channels *as individual images* (not as a stack)
  • display the blue channel
  • choose the red channel for a split view
  • go to the Process tab and choose Split Math
  • decide how to handle negative values (I recommend either offsetting or setting to zero)
  • select subtract and click Apply

The result will appear in an image with a suffix "_sms". The result is a floating point image.

Eventually, I hope to add an option to do split math using string input equations such as L^2 * R (meaning the square of the left times the right). When this happens, processing for color scales would be via an equation L - c*R, where c is a numeric value for the color conversion factor.

In the meantime, I would be interested to hear whether you find the package handles your needs as well as whether any issues arise.