Issue operations on RGB layers
DavideT
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
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
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
July 13, 2023 at 04:17 am - Permalink
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
July 13, 2023 at 05:45 am - Permalink
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();
}
July 13, 2023 at 05:47 am - Permalink
If you are willing, please post an experiment containing the image (or the original image), and identify what the result should look like.
July 13, 2023 at 10:14 am - Permalink
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
July 13, 2023 at 01:18 pm - Permalink
Hello DavideT,
You got some sound advice above but I would like to add a few suggestions:
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.
July 13, 2023 at 04:43 pm - Permalink
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
July 13, 2023 at 10:36 pm - Permalink
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:
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.
July 16, 2023 at 09:54 am - Permalink