【问题标题】:Taking too much time when resizing bitmap using Bi-linear algorithm in android在android中使用双线性算法调整位图大小时花费太多时间
【发布时间】:2015-12-22 14:59:30
【问题描述】:

我正在开发一个将大位图加载到 ImageView 的应用程序。在这里,我正在使用 Bi 线性算法来重新调整图像大小,它工作正常,但是调整大小需要太多时间(Bi-linear 算法)。我在下面添加一些代码。

这里是代码:

mutableBitmap = biLinear(mutableBitmap, outWidth,outHeight);// Bi-Linear code 
mutableBitmap = Bitmap.createBitmap(mutableBitmap, 0, 0, mutableBitmap.getWidth(),
                mutableBitmap.getHeight(), m, true); 

双线性算法方法:

 public static Bitmap biLinear(final Bitmap input,int outWidth,int outHeight)
  {
  final int oldHeight=input.getHeight(),oldWidth=input.getWidth();
  final int newHeight=outHeight,newWidth=outWidth;

  Bitmap output =Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);

  // position of the top left pixel of the 4 pixels to use interpolation on
  int xTopLeft,yTopLeft;
  int x,y,lastTopLefty;
  final float xRatio=(float)newWidth/(float)oldWidth,yratio=(float)newHeight/(float)oldHeight;
  // Y color ratio to use on left and right pixels for interpolation
  float ycRatio2=0,ycRatio1=0;
  // pixel target in the src
  float xt,yt;
  // X color ratio to use on left and right pixels for interpolation
  float xcRatio2=0,xcratio1=0;
  int rgbTopLeft=0,rgbTopRight=0,rgbBottomLeft=0,rgbBottomRight=0,rgbTopMiddle=0,rgbBottomMiddle=0;
  // do the resizing:
  for(x=0;x<newWidth;x++)
    {
    xTopLeft=(int)(xt=x/xRatio);
    // when meeting the most right edge, move left a little
    if(xTopLeft>=oldWidth-1)
      xTopLeft--;
    if(xt<=xTopLeft+1)
      {
      // we are between the left and right pixel
      xcratio1=xt-xTopLeft;
      // color ratio in favor of the right pixel color
      xcRatio2=1-xcratio1;
      }
    for(y=0,lastTopLefty=Integer.MIN_VALUE;y<newHeight;y++)
      {
      yTopLeft=(int)(yt=y/yratio);
      // when meeting the most bottom edge, move up a little
      if(yTopLeft>=oldHeight-1)
        yTopLeft--;
      // we went down only one rectangle
      if(lastTopLefty==yTopLeft-1)
        {
        rgbTopLeft=rgbBottomLeft;
        rgbTopRight=rgbBottomRight;
        rgbTopMiddle=rgbBottomMiddle;
        rgbBottomLeft=input.getPixel(xTopLeft,yTopLeft+1);
        rgbBottomRight=input.getPixel(xTopLeft+1,yTopLeft+1);
        rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
            (int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
            (int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
            (int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
        }
      else if(lastTopLefty!=yTopLeft)
        {
        // we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
        rgbTopLeft=input.getPixel(xTopLeft,yTopLeft);
        rgbTopRight=input.getPixel(xTopLeft+1,yTopLeft);
        rgbTopMiddle=Color.argb((int)(Color.alpha(rgbTopLeft)*xcRatio2+Color.alpha(rgbTopRight)*xcratio1),//
            (int)(Color.red(rgbTopLeft)*xcRatio2+Color.red(rgbTopRight)*xcratio1),//
            (int)(Color.green(rgbTopLeft)*xcRatio2+Color.green(rgbTopRight)*xcratio1),//
            (int)(Color.blue(rgbTopLeft)*xcRatio2+Color.blue(rgbTopRight)*xcratio1));
        rgbBottomLeft=input.getPixel(xTopLeft,yTopLeft+1);
        rgbBottomRight=input.getPixel(xTopLeft+1,yTopLeft+1);
        rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
            (int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
            (int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
            (int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
        }
      lastTopLefty=yTopLeft;
      if(yt<=yTopLeft+1)
        {
        // color ratio in favor of the bottom pixel color
        ycRatio1=yt-yTopLeft;
        ycRatio2=1-ycRatio1;
        }
      // prepared all pixels to look at, so finally set the new pixel data
      output.setPixel(x,y,Color.argb(//
          (int)(Color.alpha(rgbTopMiddle)*ycRatio2+Color.alpha(rgbBottomMiddle)*ycRatio1),//
          (int)(Color.red(rgbTopMiddle)*ycRatio2+Color.red(rgbBottomMiddle)*ycRatio1),//
          (int)(Color.green(rgbTopMiddle)*ycRatio2+Color.green(rgbBottomMiddle)*ycRatio1),//
          (int)(Color.blue(rgbTopMiddle)*ycRatio2+Color.blue(rgbBottomRight)*ycRatio1)));
      }
    }
  return output;
  }

这个算法需要将近 15-20 秒来加载图像

有没有可能减少加载时间

如果有人知道,请帮助我

提前致谢。

【问题讨论】:

    标签: android algorithm bitmap


    【解决方案1】:

    为每个像素调用 getPixel/setPixel 方法可能需要很长时间。 我建议你改用 copyPixelsToBuffer/copyPixelsFromBuffer 方法。

    例如:

        public static Bitmap biLinear(final Bitmap input,int outWidth,int outHeight) {
    
        if(input.getConfig() != Bitmap.Config.ARGB_8888) {
            // this example assumes that input bitmap configuration is Bitmap.Config.ARGB_8888
            throw new RuntimeException();
        }
    
    
        final int oldHeight=input.getHeight(),oldWidth=input.getWidth();
        final int newHeight=outHeight,newWidth=outWidth;
    
        IntBuffer inputBuffer = IntBuffer.allocate(oldWidth * oldHeight);
        IntBuffer outputBuffer = IntBuffer.allocate(newWidth * newHeight);
    
        Bitmap output = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
    
        input.copyPixelsToBuffer(inputBuffer);
    
        // position of the top left pixel of the 4 pixels to use interpolation on
        int xTopLeft,yTopLeft;
        int x,y,lastTopLefty;
        final float xRatio=(float)newWidth/(float)oldWidth,yratio=(float)newHeight/(float)oldHeight;
        // Y color ratio to use on left and right pixels for interpolation
        float ycRatio2=0,ycRatio1=0;
        // pixel target in the src
        float xt,yt;
        // X color ratio to use on left and right pixels for interpolation
        float xcRatio2=0,xcratio1=0;
        int rgbTopLeft=0,rgbTopRight=0,rgbBottomLeft=0,rgbBottomRight=0,rgbTopMiddle=0,rgbBottomMiddle=0;
        // do the resizing:
        for(x=0;x<newWidth;x++)
        {
            xTopLeft=(int)(xt=x/xRatio);
            // when meeting the most right edge, move left a little
            if(xTopLeft>=oldWidth-1)
                xTopLeft--;
            if(xt<=xTopLeft+1)
            {
                // we are between the left and right pixel
                xcratio1=xt-xTopLeft;
                // color ratio in favor of the right pixel color
                xcRatio2=1-xcratio1;
            }
            for(y=0,lastTopLefty=Integer.MIN_VALUE;y<newHeight;y++)
            {
                yTopLeft=(int)(yt=y/yratio);
                // when meeting the most bottom edge, move up a little
                if(yTopLeft>=oldHeight-1)
                    yTopLeft--;
                // we went down only one rectangle
                if(lastTopLefty==yTopLeft-1)
                {
                    rgbTopLeft=rgbBottomLeft;
                    rgbTopRight=rgbBottomRight;
                    rgbTopMiddle=rgbBottomMiddle;
                    rgbBottomLeft=inputBuffer.get(xTopLeft + (oldWidth * (yTopLeft+1)));
                    rgbBottomRight=inputBuffer.get(xTopLeft+1 + (oldWidth * (yTopLeft+1)));
                    rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
                            (int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
                            (int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
                            (int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
                }
                else if(lastTopLefty!=yTopLeft)
                {
                    // we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
                    rgbTopLeft=inputBuffer.get(xTopLeft + (oldWidth * yTopLeft));
                    rgbTopRight=inputBuffer.get(xTopLeft+1 + (oldWidth * yTopLeft));
                    rgbTopMiddle=Color.argb((int)(Color.alpha(rgbTopLeft)*xcRatio2+Color.alpha(rgbTopRight)*xcratio1),//
                            (int)(Color.red(rgbTopLeft)*xcRatio2+Color.red(rgbTopRight)*xcratio1),//
                            (int)(Color.green(rgbTopLeft)*xcRatio2+Color.green(rgbTopRight)*xcratio1),//
                            (int)(Color.blue(rgbTopLeft)*xcRatio2+Color.blue(rgbTopRight)*xcratio1));
                    rgbBottomLeft=inputBuffer.get(xTopLeft + (oldWidth * (yTopLeft+1)));
                    rgbBottomRight=inputBuffer.get(xTopLeft+1+(oldWidth * (yTopLeft+1)));
                    rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
                            (int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
                            (int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
                            (int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
                }
                lastTopLefty=yTopLeft;
                if(yt<=yTopLeft+1)
                {
                    // color ratio in favor of the bottom pixel color
                    ycRatio1=yt-yTopLeft;
                    ycRatio2=1-ycRatio1;
                }
                // prepared all pixels to look at, so finally set the new pixel data
                outputBuffer.put(x + outWidth * y,Color.argb(//
                        (int)(Color.alpha(rgbTopMiddle)*ycRatio2+Color.alpha(rgbBottomMiddle)*ycRatio1),//
                        (int)(Color.red(rgbTopMiddle)*ycRatio2+Color.red(rgbBottomMiddle)*ycRatio1),//
                        (int)(Color.green(rgbTopMiddle)*ycRatio2+Color.green(rgbBottomMiddle)*ycRatio1),//
                        (int)(Color.blue(rgbTopMiddle)*ycRatio2+Color.blue(rgbBottomRight)*ycRatio1)));
            }
        }
    
        output.copyPixelsFromBuffer(outputBuffer);
        return output;
    }
    

    【讨论】:

    • 抱歉回复晚了。我尝试在上面的代码中实现这些方法,但我未能将 setpixels 的参数转换为缓冲区。实际上我是这个概念的新手,所以你能给出一些代码 sn-p 吗?
    • @user512 ,我已修改您的代码以使用缓冲区并作为示例添加
    猜你喜欢
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    相关资源
    最近更新 更多