skip to Main Content

I’m using the kmeans feature in version 7 of ImageMagick.

time convert in.png -kmeans 20 out.png

This command completes rather quickly on my machine (1.7s)

However when running within docker it goes much slower (48.8s).

I’ve tried docker on my same machine, and also docker in AWS Lambda. Doesn’t seem to matter what type of image I use either. Same slow speed everywhere within docker.

I’m using this docker: FROM amazon/aws-lambda-nodejs:20.2024.02.07.18 as build and compiling ImageMagic 7 via source (because only ImageMagick version 6 is available as a package via dnf on AmazonLinux2023).

Have I done something wrong with compiling ImageMagick perhaps? A missing library or some sort of optimisation?

This is the ImageMagick version running within docker:

bash-5.2# convert -version
Version: ImageMagick 7.1.1-29 Q16-HDRI x86_64 cfc71f0aa:20240225 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI 
Delegates (built-in): bzlib fontconfig freetype jng jpeg lzma png xml zlib
Compiler: gcc (11.4)

This is the faster ImageMagick running directly on my machine:

Version: ImageMagick 7.1.1-25 Q16-HDRI aarch64 21883 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(5.0) 
Delegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg jxl lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib zstd
Compiler: gcc (4.2)

To compile ImageMagick within Docker I used this approach:

FROM amazon/aws-lambda-nodejs:20.2024.02.07.18 as build
RUN dnf -y update && dnf install -y g++ gdb ninja-build gcc cpp cmake make automake autoconf chkconfig pkgconfig clang clang-libs gcc-c++ dos2unix bzip2 bzip2-libs zlib-devel libpng libpng-tools libpng-devel openjpeg2 openjpeg2-tools openjpeg2-devel libwebp-devel giflib-devel fftw-libs fontconfig-devel libtool xz xz-libs tar bc && dnf clean all
ADD build /root/build
RUN /root/build/imagemagick.sh

with this build script:

#!/usr/bin/env bash
set -e

# libjpg

cd /root
curl https://github.com/winlibs/libjpeg/archive/refs/tags/libjpeg-9c.tar.gz -L -o tmp-libjpeg.tar.gz
tar xf tmp-libjpeg.tar.gz
cd libjpeg*

dos2unix *
dos2unix -f configure
chmod +x configure

PKG_CONFIG_PATH=/root/build/cache/lib/pkgconfig 
  ./configure 
    CPPFLAGS=-I/root/build/cache/include 
    LDFLAGS=-L/root/build/cache/lib 
    --disable-dependency-tracking 
    --disable-shared 
    --enable-static 
    --prefix=/root/build/cache

dos2unix -f libtool

make
make install

# libpng

cd /root
curl http://prdownloads.sourceforge.net/libpng/libpng-1.6.37.tar.xz -L -o tmp-libpng.tar.xz
tar xf tmp-libpng.tar.xz
cd libpng*

PKG_CONFIG_PATH=/root/build/cache/lib/pkgconfig 
  ./configure 
    CPPFLAGS=-I/root/build/cache/include 
    LDFLAGS=-L/root/build/cache/lib 
    --disable-dependency-tracking 
    --disable-shared 
    --enable-static 
    --prefix=/root/build/cache

make
make install

# imagemagick

cd /root
curl https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.1-29.tar.gz -L -o tmp-imagemagick.tar.gz
tar xf tmp-imagemagick.tar.gz
cd ImageMagick*

PKG_CONFIG_PATH=/root/build/cache/lib/pkgconfig 
  ./configure 
    CPPFLAGS=-I/root/build/cache/include 
    LDFLAGS="-L/root/build/cache/lib -lstdc++" 
    --disable-dependency-tracking 
    --disable-shared 
    --enable-static 
    --prefix=/root/result 
    --enable-delegate-build 
    --disable-installed 
    --without-modules 
    --disable-docs 
    --without-magick-plus-plus 
    --without-perl 
    --without-x 
    --disable-openmp 
    --with-openjp2=no 
    --with-webp=no 
    --with-tiff=no

make clean
make all
make install

*edit: I also tried re-compiling without disable-openmp after reading that it can improve performance. Same time with and without that compilation option.

2

Answers


  1. Here are some things you could try…


    Run the following on both machines to see the exact options each version was built with and compare the output:

    identify -list configure
    

    Try building a Q8 version to see if that is any faster:

    ./configure --with-quantum-depth=8 ...
    

    Try using compiler optimisation and targeting the exact architecture of your machine, along these lines depending on your compiler:

    ./configure CFLAGS="-O3 -march=native" CPPFLAGS="-O3 -march=native" ...
    

    Try disabling OpenCL:

    ./conigure --disable-opencl ...
    

    Check your docker config files to see how much RAM and how many CPU cores it is giving your container.


    Maybe you are open to using a different tool? For example, on an alpine:latest container, you can install OpenCV with:

    apk update && apk add py3-opencv
    

    Then you can do K-means clustering like this:

    #!/usr/bin/env python3
    
    import sys
    import cv2 as cv
    import numpy as np
    
    # Check we got an input file and K
    if len(sys.argv) != 3:
       sys.exit(f'Usage: {sys.argv[0]} filename K')
    
    # Pick up parameters into variables
    file = sys.argv[1]
    K = int(sys.argv[2])
    
    # Load image and reshape
    im = cv.imread(file, cv.IMREAD_ANYCOLOR)
    bgrVector = im.reshape((-1,3)).astype(np.float32)
    
    # Define criteria, number of clusters(K) and apply kmeans()
    criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    ret,label,centre = cv.kmeans(bgrVector, K, None, criteria, 10, cv.KMEANS_RANDOM_CENTERS)
    
    # Convert back to uint8, and remake original image
    centre = np.uint8(centre)
    res = centre[label.flatten()].reshape(im.shape)
    cv.imwrite('result.png', res)
    

    Or maybe you do lots of other processing and ImageMagick is more appropriate and flexible.

    Login or Signup to reply.
  2. You can speed up kmeans in Imagemagick by using its optional arguments for number of iterations or convergence tolerance. So reduce the number of iterations from the default or increase the tolerance from the default. The arguments are:

    -kmeans colors{xiterations}{+tolerance}
    

    Defaults are: iterations=300 and convergence=0.0001

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search