JPEG文件转换为GIF格式太长 [英] Converting jpegs to gifs is too long

查看:227
本文介绍了JPEG文件转换为GIF格式太长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从我的JPEG从摄像机获取做出GIF动画。但这个过程是不真实的长。我用了两个不同的库。 首先是写有原生C ++ code和第二个是Java的 之一

我COM preSS帧作为我可以,但即使这样也不能减少生成时间。

本机库大约需要80-100秒和Java的时间约40-60秒(我不知道Java是怎么一快2倍,但记录显示此结果),持续5秒的视频与16 FPS(每80帧GIF)。

我改变根据有点C ++算法,因为我得到了同样的问题(试两个版本不断变化的一张code并改变整个学习()功能)。

在这里你可以看到一块的日志:

这是在本地实现最后三个框架:

  D / TimeUtils:添加帧949ms执行
D / TimeUtils:添加帧976ms执行
D / TimeUtils:添加帧1028ms执行
D / TimeUtils:在82553ms执行本地库创建GIF

这是最后的三个框架Java的版本:

  D / TimeUtils:添加帧541ms执行
D / TimeUtils:添加帧513ms执行
D / TimeUtils:添加帧521ms执行
D / TimeUtils:在44811ms执行nbadal的图书馆创建GIF

也许其他一些有用的日志:

  D / CameraActivity:捕捉视频的时间为5000毫秒
V / CameraActivity:尺寸为288瓦特点¯x288H
D / CameraActivity:最后的位图数:80

TimeUtils.java包含静态方法来检查方法执行多久。

NativeGifConverter.java(仅适用于转换功能):

  @覆盖公共无效createGifFile(字符串路径,列表与LT;弦乐> bitmapPaths){    位图的位图= BitmapUtils.retrieve(bitmapPaths.get(0));    如果(初始化(路径,bitmap.getWidth(),bitmap.getHeight(),mNumColors,mQuality,mFrameDelay)!= 0){
      Timber.e(Gifflen初始化失败);
      返回;
    }    bitmap.recycle();    对于(字符串bitmapPath:bitmapPaths){      位= howLong(检索位图,() - GT; BitmapUtils.retrieve(bitmapPath));      最终诠释宽度= bitmap.getWidth();
      最终诠释身高= bitmap.getHeight();
      最终诠释[] =像素新INT [宽*高]。
      最后的位图finalBitmap =位图; //为计时
      howLongVoid(检索像素() - > finalBitmap.getPixels(像素,0,宽度,0,0,宽度,高度));
      howLongVoid(添加帧,帧() - GT; ADDFRAME的(像素));      bitmap.recycle();
    }
    位= NULL;
    关();
  }

NbadalGifConverter.java(仅适用于转换功能):

  @覆盖公共无效createGifFile(字符串路径,列表与LT;弦乐> bitmapsNames){    最后ByteArrayOutputStream BOS =新ByteArrayOutputStream();    最后AnimatedGifEn codeR EN codeR =新AnimatedGifEn codeR();
    EN coder.setDelay(mDelay);
    EN coder.setQuality(mQuality);
    EN coder.start(BOS);    对于(字符串bitmapName:bitmapsNames){
      最后的位图位= howLong(检索位图,() - GT; BitmapUtils.retrieve(bitmapName));
      howLongVoid(添加帧,帧() - GT; EN coder.addFrame(位图));
    }    EN coder.finish();
    FileUtils.store(bos.toByteArray(),path.substring(0,path.lastIndexOf())+.gif注意'。');
  }

我愿意向你展示code的另一个相关部分。我将不胜AP preciate任何帮助。

[更新]

在检索位图的日志:

  D / TimeUtils:检索位图3ms的执行
D / TimeUtils:检索位图3ms的执行
D / TimeUtils:检索位图4ms的执行


解决方案

首先,我要感谢的@Spektre了这样的回答:的有效GIF /图像色彩量化?

我和我的同事刚刚从C ++到Java翻译它。它显示了4倍的时间更少了良好的效果。我会尽力改进它,但是这已经是更好的结果,比AnimatedGifEn coder.java(我之前使用)

下面是code:

 公共静态最终诠释MAX_COLOR_COUNT = 65536;/ **
 * @参数像素RGB 888
 * @参数调色板INT [256]
 *在调色板颜色@返回指数
 * /
私人INT [] [] [] createPalette(INT []像素,INT []调色板){  最终诠释[] =直方图新INT [MAX_COLOR_COUNT] //像素数直方图
  最终诠释[] =指数新INT [MAX_COLOR_COUNT] //此处指数颜色值  的for(int i = 0; I< MAX_COLOR_COUNT;我++){
    指数[i] =我;
  }  //创建直方图
  对于(INT颜色:像素){
    // 0001 1111 0111 1110 0000 1111 1000 0000 0000
    颜色=((彩色>> 3)及0x1F的)| ((彩色>> 5)及0x7E0)| ((彩色>> 8)及0xF800);
    如果(直方图[颜色]< Integer.MAX_VALUE的){//图片必须是真大
      直方图[颜色] ++;
    }
  }  //删除零
  INT J = 0;
  的for(int i = 0; I< MAX_COLOR_COUNT;我++){
    直方图[J] =直方图[I]
    指数[J] =指数[I]
    如果(直方图[J]!= 0){
      J ++;
    }
  }
  最终诠释直方图= j的;  //冒泡排序
  的for(int i = 1;!I = 0;){
    I = 0;
    为(中间体X = 0,Y = 1; Y&下;直方图; X ++,Y ++){
      如果(直方图[X]<柱状图[Y]){
        I =直方图[X];
        直方图[X] =直方图[Y];
        直方图[Y] =我;
        I =指数[X];
        指数[X] =指数[Y];
        指数[Y] =我;
        I = 1;
      }
    }
  }  最终诠释[] [] [] =颜色表INT新[32] [64] [32];  INT colorTableIndex = 0,X = 0;
  为(X - LT;柱状图; X ++){//主色调
    最终诠释颜色=指数[X];
    // 1F(16)= 0001 1111(2)
    // 3F(16)= 0011 1111(2)
    //(1111 1)(111 111)(1 1111)
    最终诠释B =颜色和放大器; 0x1F的;
    最终诠释G =(彩色>> 5)及0x3F的;
    最终诠释R =(彩色>> 11)及0x1F的;    //如果跳过类似的颜色已经在调色板[]
    诠释一个= 0,I = 0;
    对于(; I< colorTableIndex;我++){
      最后一个字节tempB =(字节)((调色板[Ⅰ]≥→3)及0x1F的);
      最后一个字节tempG =(字节)((调色板[Ⅰ]≥→10)及0x3F的);
      最后一个字节tempR =(字节)((调色板[Ⅰ]≥> 19)及0x1F的);      //如果两种颜色之间的区别是pretty小
      //出租车距离
      INT差= tempB - B;
      如果(差℃,){
        差值= -difference;
      }
      A =差;
      差值= tempG - 克;
      如果(差℃,){
        差值= -difference;
      }
      A + =差;
      差值= tempR - R的;
      如果(差℃,){
        差值= -difference;
      }
      A + =差;
      如果(一个或下; = 2){//小于16/8
        一个= 1;
        打破;
      }
      一个= 0;
    }    如果(一个!= 0){
      颜色表[R] [G] [B] =我; //映射到现有的颜色
    }其他{
      颜色表[R] [G] [B] = colorTableIndex; //映射到新的索引      // 1111年1000年1111 1100 1111 1000年
      调色板[colorTableIndex] = B<< 3 | (克下;小于10)| (为r所述19); //填补这一指数与新色
      colorTableIndex ++;
      如果(colorTableIndex> = 256 / * * palette.length /){
        X ++;
        打破;
      }
    }
  } // colorTableIndex =新的颜色表的大小  为(X - LT;柱状图; X ++){//次要颜色    最终诠释颜色=指数[X];    最终诠释B =颜色和放大器; 0x1F的;
    最终诠释G =(彩色>> 5)及0x3F的;
    最终诠释R =(彩色>> 11)及0x1F的;    //找到最接近的颜色
    INT minDistance才会= -1;
    INT colorIndex = 0;
    对于(INT A,I = 0; I< colorTableIndex;我++){
      最后一个字节tempB =(字节)((调色板[Ⅰ]≥→3)及0x1F的);
      最后一个字节tempG =(字节)((调色板[Ⅰ]≥→10)及0x3F的);
      最后一个字节tempR =(字节)((调色板[Ⅰ]≥> 19)及0x1F的);      INT差= tempB - B;
      如果(差℃,){
        差值= -difference;
      }
      A =差;
      差值= tempG - 克;
      如果(差℃,){
        差值= -difference;
      }
      A + =差;
      差值= tempR - R的;
      如果(差℃,){
        差值= -difference;
      }
      A + =差;
      如果((minDistance才会℃,)||(minDistance才会>一种)){
        minDistance才会=一;
        colorIndex = I;
      }
    }
    颜色表[R] [G] [B] = colorIndex;
  }  返回颜色表;
}私人字节[]地图(INT []像素,INT [] [] []颜色表){
  最终诠释pixelsLength = pixels.length;  最后一个字节[] =映射到新的字节[pixelsLength]
  的for(int i = 0; I< pixelsLength;我++){
    最终诠释颜色=
        ((象素[Ⅰ]≥→3)及0x1F的)| ((象素[Ⅰ]≥大于5)及0x7E0)| ((象素[Ⅰ]≥→8)及0xF800);    最终诠释B =颜色和放大器; 0x1F的;
    最终诠释G =(彩色>> 5)及0x3F的;
    最终诠释R =(彩色>> 11)及0x1F的;    映射[I] =(字节)的颜色表[R] [G] [B]。
  }
  返回映射;
}

I'm trying to make gif animation from jpegs I get from video camera. But this process is unreal long. I used two different libraries. First is written with native C++ code and second is Java's one.

I compress frames as I can, but even this cannot reduce generating time.

Native library takes about 80-100 seconds and Java's takes about 40-60 seconds (I don't know how java is 2 times faster, but logs show me this result) for 5 seconds video with 16 fps (80 frames per gif).

I changed a bit C++ algorithm according to this, because I got same problem (tried both versions with changing a piece of code and changing whole learn() function).

Here you can see piece of logs:

It's last three frames in native implementation:

D/TimeUtils: Adding frame executed in 949ms
D/TimeUtils: Adding frame executed in 976ms
D/TimeUtils: Adding frame executed in 1028ms
D/TimeUtils: Creating gif with native library executed in 82553ms

It's last three frames in Java's version:

D/TimeUtils: Adding frame executed in 541ms
D/TimeUtils: Adding frame executed in 513ms
D/TimeUtils: Adding frame executed in 521ms
D/TimeUtils: Creating gif with nbadal's library executed in 44811ms

Maybe some other useful logs:

D/CameraActivity: Duration of the captured video is 5000ms
V/CameraActivity: Dimensions are 288w x 288h
D/CameraActivity: Final bitmaps count: 80

TimeUtils.java contains static methods to check how long method executes.

NativeGifConverter.java (only converting function):

@Override public void createGifFile(String path, List<String> bitmapPaths) {

    Bitmap bitmap = BitmapUtils.retrieve(bitmapPaths.get(0));

    if (init(path, bitmap.getWidth(), bitmap.getHeight(), mNumColors, mQuality, mFrameDelay) != 0) {
      Timber.e("Gifflen init failed");
      return;
    }

    bitmap.recycle();

    for (String bitmapPath : bitmapPaths) {

      bitmap = howLong("Retrieving bitmap", () -> BitmapUtils.retrieve(bitmapPath));

      final int width = bitmap.getWidth();
      final int height = bitmap.getHeight();
      final int[] pixels = new int[width * height];
      final Bitmap finalBitmap = bitmap; // for counting time
      howLongVoid("Retrieving pixels", () -> finalBitmap.getPixels(pixels, 0, width, 0, 0, width, height));
      howLongVoid("Adding frame", () -> addFrame(pixels));

      bitmap.recycle();
    }
    bitmap = null;
    close();
  }

NbadalGifConverter.java (only converting function):

  @Override public void createGifFile(String path, List<String> bitmapsNames) {

    final ByteArrayOutputStream bos = new ByteArrayOutputStream();

    final AnimatedGifEncoder encoder = new AnimatedGifEncoder();
    encoder.setDelay(mDelay);
    encoder.setQuality(mQuality);
    encoder.start(bos);

    for (String bitmapName : bitmapsNames) {
      final Bitmap bitmap = howLong("Retrieving bitmap", () -> BitmapUtils.retrieve(bitmapName));
      howLongVoid("Adding frame", () -> encoder.addFrame(bitmap));
    }

    encoder.finish();
    FileUtils.store(bos.toByteArray(), path.substring(0, path.lastIndexOf('.')) + ".gif");
  }

I'm open to show you another related pieces of code. I would greatly appreciate any help.

[UPDATE]

Logs of the retrieving bitmaps:

D/TimeUtils: Retrieving bitmap executed in 3ms
D/TimeUtils: Retrieving bitmap executed in 3ms
D/TimeUtils: Retrieving bitmap executed in 4ms

解决方案

Firstly I have to thank to the @Spektre for this answer: Effective gif/image color quantization?

My colleague and I just translated it from the C++ to the Java. It shows good results in 4x less time. I'll try to improve it, but this is already much better result, than AnimatedGifEncoder.java (I used before)

Here is the code:

public static final int MAX_COLOR_COUNT = 65536;

/**
 * @param pixels rgb 888
 * @param palette int[256]
 * @return indices of colors in palette
 */
private int[][][] createPalette(int[] pixels, int[] palette) {

  final int[] histogram = new int[MAX_COLOR_COUNT]; // pixel count histogram
  final int[] indices = new int[MAX_COLOR_COUNT]; // here index is color value

  for (int i = 0; i < MAX_COLOR_COUNT; i++) {
    indices[i] = i;    
  }

  // creating histogram
  for (int color : pixels) {
    //                   0001 1111             0111 1110 0000         1111 1000 0000 0000
    color = ((color >> 3) & 0x1F) | ((color >> 5) & 0x7E0) | ((color >> 8) & 0xF800);
    if (histogram[color] < Integer.MAX_VALUE) { // picture must be really big
      histogram[color]++;
    }
  }

  // removing zeros
  int j = 0;
  for (int i = 0; i < MAX_COLOR_COUNT; i++) {
    histogram[j] = histogram[i];
    indices[j] = indices[i];
    if (histogram[j] != 0) {
      j++;
    }
  }
  final int histograms = j;

  // bubble sort
  for (int i = 1; i != 0; ) {
    i = 0;
    for (int x = 0, y = 1; y < histograms; x++, y++) {
      if (histogram[x] < histogram[y]) {
        i = histogram[x];
        histogram[x] = histogram[y];
        histogram[y] = i;
        i = indices[x];
        indices[x] = indices[y];
        indices[y] = i;
        i = 1;
      }
    }
  }

  final int[][][] colorMap = new int[32][64][32];

  int colorTableIndex = 0, x = 0;
  for (; x < histograms; x++) { // main colors
    final int color = indices[x];
    // 1f (16) = 0001 1111 (2)
    // 3f (16) = 0011 1111 (2)
    // (1111 1)(111 111)(1 1111)
    final int b = color & 0x1f;
    final int g = (color >> 5) & 0x3f;
    final int r = (color >> 11) & 0x1f;

    // skip if similar color already in palette[]
    int a = 0, i = 0;
    for (; i < colorTableIndex; i++) {
      final byte tempB = (byte) ((palette[i] >> 3) & 0x1f);
      final byte tempG = (byte) ((palette[i] >> 10) & 0x3f);
      final byte tempR = (byte) ((palette[i] >> 19) & 0x1f);

      // if difference between two colors is pretty small
      // taxicab distance
      int difference = tempB - b;
      if (difference < 0) {
        difference = -difference;
      }
      a = difference;
      difference = tempG - g;
      if (difference < 0) {
        difference = -difference;
      }
      a += difference;
      difference = tempR - r;
      if (difference < 0) {
        difference = -difference;
      }
      a += difference;
      if (a <= 2) { // smaller than 16/8
        a = 1;
        break;
      }
      a = 0;
    }

    if (a != 0) {
      colorMap[r][g][b] = i; // map to existing color
    } else {
      colorMap[r][g][b] = colorTableIndex; // map to new index

      // 1111 1000 1111 1100 1111 1000
      palette[colorTableIndex] = b << 3 | (g << 10) | (r << 19); // fill this index with new color
      colorTableIndex++;
      if (colorTableIndex >= 256/*palette.length*/) {
        x++;
        break;
      }
    }
  }   // colorTableIndex = new color table size

  for (; x < histograms; x++) { // minor colors

    final int color = indices[x];

    final int b = color & 0x1f;
    final int g = (color >> 5) & 0x3f;
    final int r = (color >> 11) & 0x1f;

    // find closest color
    int minDistance = -1;
    int colorIndex = 0;
    for (int a, i = 0; i < colorTableIndex; i++) {
      final byte tempB = (byte) ((palette[i] >> 3) & 0x1f);
      final byte tempG = (byte) ((palette[i] >> 10) & 0x3f);
      final byte tempR = (byte) ((palette[i] >> 19) & 0x1f);

      int difference = tempB - b;
      if (difference < 0) {
        difference = -difference;
      }
      a = difference;
      difference = tempG - g;
      if (difference < 0) {
        difference = -difference;
      }
      a += difference;
      difference = tempR - r;
      if (difference < 0) {
        difference = -difference;
      }
      a += difference;
      if ((minDistance < 0) || (minDistance > a)) {
        minDistance = a;
        colorIndex = i;
      }
    }
    colorMap[r][g][b] = colorIndex;
  }

  return colorMap;
}

private byte[] map(int[] pixels, int[][][] colorMap) {
  final int pixelsLength = pixels.length;

  final byte[] mapped = new byte[pixelsLength];
  for (int i = 0; i < pixelsLength; i++) {
    final int color =
        ((pixels[i] >> 3) & 0x1F) | ((pixels[i] >> 5) & 0x7E0) | ((pixels[i] >> 8) & 0xF800);

    final int b = color & 0x1f;
    final int g = (color >> 5) & 0x3f;
    final int r = (color >> 11) & 0x1f;

    mapped[i] = (byte) colorMap[r][g][b];
  }
  return mapped;
}

这篇关于JPEG文件转换为GIF格式太长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆