I just wrote my first macro to calclate binary granulometry.
Hi All, I just wrote my first macro to calclate binary granulometry. It worked but still need your kind help. The code is: run("Blobs (25K)"); run("Make Binary"); // select object areas/pisels run("Duplicate...", "title=erode.gif"); // for keeping sequentially eroded images run("Duplicate...", "title=size-map.gif"); // for the result size map. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1;i<12;i++) { selectWindow("erode.gif"); run("Erode"); run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate all the way back. for (j=0;j<i;j++) { run("Dilate"); } run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=size-map.gif operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } selectWindow("erode.gif"); close(); selectWindow("size-map.gif"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Histogram"); // to get mean, std, and etc. But how can I exclude background pixels? Problems: 1. What's the best way to detect an images when all seleceted areas are eroded away? I tried and error with this image to set the loop with 12 erosions. It will be nice to detect that automatically and stop the loop. 2. The histogram at the end calculates mean and std including background pixel (value=0). Is there a way to calculate with only selected pixels (value > 0)? 3. Erosion and dilation are pretty fast, the adding (image calculator) is very slow. (I turned on the macro recorder to see the progress) Is there a good way to speed up? write in Java? 4. Any other software available for binary granulometry? Matlab? ImagePro? 5. Any other coments are welcome. Thanks in advance for your comments/answers. Li-Ping (Li) Yuan |
Hi Li,
not an attempt to answer your questions, but an alternative way of doing something similar: It seems that you want to have statistics on the particles. Assuming that 'erode' would be circular symmetric (it is not) your macro would give statistics on the maximum distance from the center. This is similar to, but not equal to 0.5*MinFeret width. Feret (caliper length): you can get it directly from 'Analyze particles' with suitable 'set measurements'. If you are not satisfied with Feret width, you can still do it with 'Analyze Particles': Run Process>Binary>Distance Map on your binary image, threshold at 1-255, then run the particle analyzer. You can then use 'Distribution' to get a histogram of the maxima, i.e., the maximum distance from the center. Your macro would give the statistics in a different way: larger particles would get a larger weight. If you want this, you have to multiply the 'max' and 'area' columns of the particle analyzer results and do the histogram from this. A few more remarks on your code: - When using binary operations like 'erode' in a macro, always set the binary options first, otherwise you might get an undesired results. By setting the options, you could also do several iterations at once, no need for the 'j' loop. - getImageStatistics or getRawStatistics give you min&max, it would tell you when everything is eroded. - Histogram is limited to the current selection, so you can easily threshold your image at some level (e.g. 1-255) and then 'create selection'. Michael ________________________________________________________________ On 3 May 2010, at 20:38, Li-Ping Yuan wrote: > I just wrote my first macro to calclate binary granulometry. > Hi All, > > I just wrote my first macro to calclate binary granulometry. It > worked but still need your kind help. > > The code is: > > run("Blobs (25K)"); > run("Make Binary"); // select object areas/pisels > run("Duplicate...", "title=erode.gif"); // for keeping > sequentially eroded images > run("Duplicate...", "title=size-map.gif"); // for the result > size map. > run("Divide...", "value=255"); // initialize all selected pixels > with value 1 in size-map. > for (i=1;i<12;i++) { > selectWindow("erode.gif"); > run("Erode"); > run("Duplicate...", "title=dilate.gif"); // for each eroded > image, dilate all the way back. > for (j=0;j<i;j++) { > run("Dilate"); > } > run("Divide...", "value=255"); // for all survived pixels, > add one to the size map. > run("Image Calculator...", "image1=size-map.gif operation=Add > image2=dilate.gif "); > selectWindow("dilate.gif"); > close(); > } > selectWindow("erode.gif"); > close(); > selectWindow("size-map.gif"); > run("Enhance Contrast", "saturated=0.5"); // to see the result. > run("Histogram"); // to get mean, std, and etc. But how can I > exclude background pixels? > > Problems: > 1. What's the best way to detect an images when all seleceted > areas are eroded away? I tried and error with this image to set > the loop with 12 erosions. It will be nice to detect that > automatically and stop the loop. > 2. The histogram at the end calculates mean and std including > background pixel (value=0). Is there a way to calculate with only > selected pixels (value > 0)? > 3. Erosion and dilation are pretty fast, the adding (image > calculator) is very slow. (I turned on the macro recorder to see > the progress) Is there a good way to speed up? write in Java? > 4. Any other software available for binary granulometry? Matlab? > ImagePro? > 5. Any other coments are welcome. > Thanks in advance for your comments/answers. > Li-Ping (Li) Yuan > |
In reply to this post by Li-Ping Yuan
Hi All,
The purpose of this work is unclear. What do you want to measure or filter? Best regards, Dimiter -----Original Message----- From: Michael Schmid [mailto:[hidden email]] Sent: Tuesday 4 May 2010 11:56 Subject: Re: Binary granulometry macro Hi Li, not an attempt to answer your questions, but an alternative way of doing something similar: It seems that you want to have statistics on the particles. Assuming that 'erode' would be circular symmetric (it is not) your macro would give statistics on the maximum distance from the center. This is similar to, but not equal to 0.5*MinFeret width. Feret (caliper length): you can get it directly from 'Analyze particles' with suitable 'set measurements'. If you are not satisfied with Feret width, you can still do it with 'Analyze Particles': Run Process>Binary>Distance Map on your binary image, threshold at 1-255, then run the particle analyzer. You can then use 'Distribution' to get a histogram of the maxima, i.e., the maximum distance from the center. Your macro would give the statistics in a different way: larger particles would get a larger weight. If you want this, you have to multiply the 'max' and 'area' columns of the particle analyzer results and do the histogram from this. A few more remarks on your code: - When using binary operations like 'erode' in a macro, always set the binary options first, otherwise you might get an undesired results. By setting the options, you could also do several iterations at once, no need for the 'j' loop. - getImageStatistics or getRawStatistics give you min&max, it would tell you when everything is eroded. - Histogram is limited to the current selection, so you can easily threshold your image at some level (e.g. 1-255) and then 'create selection'. Michael ________________________________________________________________ On 3 May 2010, at 20:38, Li-Ping Yuan wrote: > I just wrote my first macro to calclate binary granulometry. > Hi All, > > I just wrote my first macro to calclate binary granulometry. It > worked but still need your kind help. > > The code is: > > run("Blobs (25K)"); > run("Make Binary"); // select object areas/pisels > run("Duplicate...", "title=erode.gif"); // for keeping > sequentially eroded images > run("Duplicate...", "title=size-map.gif"); // for the result > size map. > run("Divide...", "value=255"); // initialize all selected pixels > with value 1 in size-map. > for (i=1;i<12;i++) { > selectWindow("erode.gif"); > run("Erode"); > run("Duplicate...", "title=dilate.gif"); // for each eroded > image, dilate all the way back. > for (j=0;j<i;j++) { > run("Dilate"); > } > run("Divide...", "value=255"); // for all survived pixels, > add one to the size map. > run("Image Calculator...", "image1=size-map.gif operation=Add > image2=dilate.gif "); > selectWindow("dilate.gif"); > close(); > } > selectWindow("erode.gif"); > close(); > selectWindow("size-map.gif"); > run("Enhance Contrast", "saturated=0.5"); // to see the result. > run("Histogram"); // to get mean, std, and etc. But how can I > exclude background pixels? > > Problems: > 1. What's the best way to detect an images when all seleceted > areas are eroded away? I tried and error with this image to set > the loop with 12 erosions. It will be nice to detect that > automatically and stop the loop. > 2. The histogram at the end calculates mean and std including > background pixel (value=0). Is there a way to calculate with only > selected pixels (value > 0)? > 3. Erosion and dilation are pretty fast, the adding (image > calculator) is very slow. (I turned on the macro recorder to see > the progress) Is there a good way to speed up? write in Java? > 4. Any other software available for binary granulometry? Matlab? > ImagePro? > 5. Any other coments are welcome. > Thanks in advance for your comments/answers. > Li-Ping (Li) Yuan > |
Michael, Dimiter, and all,
. Thanks for the remarks on the code. They gave me good directions to find proper coding. (Still took a while due to my limited knowledge on ImageJ). My revised code is at the end of this e-mail. It gives the granulometry results for both particles and background. Any comments are welcome. Also thanks for providing the alternative approach. The alternative approach is good for particles. The power of granulometry is more than analyzing particles. I can invert this binary image and perform the granulometry on the background. What does it mean is a different issue. (In certain cases, it gives information of spatial distribution of particles; in other cases, the object might be studying the pore space between particle grains.) Yes, my code is weighted with area, not number of particles. In fact, it gives good measurements for slighted overlapped particles without the need to separate them. I realize that the default erosion/dilation is based on the 8 neighbor (chessboard) distance function. The result size map has blocky shapes. The distance map method gives a better Euclidean distance which is nice. I hope that there is a Euclidean granulometry exist, but I haven't seen one, at least not for binary granulometry. Just tried Dimiter's gray scale granulometry plugin on the binarized "blobs.gif". It uses Euclidean distance function which is very nice (and quite fast). However, the result on this binarized "Blobs.gif" image is quite different from what I got here. They should be close even the distance functions are different. I wonder whether because the different algorithm? Thanks again to Micheal and Dimiter's reply Li-Ping (Li) Yuan ------------------------------------------------------------------------------- run("Blobs (25K)"); run("Make Binary"); // select object areas/pisels run("Duplicate...", "title=erode.gif"); // for keeping sequentially eroded images run("Duplicate...", "title=Object_Size_Map"); // for the result size map of object areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Object_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Object_Size_Map"); run("Duplicate...", "title=Object_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Object_Area"); close(); // Do not want to see the mask. selectWindow("Object_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection. selectWindow("blobs.gif"); run("Duplicate...", "title=erode.gif"); run("Invert"); // Analyze background areas for object distribution information. run("Duplicate...", "title=Background_Size_Map"); // for the result size map of background areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Background_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Background_Size_Map"); run("Duplicate...", "title=Background_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Background_Area"); close(); // Do not want to see the mask. selectWindow("Background_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection ________________________________ From: Prodanov Dimiter <[hidden email]> To: [hidden email] Sent: Wed, May 5, 2010 4:08:58 AM Subject: Re: Binary granulometry macro Hi All, The purpose of this work is unclear. What do you want to measure or filter? Best regards, Dimiter -----Original Message----- From: Michael Schmid [mailto:[hidden email]] Sent: Tuesday 4 May 2010 11:56 Subject: Re: Binary granulometry macro Hi Li, not an attempt to answer your questions, but an alternative way of doing something similar: It seems that you want to have statistics on the particles. Assuming that 'erode' would be circular symmetric (it is not) your macro would give statistics on the maximum distance from the center. This is similar to, but not equal to 0.5*MinFeret width. Feret (caliper length): you can get it directly from 'Analyze particles' with suitable 'set measurements'. If you are not satisfied with Feret width, you can still do it with 'Analyze Particles': Run Process>Binary>Distance Map on your binary image, threshold at 1-255, then run the particle analyzer. You can then use 'Distribution' to get a histogram of the maxima, i.e., the maximum distance from the center. Your macro would give the statistics in a different way: larger particles would get a larger weight. If you want this, you have to multiply the 'max' and 'area' columns of the particle analyzer results and do the histogram from this. A few more remarks on your code: - When using binary operations like 'erode' in a macro, always set the binary options first, otherwise you might get an undesired results. By setting the options, you could also do several iterations at once, no need for the 'j' loop. - getImageStatistics or getRawStatistics give you min&max, it would tell you when everything is eroded. - Histogram is limited to the current selection, so you can easily threshold your image at some level (e.g. 1-255) and then 'create selection'. Michael ________________________________________________________________ On 3 May 2010, at 20:38, Li-Ping Yuan wrote: > I just wrote my first macro to calclate binary granulometry. > Hi All, > > I just wrote my first macro to calclate binary granulometry. It > worked but still need your kind help. > > The code is: > > run("Blobs (25K)"); > run("Make Binary"); // select object areas/pisels > run("Duplicate...", "title=erode.gif"); // for keeping > sequentially eroded images > run("Duplicate...", "title=size-map.gif"); // for the result > size map. > run("Divide...", "value=255"); // initialize all selected pixels > with value 1 in size-map. > for (i=1;i<12;i++) { > selectWindow("erode.gif"); > run("Erode"); > run("Duplicate...", "title=dilate.gif"); // for each eroded > image, dilate all the way back. > for (j=0;j<i;j++) { > run("Dilate"); > } > run("Divide...", "value=255"); // for all survived pixels, > add one to the size map. > run("Image Calculator...", "image1=size-map.gif operation=Add > image2=dilate.gif "); > selectWindow("dilate.gif"); > close(); > } > selectWindow("erode.gif"); > close(); > selectWindow("size-map.gif"); > run("Enhance Contrast", "saturated=0.5"); // to see the result. > run("Histogram"); // to get mean, std, and etc. But how can I > exclude background pixels? > > Problems: > 1. What's the best way to detect an images when all seleceted > areas are eroded away? I tried and error with this image to set > the loop with 12 erosions. It will be nice to detect that > automatically and stop the loop. > 2. The histogram at the end calculates mean and std including > background pixel (value=0). Is there a way to calculate with only > selected pixels (value > 0)? > 3. Erosion and dilation are pretty fast, the adding (image > calculator) is very slow. (I turned on the macro recorder to see > the progress) Is there a good way to speed up? write in Java? > 4. Any other software available for binary granulometry? Matlab? > ImagePro? > 5. Any other coments are welcome. > Thanks in advance for your comments/answers. > Li-Ping (Li) Yuan > |
Hi,
The blobs is not the best test case because the LUT is inverted so sometimes it gives counterintuitive results. Indeed, for binary erosion/dilation it is better to start from EDM or other metrics map. In the granulometry plugin I support several types of structuring elements -> several metrics. Best regards, Dimiter -----Original Message----- From: Li-Ping Yuan [mailto:[hidden email]] Sent: Thursday 6 May 2010 07:31 Subject: Re: Binary granulometry macro. Michael, Dimiter, and all, . Thanks for the remarks on the code. They gave me good directions to find proper coding. (Still took a while due to my limited knowledge on ImageJ). My revised code is at the end of this e-mail. It gives the granulometry results for both particles and background. Any comments are welcome. Also thanks for providing the alternative approach. The alternative approach is good for particles. The power of granulometry is more than analyzing particles. I can invert this binary image and perform the granulometry on the background. What does it mean is a different issue. (In certain cases, it gives information of spatial distribution of particles; in other cases, the object might be studying the pore space between particle grains.) Yes, my code is weighted with area, not number of particles. In fact, it gives good measurements for slighted overlapped particles without the need to separate them. I realize that the default erosion/dilation is based on the 8 neighbor (chessboard) distance function. The result size map has blocky shapes. The distance map method gives a better Euclidean distance which is nice. I hope that there is a Euclidean granulometry exist, but I haven't seen one, at least not for binary granulometry. Just tried Dimiter's gray scale granulometry plugin on the binarized "blobs.gif". It uses Euclidean distance function which is very nice (and quite fast). However, the result on this binarized "Blobs.gif" image is quite different from what I got here. They should be close even the distance functions are different. I wonder whether because the different algorithm? Thanks again to Micheal and Dimiter's reply Li-Ping (Li) Yuan ------------------------------------------------------------------------------- run("Blobs (25K)"); run("Make Binary"); // select object areas/pisels run("Duplicate...", "title=erode.gif"); // for keeping sequentially eroded images run("Duplicate...", "title=Object_Size_Map"); // for the result size map of object areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Object_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Object_Size_Map"); run("Duplicate...", "title=Object_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Object_Area"); close(); // Do not want to see the mask. selectWindow("Object_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection. selectWindow("blobs.gif"); run("Duplicate...", "title=erode.gif"); run("Invert"); // Analyze background areas for object distribution information. run("Duplicate...", "title=Background_Size_Map"); // for the result size map of background areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Background_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Background_Size_Map"); run("Duplicate...", "title=Background_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Background_Area"); close(); // Do not want to see the mask. selectWindow("Background_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection ________________________________ From: Prodanov Dimiter <[hidden email]> To: [hidden email] Sent: Wed, May 5, 2010 4:08:58 AM Subject: Re: Binary granulometry macro Hi All, The purpose of this work is unclear. What do you want to measure or filter? Best regards, Dimiter -----Original Message----- From: Michael Schmid [mailto:[hidden email]] Sent: Tuesday 4 May 2010 11:56 Subject: Re: Binary granulometry macro Hi Li, not an attempt to answer your questions, but an alternative way of doing something similar: It seems that you want to have statistics on the particles. Assuming that 'erode' would be circular symmetric (it is not) your macro would give statistics on the maximum distance from the center. This is similar to, but not equal to 0.5*MinFeret width. Feret (caliper length): you can get it directly from 'Analyze particles' with suitable 'set measurements'. If you are not satisfied with Feret width, you can still do it with 'Analyze Particles': Run Process>Binary>Distance Map on your binary image, threshold at 1-255, then run the particle analyzer. You can then use 'Distribution' to get a histogram of the maxima, i.e., the maximum distance from the center. Your macro would give the statistics in a different way: larger particles would get a larger weight. If you want this, you have to multiply the 'max' and 'area' columns of the particle analyzer results and do the histogram from this. A few more remarks on your code: - When using binary operations like 'erode' in a macro, always set the binary options first, otherwise you might get an undesired results. By setting the options, you could also do several iterations at once, no need for the 'j' loop. - getImageStatistics or getRawStatistics give you min&max, it would tell you when everything is eroded. - Histogram is limited to the current selection, so you can easily threshold your image at some level (e.g. 1-255) and then 'create selection'. Michael ________________________________________________________________ On 3 May 2010, at 20:38, Li-Ping Yuan wrote: > I just wrote my first macro to calclate binary granulometry. > Hi All, > > I just wrote my first macro to calclate binary granulometry. It > worked but still need your kind help. > > The code is: > > run("Blobs (25K)"); > run("Make Binary"); // select object areas/pisels > run("Duplicate...", "title=erode.gif"); // for keeping > sequentially eroded images > run("Duplicate...", "title=size-map.gif"); // for the result > size map. > run("Divide...", "value=255"); // initialize all selected pixels > with value 1 in size-map. > for (i=1;i<12;i++) { > selectWindow("erode.gif"); > run("Erode"); > run("Duplicate...", "title=dilate.gif"); // for each eroded > image, dilate all the way back. > for (j=0;j<i;j++) { > run("Dilate"); > } > run("Divide...", "value=255"); // for all survived pixels, > add one to the size map. > run("Image Calculator...", "image1=size-map.gif operation=Add > image2=dilate.gif "); > selectWindow("dilate.gif"); > close(); > } > selectWindow("erode.gif"); > close(); > selectWindow("size-map.gif"); > run("Enhance Contrast", "saturated=0.5"); // to see the result. > run("Histogram"); // to get mean, std, and etc. But how can I > exclude background pixels? > > Problems: > 1. What's the best way to detect an images when all seleceted > areas are eroded away? I tried and error with this image to set > the loop with 12 erosions. It will be nice to detect that > automatically and stop the loop. > 2. The histogram at the end calculates mean and std including > background pixel (value=0). Is there a way to calculate with only > selected pixels (value > 0)? > 3. Erosion and dilation are pretty fast, the adding (image > calculator) is very slow. (I turned on the macro recorder to see > the progress) Is there a good way to speed up? write in Java? > 4. Any other software available for binary granulometry? Matlab? > ImagePro? > 5. Any other coments are welcome. > Thanks in advance for your comments/answers. > Li-Ping (Li) Yuan > |
Dimiter,
. Yes, the "blob.gif" uses inverted LUT and is confusing. However, I tried "AuPbSn 40 (56K)" and results are still very strange. My understanding of granulometry is performing a series of openning (of increasing radius) and observing the changes of the total intensity (for a gray image; or the pixel number for a binary image) over those openning results. I tried just one openning with radius=1 in "Granulometry" plugin (minimal=0 maximal=1 step=1 plot=radius show=yes). The result is very different from your another plugin "Gray Morphology" with an openning of radius=1. Should they be the same? The macro is (need both plugins installed): run("AuPbSn 40 (56K)"); // Run gray openning and display image run("Duplicate...", "title=After_One_Openning.jpg"); run("Gray Morphology", "radius=1 type=circle operator=open"); // Run granulometry at the same level and display image selectWindow("AuPbSn40.jpg"); run("Granulometry ", "minimal=0 maximal=1 step=1 plot=radius show=yes"); One openning of radius=1 with "Gray Morphology" plugin didn't change the image much as expected, but the Granulometry plugin changed the image a lot. It seems that the Granulometry plugin produces maximun intensity at the grain boundary while openning should lower the intensity in general. Is there some setting I missed? Thanks to your "Gray Morphology" plugin. It worked great and with choice of different structure elements. Best Regards Li-Ping (Li) Yuan ________________________________ From: Prodanov Dimiter <[hidden email]> To: [hidden email] Sent: Fri, May 7, 2010 3:26:31 AM Subject: Re: Binary granulometry macro. Hi, The blobs is not the best test case because the LUT is inverted so sometimes it gives counterintuitive results. Indeed, for binary erosion/dilation it is better to start from EDM or other metrics map. In the granulometry plugin I support several types of structuring elements -> several metrics. Best regards, Dimiter -----Original Message----- From: Li-Ping Yuan [mailto:[hidden email]] Sent: Thursday 6 May 2010 07:31 Subject: Re: Binary granulometry macro. Michael, Dimiter, and all, . Thanks for the remarks on the code. They gave me good directions to find proper coding. (Still took a while due to my limited knowledge on ImageJ). My revised code is at the end of this e-mail. It gives the granulometry results for both particles and background. Any comments are welcome. Also thanks for providing the alternative approach. The alternative approach is good for particles. The power of granulometry is more than analyzing particles. I can invert this binary image and perform the granulometry on the background. What does it mean is a different issue. (In certain cases, it gives information of spatial distribution of particles; in other cases, the object might be studying the pore space between particle grains.) Yes, my code is weighted with area, not number of particles. In fact, it gives good measurements for slighted overlapped particles without the need to separate them. I realize that the default erosion/dilation is based on the 8 neighbor (chessboard) distance function. The result size map has blocky shapes. The distance map method gives a better Euclidean distance which is nice. I hope that there is a Euclidean granulometry exist, but I haven't seen one, at least not for binary granulometry. Just tried Dimiter's gray scale granulometry plugin on the binarized "blobs.gif". It uses Euclidean distance function which is very nice (and quite fast). However, the result on this binarized "Blobs.gif" image is quite different from what I got here. They should be close even the distance functions are different. I wonder whether because the different algorithm? Thanks again to Micheal and Dimiter's reply Li-Ping (Li) Yuan ------------------------------------------------------------------------------- run("Blobs (25K)"); run("Make Binary"); // select object areas/pisels run("Duplicate...", "title=erode.gif"); // for keeping sequentially eroded images run("Duplicate...", "title=Object_Size_Map"); // for the result size map of object areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Object_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Object_Size_Map"); run("Duplicate...", "title=Object_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Object_Area"); close(); // Do not want to see the mask. selectWindow("Object_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection. selectWindow("blobs.gif"); run("Duplicate...", "title=erode.gif"); run("Invert"); // Analyze background areas for object distribution information. run("Duplicate...", "title=Background_Size_Map"); // for the result size map of background areas. run("Divide...", "value=255"); // initialize all selected pixels with value 1 in size-map. for (i=1 ; i<100 ; i++) { selectWindow("erode.gif"); run("Options...", "iterations=1 pad edm=Overwrite count=1"); run("Erode"); run("Measure"); max = getResult("Max" ) ; // See any selected areas still remain (Max=255) if( max != 0 ) { run("Duplicate...", "title=dilate.gif"); // for each eroded image, dilate it back to original run("Options...", "iterations=" + i + " pad edm=Overwrite count=1"); run("Dilate"); run("Divide...", "value=255"); // for all survived pixels, add one to the size map. run("Image Calculator...", "image1=Background_Size_Map operation=Add image2=dilate.gif "); selectWindow("dilate.gif"); close(); } else { i=100; // All selected areas have eroded away. stop the loop } } selectWindow("erode.gif"); close(); selectWindow("Background_Size_Map"); run("Duplicate...", "title=Background_Area"); //need to create selection but don't want to see the mask. setThreshold(1, 255); run("Create Selection"); run("Histogram"); // to get the size distribution (granulometry) and stats selectWindow("Background_Area"); close(); // Do not want to see the mask. selectWindow("Background_Size_Map"); run("Enhance Contrast", "saturated=0.5"); // to see the result. run("Restore Selection"); // show selection ________________________________ From: Prodanov Dimiter <[hidden email]> To: [hidden email] Sent: Wed, May 5, 2010 4:08:58 AM Subject: Re: Binary granulometry macro Hi All, The purpose of this work is unclear. What do you want to measure or filter? Best regards, Dimiter -----Original Message----- From: Michael Schmid [mailto:[hidden email]] Sent: Tuesday 4 May 2010 11:56 Subject: Re: Binary granulometry macro Hi Li, not an attempt to answer your questions, but an alternative way of doing something similar: It seems that you want to have statistics on the particles. Assuming that 'erode' would be circular symmetric (it is not) your macro would give statistics on the maximum distance from the center. This is similar to, but not equal to 0.5*MinFeret width. Feret (caliper length): you can get it directly from 'Analyze particles' with suitable 'set measurements'. If you are not satisfied with Feret width, you can still do it with 'Analyze Particles': Run Process>Binary>Distance Map on your binary image, threshold at 1-255, then run the particle analyzer. You can then use 'Distribution' to get a histogram of the maxima, i.e., the maximum distance from the center. Your macro would give the statistics in a different way: larger particles would get a larger weight. If you want this, you have to multiply the 'max' and 'area' columns of the particle analyzer results and do the histogram from this. A few more remarks on your code: - When using binary operations like 'erode' in a macro, always set the binary options first, otherwise you might get an undesired results. By setting the options, you could also do several iterations at once, no need for the 'j' loop. - getImageStatistics or getRawStatistics give you min&max, it would tell you when everything is eroded. - Histogram is limited to the current selection, so you can easily threshold your image at some level (e.g. 1-255) and then 'create selection'. Michael ________________________________________________________________ On 3 May 2010, at 20:38, Li-Ping Yuan wrote: > I just wrote my first macro to calclate binary granulometry. > Hi All, > > I just wrote my first macro to calclate binary granulometry. It > worked but still need your kind help. > > The code is: > > run("Blobs (25K)"); > run("Make Binary"); // select object areas/pisels > run("Duplicate...", "title=erode.gif"); // for keeping > sequentially eroded images > run("Duplicate...", "title=size-map.gif"); // for the result > size map. > run("Divide...", "value=255"); // initialize all selected pixels > with value 1 in size-map. > for (i=1;i<12;i++) { > selectWindow("erode.gif"); > run("Erode"); > run("Duplicate...", "title=dilate.gif"); // for each eroded > image, dilate all the way back. > for (j=0;j<i;j++) { > run("Dilate"); > } > run("Divide...", "value=255"); // for all survived pixels, > add one to the size map. > run("Image Calculator...", "image1=size-map.gif operation=Add > image2=dilate.gif "); > selectWindow("dilate.gif"); > close(); > } > selectWindow("erode.gif"); > close(); > selectWindow("size-map.gif"); > run("Enhance Contrast", "saturated=0.5"); // to see the result. > run("Histogram"); // to get mean, std, and etc. But how can I > exclude background pixels? > > Problems: > 1. What's the best way to detect an images when all seleceted > areas are eroded away? I tried and error with this image to set > the loop with 12 erosions. It will be nice to detect that > automatically and stop the loop. > 2. The histogram at the end calculates mean and std including > background pixel (value=0). Is there a way to calculate with only > selected pixels (value > 0)? > 3. Erosion and dilation are pretty fast, the adding (image > calculator) is very slow. (I turned on the macro recorder to see > the progress) Is there a good way to speed up? write in Java? > 4. Any other software available for binary granulometry? Matlab? > ImagePro? > 5. Any other coments are welcome. > Thanks in advance for your comments/answers. > Li-Ping (Li) Yuan > |
Free forum by Nabble | Edit this page |