mips - 有没有办法在 mips CPU 上加速 GraphicsMagick 的调整图像大小性能?
问题描述
我正在使用 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
更新:
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
UPDATE2:样本模式
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
有什么方法可以提高性能吗?我只是想调整一些照片的大小,如果有MIPS提供的一些库,我可以写一个工具用C语言调用它。
解决方案
我从IJG 网站example.c
上的 v9c 源代码中获取了该文件,并迅速将其破解如下,只从您的 4640x3480 输入文件中写入每 8 行和每 8 列。它创建了以下 580x435 图像,GraphicsMagick 可以在合理的时间内设法将其大小调整为 64x64,因为文件小了 64 倍。
你会使用:
gm convert result.ppm -resize 64x64 thumb.jpg
它只使用 1.1MB 的 RAM,因为它一次只读取 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
推荐阅读
- sas - 为什么我收到错误:错误:值 02 不是有效的 SAS 名称。在这个简单的查询中
- pandas - 在 Pandas 中,基于两组索引连接来自两个数据帧的值
- c++ - 使用基于范围的 for 循环和指针向量时的 C++ 错误
- powershell - 使用 PowerShell 替换程序中的代码源
- mongodb - 与 mongodb 连接时出现 Apache solr 错误
- osgi - Karaf Cellar:安装 Kar 文件时出现问题 -> Maven 找不到工件
- python - 如何通过某些功能在 PyQt5 中切换屏幕?
- linux - YOCTO 更改内核版本并选择驱动程序
- django - Django URL 给出错误当前路径 carmodels/Tata/ZEST/XE Petrol 与其中任何一个都不匹配
- android - 基本反应本机应用程序没有在模拟器上显示任何带有应用程序名称的纯文本白屏