image-processingimagemagickimage-manipulationimagemagick-convert

Imagemagick: Are there any operators that could convert all spots on b/w mages into pixel placed at geometric center?


I have a huge set of black and white images with spots and want to replace every spot into pixel (or small circle) that is located in the geometric center of the spot.

enter image description here

Because the spots has different sizes, I could not consequently use dilate operator because it completely deletes small sports. Is there any way to do this automatical with Imagemagick?


Solution

  • Kudos (and upvotes) to Fred (@fmw42) for the original technique. As much for my own curiosity as anything (and to document the approach), I wanted to make a variant that is hopefully more CPU-friendly, I/O friendly and maybe more portable. This should also have advantages given that OP has large numbers of images to process.

    I worked on the following aspects:

    So, it looks like this:

    #!/bin/bash
    
    magick black_spots.png \
       -threshold 50% -type bilevel \
       -define connected-components:mean-color=true \
       -define connected-components:area-threshold=0-300 \
       -define connected-components:verbose=true \
       -connected-components 8 null: | awk -F'[ x+]*' '
          BEGIN       { print "black_spots.png -fill white -colorize 100 -fill black" }
          /gray\(0\)/ {
                        w=$3; h=$4; x=$5; y=$6; cx=x+w/2; cy=y+h/2
                        printf("-draw \"translate %f,%f circle 0,0 0,5\"\n", cx, cy)
                      }
          END         { print "-write result.png"}
       ' | magick -script -
    

    enter image description here


    The awk part in the middle actually generates a script that looks like this:

    black_spots.png -fill white -colorize 100 -fill black
    -draw "translate 1429.000000,368.000000 circle 0,0 0,5"
    -draw "translate 6.000000,1026.500000 circle 0,0 0,5"
    -draw "translate 739.500000,378.000000 circle 0,0 0,5"
    ...
    ...
    -write result.png
    

    That is then piped into magick -script at the end. Hopefully it is clear that the input file is only read once, all the circles are drawn, then the output file is written - just once.


    Some notes on the awk parts:


    As regards processing large numbers of files, I would use GNU Parallel, but you have not indicated your operating system. Basically, modify the above script to accept a filename as a parameter, save it as ProcessOne, make it executable with chmod +x ProcessOne, then run:

    parallel ./ProcessOne ::: *.png
    

    and it will keep all your CPU cores busy processing all your files in parallel till they are all done. You can get progress bars and ETAs with various switches:

    parallel --eta ...         # show ETA
    parallel --progress ...    # report progress
    parallel --bar ...         # add progress bar
    parallel -j 4 ...          # just run 4 jobs in parallel