Есть ли способ ускорить изменение размера изображения в GraphicsMagick на mips CPU? - PullRequest
1 голос
/ 10 июня 2019

Я использую Netgear WNDR4300 для запуска GraphicsMaigick для изменения размера изображений JPEG.Это cpuinfo,

cat /proc/cpuinfo
system type             : Atheros AR9344 rev 2
machine                 : NETGEAR WNDR4300
processor               : 0
cpu model               : MIPS 74Kc V4.12
BogoMIPS                : 278.93
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 32
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa                     : mips1 mips2 mips32r1 mips32r2
ASEs implemented        : mips16 dsp dsp2
shadow register sets    : 1
kscratch registers      : 0
package                 : 0
core                    : 0
VCED exceptions         : not available
VCEI exceptions         : not available

Это очень медленно и занимает 4 минуты для каждой фотографии.

root@OpenWrt:/mnt/sda1/media/# ll
drwxrwxrwx    2 root     root        131072 Jun 10 14:07 ./
drwxrwxrwx    7 root     root        131072 Jun  8 10:18 ../
-rwxrwxrwx    1 root     root       4130026 Feb 10  2018 IMG_20180210_115807.jpg*

root@OpenWrt:/mnt/sda1/media/kidds# time gm mogrify -output-directory > /mnt/sda1/web -resize 64x64 -quality 75 IMG_20170628_100052.jpg
real    4m 19.72s
user    3m 21.86s
sys     0m 9.29s

-resize output

ОБНОВЛЕНИЕ:

root@OpenWrt:~# gm identify -version
GraphicsMagick 1.3.31 2018-11-17 Q8 http://www.GraphicsMagick.org/
Copyright (C) 2002-2018 GraphicsMagick Group.
Additional copyrights and licenses apply to this software.
See http://www.GraphicsMagick.org/www/Copyright.html for details.

Feature Support:
  Native Thread Safe       yes
  Large Files (> 32 bit)   yes
  Large Memory (> 32 bit)  no
  BZIP                     no
  DPS                      no
  FlashPix                 no
  FreeType                 yes
  Ghostscript (Library)    no
  JBIG                     no
  JPEG-2000                no
  JPEG                     yes
  Little CMS               no
  Loadable Modules         yes
  OpenMP                   no
  PNG                      yes
  TIFF                     yes
  TRIO                     no
  UMEM                     no
  WebP                     no
  WMF                      no
  X11                      no
  XML                      no
  ZLIB                     yes

Host type: mips-openwrt-linux-gnu

Configured using the command:
  ./configure  '--target=mips-openwrt-linux' '--host=mips-openwrt-linux' '--build=x86_64-pc-linux-gnu' '--program-prefix=' '--program-suffix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--libexecdir=/usr/lib' '--sysconfdir=/etc' '--datadir=/usr/share' '--localstatedir=/var' '--mandir=/usr/man' '--infodir=/usr/info' '--disable-nls' '--enable-shared' '--disable-static' '--enable-dependency-tracking' '--with-modules' '--with-threads' '--without-magick-plus-plus' '--without-perl' '--without-bzlib' '--without-dps' '--without-fpx' '--without-jbig' '--without-webp' '--with-jpeg' '--without-jp2' '--without-lcms2' '--without-lzma' '--with-png' '--with-tiff' '--without-trio' '--with-ttf' '--without-umem' '--without-wmf' '--without-xml' '--with-zlib' '--without-zstd' '--without-x' 'build_alias=x86_64-pc-linux-gnu' 'host_alias=mips-openwrt-linux' 'target_alias=mips-openwrt-linux' 'CC=mips-openwrt-linux-musl-gcc' 'CFLAGS=-Os -pipe -mno-branch-likely -mips32r2 -mtune=24kc -fno-caller-save

Final Build Parameters:
  CC       = mips-openwrt-linux-musl-gcc
  CFLAGS   = -Os -pipe -mno-branch-likely -mips32r2 -mtune=24kc -fno-caller-saves -fno-plt -fhonour-copts -Wno-error=unused-but-set-variable -Wno-error=unused-result -msoft-float -mips16 -minterlink-mips16 -iremap/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/build_dir/target-mips_24kc_musl/GraphicsMagick-1.3.31:GraphicsMagick-1.3.31 -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -flto -Wall
  CPPFLAGS = -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/usr/include -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/include -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/toolchain-mips_24kc_gcc-7.4.0_musl/usr/include -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/toolchain-mips_24kc_gcc-7.4.0_musl/include/fortify -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/toolchain-mips_24kc_gcc-7.4.0_musl/include -I/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/usr/include/freetype2
  CXX      = mips-openwrt-linux-musl-g++
  CXXFLAGS = -Os -pipe -mno-branch-likely -mips32r2 -mtune=24kc -fno-caller-saves -fno-plt -fhonour-copts -Wno-error=unused-but-set-variable -Wno-error=unused-result -msoft-float -mips16 -minterlink-mips16 -iremap/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/build_dir/target-mips_24kc_musl/GraphicsMagick-1.3.31:GraphicsMagick-1.3.31 -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -flto
  LDFLAGS  = -L/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/usr/lib -L/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/lib -L/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/toolchain-mips_24kc_gcc-7.4.0_musl/usr/lib -L/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/toolchain-mips_24kc_gcc-7.4.0_musl/lib -znow -zrelro -L/opt/buildbot/slaves/lede-slave-tah/mips_24kc/build/sdk/staging_dir/target-mips_24kc_musl/usr/lib
  LIBS     = -lfreetype -lz -lltdl -lm -lpthread

ОБНОВЛЕНИЕ2: режим выборки

root@OpenWrt:/mnt/sda1/media/kidds# time gm mogrify -output-directory /mnt/sda1/web -sample 64x64 -quality 75 IMG_20170628_100052.jpg
real    0m 20.76s
user    0m 8.70s
sys     0m 3.29s

-sample output

Есть ли способ улучшить производительность?Я просто хочу изменить размеры некоторых фотографий, если есть какая-то библиотека, предоставляемая MIPS, я могу написать инструмент для ее вызова с использованием языка C.

1 Ответ

0 голосов
/ 10 июня 2019

Я взял файл example.c из источника v9c на веб-сайте IJG и быстро взломал его, как показано ниже, чтобы записывать только каждую 8-ю строку и каждый 8-й столбец из вашего входного файла 4640x3480.Он создает следующее изображение размером 580x435, которое можно предположить, что GraphicsMagick сможет изменить его размер до 64x64 за разумное время, поскольку размер файла в 64 раза меньше.

enter image description here

Вы будете использовать:

gm convert result.ppm -resize 64x64 thumb.jpg

Он использует только 1,1 МБ ОЗУ, поскольку читает только одну строку за раз- Я проверил, используя:

/usr/bin/time -l ./example photo.jpg

Вы можете поэкспериментировать с коэффициентом прореживания, я использовал 8, но вы можете попробовать 4 или 10 и увидеть компромисс между временем и качеством.Просто измените 8 в последней строке файла.

Код выглядит следующим образом - я добавил "HACK" в комментарии, чтобы вы могли видеть, где я был занят, делая грязную грязькод:

#include <stdio.h>
#include <stdlib.h>
#include "jpeglib.h"
#include <setjmp.h>

struct my_error_mgr {
  struct jpeg_error_mgr pub;    /* "public" fields */

  jmp_buf setjmp_buffer;    /* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;

METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Always display the message. */
  /* We could postpone this until after returning, if we chose. */
  (*cinfo->err->output_message) (cinfo);

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}

GLOBAL(int)
read_JPEG_file (char * filename,int factor)
{
  /* This struct contains the JPEG decompression parameters and pointers to
   * working space (which is allocated as needed by the JPEG library).
   */
  struct jpeg_decompress_struct cinfo;
  /* We use our private extension JPEG error handler.
   * Note that this struct must live as long as the main JPEG parameter
   * struct, to avoid dangling-pointer problems.
   */
  struct my_error_mgr jerr;
  /* More stuff */
  FILE * infile;        /* source file */
  FILE * outfile;       /* result file */        // HACK
  JSAMPARRAY buffer;        /* Output row buffer */
  int row_stride;       /* physical row width in output buffer */

  /* In this example we want to open the input file before doing anything else,
   * so that the setjmp() error recovery below can assume the file is open.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to read binary files.
   */

  if ((infile = fopen(filename, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    return 0;
  }

  /* Step 1: allocate and initialize JPEG decompression object */

  /* We set up the normal JPEG error routines, then override error_exit. */
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp(jerr.setjmp_buffer)) {
    /* If we get here, the JPEG code has signaled an error.
     * We need to clean up the JPEG object, close the input file, and return.
     */
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return 0;
  }
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress(&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src(&cinfo, infile);

  /* Step 3: read file parameters with jpeg_read_header() */

  (void) jpeg_read_header(&cinfo, TRUE);
  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.txt for more info.
   */

  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */

  /* Step 5: Start decompressor */

  (void) jpeg_start_decompress(&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   * In this example, we need to make an output work buffer of the right size.
   */ 
  /* JSAMPLEs per row in output buffer */
  row_stride = cinfo.output_width * cinfo.output_components;
  /* Make a one-row-high sample array that will go away when done with image */
  buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  // Write a simple PPM file called "result.ppm" that can be thumbnailed with GraphicsMagick
  // gm convert result.ppm -resize 64x64 thumbnail.jpg
  if ((outfile = fopen("result.ppm", "wb")) == NULL) {           // HACK
    fprintf(stderr, "can't open result.ppm\n");                  // HACK
    return 0;                                                    // HACK
  }
  int outwidth  = cinfo.output_width/factor;                     // HACK
  int outheight = cinfo.output_height/factor;                    // HACK
  fprintf(outfile,"P6\n%d %d\n255\n",outwidth,outheight);        // HACK
  unsigned char * outbuf;                                        // HACK
  outbuf = (unsigned char*)malloc(outwidth*3);                   // HACK

  int line=0;           // HACK
  while (cinfo.output_scanline < cinfo.output_height) {
    /* jpeg_read_scanlines expects an array of pointers to scanlines.
     * Here the array is only one element long, but you could ask for
     * more than one scanline at a time if that's more convenient.
     */
    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
    // Do every Nth row                                          // HACK
    if(line%factor==0){                                          // HACK
       int pixel,op;
       op=0;
       for(pixel=0;pixel<row_stride/3;pixel+=factor){
          outbuf[op++] = buffer[0][(pixel*3) +0];
          outbuf[op++] = buffer[0][(pixel*3) +1];
          outbuf[op++] = buffer[0][(pixel*3) +2];
       }
       fwrite(outbuf,1,op,outfile);                              // HACK
    }                                                            // HACK
    line++;                                                      // HACK
  }

  /* Step 7: Finish decompression */

  (void) jpeg_finish_decompress(&cinfo);

  /* Step 8: Release JPEG decompression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress(&cinfo);

  fclose(infile);
  return 1;
}

int main(int argc, char*argv[]){

   // Read "test.jpg" and only output every 8th row and every 8th column for a 64x size reduction
   read_JPEG_file ("test.jpg",8); // HACK
}

Я скомпилировал его с:

clang -std=c11  $(pkg-config --cflags --libs libjpeg) example.c -o example
...