Q: Full bitmap is not being populated with pixel data after parallelization. I have an app that processes a bitmap with a spherize distortion. You can touch the screen and set the radius of a circle that will contain the distortion. Once the distort button is pressed a subset bitmap is created the same size of the radius and this subset bitmap is sent for processing. Once the subset is distorted it is put back on the original bitmap as an overlay using the x,y cords from the original touch event. 
Everything works fine apart from that the last line of pixels (across the bottom) of the subset bitmap is not populated with pixel data. It looks like there is a black line at the bottom of the subset bitmap. The distortion class uses parallel programming. This checks the hardware at runtime to find out how many processor are available and the splits the bitmap up over the processor accordingly. I've had help with the parallelization and not sure how to find out why the black line is present. The looping seems to be in order, any ideas? Thanks in advance Matt.
.
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import android.graphics.Bitmap;
import android.os.Debug;
import android.util.Log;

public class MultiRuntimeProcessorFilter {



    private static final String TAG = "mrpf";
    private int x = 0;
    private Bitmap input = null;
    private int radius;


    public void createBitmapSections(int nOp, int[] sections){

        int processors = nOp;
        int jMax = input.getHeight();
        int aSectionSize = (int) Math.ceil(jMax/processors);
        Log.e(TAG, "++++++++++ sections size = "+aSectionSize);


        int k = 0;
        for(int h=0; h<processors+1; h++){

                sections[h] = k;
                k+= aSectionSize;



        }
    }// end of createBitmapSections()



    @SuppressWarnings("unchecked")
    public Bitmap barrel (Bitmap input, float k, int r){
          this.radius = r;
          this.input = input;
          int []arr = new int[input.getWidth()*input.getHeight()];




          int nrOfProcessors = Runtime.getRuntime().availableProcessors();
          int[] sections = new int[nrOfProcessors+1];


          createBitmapSections(nrOfProcessors,sections);
          ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

          for(int g=0; g<sections.length;g++){
              Log.e(TAG, "++++++++++ sections= "+sections[g]);
          }

         // ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

          Object[] task = new Object[nrOfProcessors];

          for(int z = 0; z < nrOfProcessors; z++){
             task[z]  = (FutureTask<PartialResult>) threadPool.submit(new PartialProcessing(sections[z], sections[z+1] - 1, input, k));  
             Log.e(TAG, "++++++++++ task"+z+"= "+task[z].toString()); 
          }

         PartialResult[] results = new PartialResult[nrOfProcessors];

         try{
              for(int t = 0; t < nrOfProcessors; t++){

                  results[t] = ((FutureTask<PartialResult>) task[t]).get();

                  results[t].fill(arr);
              }

          }catch(Exception e){
              e.printStackTrace();
          }

          Bitmap dst2 = Bitmap.createBitmap(arr,input.getWidth(),input.getHeight(),input.getConfig());


        return dst2;


        }//end of barrel()




    public class PartialResult {
           int startP;
           int endP;
           int[] storedValues;

           public PartialResult(int startp, int endp, Bitmap input){

               this.startP = startp;
               this.endP = endp;
               this.storedValues = new int[input.getWidth()*input.getHeight()];


           }

           public void addValue(int p, int result) {
                 storedValues[p] = result;

           }

           public void fill(int[] arr) {



              for (int p = startP; p < endP; p++){
                  for(int b=0;b<radius;b++,x++)
                 arr[x] = storedValues[x];

              } 
              Log.e(TAG, "++++++++++ x ="+x);
              }

           }//end of partialResult




    public class PartialProcessing implements Callable<PartialResult> {
        int startJ;
        int endJ;


        private int[] scalar;
        private float xscale;
        private float yscale;
        private float xshift;
        private float yshift;
        private float thresh = 1;
        private int [] s1;
        private int [] s2;
        private int [] s3;
        private int [] s4;
        private int [] s;
        private Bitmap input;
        private float k;



        public PartialProcessing(int startj, int endj, Bitmap input, float k) {

            this.startJ = startj;
            this.endJ = endj;
            this.input = input;
            this.k = k;

            s = new int[4];
            scalar = new int[4];
            s1 = new int[4];
            s2 = new int[4];
            s3 = new int[4];
            s4 = new int[4];

        }

        int [] getARGB(Bitmap buf,int x, int y){

            int rgb = buf.getPixel(y, x); // Returns by default ARGB.
            // int [] scalar = new int[4];
           //  scalar[0] = (rgb >>> 24) & 0xFF;
             scalar[1] = (rgb >>> 16) & 0xFF;
             scalar[2] = (rgb >>> 8) & 0xFF;
             scalar[3] = (rgb >>> 0) & 0xFF;
             return scalar;

        }



        float getRadialX(float x,float y,float cx,float cy,float k){

            x = (x*xscale+xshift);
            y = (y*yscale+yshift);
            float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
            return res;
          }

          float getRadialY(float x,float y,float cx,float cy,float k){

            x = (x*xscale+xshift);
            y = (y*yscale+yshift);
            float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
            return res;
          }



          float calc_shift(float x1,float x2,float cx,float k){

            float x3 = (float)(x1+(x2-x1)*0.5);
            float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
            float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));

            if(res1>-thresh && res1 < thresh)
              return x1;
            if(res3<0){
              return calc_shift(x3,x2,cx,k);
            }
            else{
              return calc_shift(x1,x3,cx,k);
            }
          }


          void sampleImage(Bitmap arr, float idx0, float idx1)
          {

             // s = new int [4];
            if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){
              s[0]=0;
              s[1]=0;
              s[2]=0;
              s[3]=0;
              return;
            }

            float idx0_fl=(float) Math.floor(idx0);
            float idx0_cl=(float) Math.ceil(idx0);
            float idx1_fl=(float) Math.floor(idx1);
            float idx1_cl=(float) Math.ceil(idx1);



             s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
             s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
             s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
             s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);

            float x = idx0 - idx0_fl;
            float y = idx1 - idx1_fl;

           // s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
            s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
            s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
            s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));


          }



        @Override public PartialResult call() { 

             PartialResult partialResult = new PartialResult(startJ, endJ,input);

             float centerX=input.getWidth()/2; //center of distortion
             float centerY=input.getHeight()/2;



             int width = input.getWidth(); //image bounds
             int height = input.getHeight();



              xshift = calc_shift(0,centerX-1,centerX,k);

              float newcenterX = width-centerX;
              float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k);

              yshift = calc_shift(0,centerY-1,centerY,k);

              float newcenterY = height-centerY;
              float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k);

              xscale = (width-xshift-xshift_2)/width;

              yscale = (height-yshift-yshift_2)/height;


            int p = startJ*radius; 
            int origPixel = 0;
            int color = 0;
            int i;

            for (int j = startJ; j <  endJ; j++){

                for ( i = 0; i < width; i++, p++){


             origPixel = input.getPixel(i,j);

             float x = getRadialX((float)j,(float)i,centerX,centerY,k);


             float y = getRadialY((float)j,(float)i,centerX,centerY,k);

             sampleImage(input,x,y);

             color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
            //Log.e(TAG, "radius = "+radius);

             if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*(radius/4)){

                                 partialResult.addValue(p, color);


            }else{


                partialResult.addValue(p, origPixel);



            }

                }//end of inner for

        }//end of outer for

            return partialResult;
    }//end of call


}// end of partialprocessing

}//end of MultiProcesorFilter

.
[update] I'll post the view class that calls the barrel method. this class gets the touch events and sets the radius of the distortion prior to processing. You can see more how everything is set up before the distortion is applied.
public class TouchView extends View{


    private File tempFile;
    private byte[] imageArray;
    private Bitmap bgr;

    private Bitmap crop;
    private Bitmap crop2;
    private Bitmap overLay;
    private Bitmap overLay2;

    private Paint pTouch;
    private float centreX;
    private float centreY;
    private float centreA;
    private float centreB;
    private Boolean xyFound = false;
    private Boolean abFound = false;
    private int Progress = 1;
    private static final String TAG = "*********TouchView";
    private Filters f = null;
    private Filters f2 = null;
    private boolean bothCirclesInPlace = false;
    private MultiProcessorFilter mpf;
    private MultiProcessorFilter mpf2;
    private MultiRuntimeProcessorFilter mrpf;
    private MultiRuntimeProcessorFilter mrpf2;
    private  int radius = 50;
    protected boolean isLocked = false;
    protected boolean isSaved = false;
    protected byte [] data;
    private float distance1;
    private float distance2;



    public TouchView(Context context) {
        super(context);

    }




    public TouchView(Context context, AttributeSet attr) {
        super(context,attr);
        Log.e(TAG, "++++++++++ inside touchview constructor");



        tempFile = new File(Environment.getExternalStorageDirectory().
                getAbsolutePath() + "/"+"image.jpeg");

        imageArray = new byte[(int)tempFile.length()];


    // new Thread(new Runnable() {
    //      public void run() {



     try{

            InputStream is = new FileInputStream(tempFile);
            BufferedInputStream bis = new BufferedInputStream(is);
            DataInputStream dis = new DataInputStream(bis);


            int i = 0;

            while (dis.available() > 0 ) {
            imageArray[i] = dis.readByte();
            i++;
            }

            dis.close();


       } catch (Exception e) {

               e.printStackTrace();
            }

         //    }
          //    }).start();

       Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length);

        if(bm == null){
            Log.e(TAG, "bm = null");
        }else{
            Log.e(TAG, "bm =  not null");
        }


        bgr = bm.copy(bm.getConfig(), true);

        overLay = null;
        overLay2 = null;



       bm.recycle();

    pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);         
   // pTouch.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT)); 
    pTouch.setColor(Color.RED);
    pTouch.setStyle(Paint.Style.STROKE);


    }// end of touchView constructor


    public void findCirclePixels(){ 


              //f = new Filters();
              // f2 = new Filters();
              //mpf = new MultiProcessorFilter();
              //mpf2 = new MultiProcessorFilter();
            mrpf = new MultiRuntimeProcessorFilter();
            mrpf2 = new MultiRuntimeProcessorFilter();
            crop = Bitmap.createBitmap(bgr,Math.max((int)centreX-radius,0),Math.max((int)centreY-radius,0),radius*2,radius*2);
            crop2 = Bitmap.createBitmap(bgr,Math.max((int)centreA-radius,0),Math.max((int)centreB-radius,0),radius*2,radius*2);

              new Thread(new Runnable() {
                public void run() {
                    float prog = (float)Progress/150001;

              // final Bitmap bgr3 = f.barrel(crop,prog);
              //  final Bitmap bgr4 = f2.barrel(crop2,prog);

                //final Bitmap bgr3 = mpf.barrel(crop,prog);
               // final Bitmap bgr4 = mpf2.barrel(crop2,prog);

                    final Bitmap bgr3 = mrpf.barrel(crop,prog,radius*2);
                    final Bitmap bgr4 = mrpf2.barrel(crop2,prog, radius*2);

                  TouchView.this.post(new Runnable() {
                    public void run() {


                      TouchView.this.overLay = bgr3;
                      TouchView.this.overLay2 = bgr4;

                      TouchView.this.invalidate();
                    }
                  });
                }
              }).start();




        }// end of findCirclePixels()




    @Override
    public boolean onTouchEvent(MotionEvent ev) {



        switch (ev.getAction()) {



            case MotionEvent.ACTION_DOWN: {

                 int w = getResources().getDisplayMetrics().widthPixels;
                 int h = getResources().getDisplayMetrics().heightPixels;

                 if(ev.getX() <radius || ev.getX() > w - radius ){

                    // Log.e(TAG, "touch event is too near width edge!!!!!!!!!!");
                     showToastMessage("You touched too near the screen edge");
                     break;

                 }

                    if(ev.getY() <radius || ev.getY() > h  - radius ){

                    // Log.e(TAG, "touch event is too near height edge!!!!!!!!!!");
                     showToastMessage("You touched too near the screen edge");
                     break;
                 }

                 distance1 = (float) Math.sqrt(Math.pow(ev.getX() - centreX, 2.0) + Math.pow(ev.getY() - centreY, 2.0));
                 distance2 = (float) Math.sqrt(Math.pow(ev.getX() - centreA, 2.0) + Math.pow(ev.getY() - centreB, 2.0));
                 Log.e(TAG, "dist1 = "+distance1 +" distance2 = " + distance2);


                if(isLocked == false){

                if(abFound == false){
                    centreA = (int) ev.getX();
                    centreB = (int) ev.getY();
                    abFound = true;


                    invalidate();

                    }

                if(xyFound == false){
                centreX = (int) ev.getX();
                centreY = (int) ev.getY();
                xyFound = true;
                invalidate();

                }


                if(abFound == true && xyFound == true){
                 bothCirclesInPlace  = true;
                }
                break;
                }
            }

            case MotionEvent.ACTION_MOVE: {

                if(isLocked == false){

                /*if(xyFound == false){
                    centreX = (int) ev.getX()-70;
                    centreY = (int) ev.getY()-70;
                    xyFound = true;
                }else{
                    centreA = (int) ev.getX()-70;
                    centreB = (int) ev.getY()-70;
                    bothCirclesInPlace = true;
                    invalidate();
                    }
                    */


                    if(distance1 < distance2){
                        centreX = (int) ev.getX();
                        centreY = (int) ev.getY();
                        xyFound = true;
                        invalidate();
                    }else{
                        centreA = (int) ev.getX();
                        centreB = (int) ev.getY();
                        bothCirclesInPlace = true;
                        invalidate();
                        }
                    break;
                }

            }          

            case MotionEvent.ACTION_UP: 


                break;

        }

        return true;

    }//end of onTouchEvent





    public void initSlider(final HorizontalSlider slider)
    {

        slider.setOnProgressChangeListener(changeListener);


    }



    private OnProgressChangeListener changeListener = new OnProgressChangeListener() {


        @Override
        public void onProgressChanged(View v, int progress) {


            if(isLocked == true){
              setProgress(progress);
            }else{
                Toast.makeText(TouchView.this.getContext(), "press lock before applying distortion ", Toast.LENGTH_SHORT).show();
            }



        }
    };





    @Override
    public void onDraw(Canvas canvas){
        super.onDraw(canvas);



        Log.e(TAG, "******about to draw bgr ");
        canvas.drawBitmap(bgr, 0, 0, null);

        if(isSaved == false){

        if (isLocked == true && bothCirclesInPlace == true){
            if(overLay != null)
             canvas.drawBitmap(overLay, centreX-radius, centreY-radius, null);
            if(overLay2 != null)
             canvas.drawBitmap(overLay2, centreA-radius, centreB-radius, null);
        }


        if(bothCirclesInPlace == true && isLocked == false){


            canvas.drawCircle(centreX, centreY, radius,pTouch);
            canvas.drawCircle(centreA, centreB, radius,pTouch);     

        }    

        }else{

        // String mFilePath  : Absolute Path of the file to be saved 

        // Bitmap mBitmap1   : First bitmap. This goes as background.
        // Bitmap mCBitmap   : Bitmap associated with the Canvas. All draws on the canvas are drawn into this bitmap.
        // Bitmap mBitmap2   : Second bitmap. This goes on top of first (in this example serves as foreground.

        // Paint mPaint1     : Paint to draw first bitmap
        // Paint mPaint2     : Paint to draw second bitmap on top of first bitmap

        isSaved = false;
        Bitmap mCBitmap = Bitmap.createBitmap(bgr.getWidth(), bgr.getHeight(), bgr.getConfig());

        Canvas tCanvas = new Canvas(mCBitmap);

        tCanvas.drawBitmap(bgr, 0, 0, null);



        if(overLay != null)
        tCanvas.drawBitmap(overLay, centreX-radius, centreY-radius, null);

        if(overLay2 != null)
             tCanvas.drawBitmap(overLay2, centreA-radius, centreB-radius, null);

        canvas.drawBitmap(mCBitmap, 0, 0, null);



        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        mCBitmap.compress(CompressFormat.JPEG, 100 /*ignored for PNG*/, bos);
        data = bos.toByteArray();
        try {
            bos.flush();
            bos.close();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try {
            bos.flush();
            bos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if ( data == null){
            Log.e(TAG, "data in touchview before save clicked is null");
        }else{
            Log.e(TAG, "data in touchview before saved clicked is not null");
        }


        }

    }//end of onDraw




    protected void setProgress(int progress2) {
        Log.e(TAG, "***********in SETPROGRESS");
        this.Progress = progress2;



        findCirclePixels();


    }




    public  int getRadius() {
        return radius;
    }




    public  void setRadius(int r) {
        radius = r;
        invalidate();
    }


    public void showToastMessage(String mess){

        Toast.makeText(TouchView.this.getContext(), mess.toString(), Toast.LENGTH_SHORT).show();

    }

}


A: My guess would be that when the bottom of the image is processed, the operation operates partially on the input image, and partially outside of the image, due to the radius in your barrel method. Edges can often cause issues when operating outside the bounds of an actual image, giving 0 as a result, which can cause a black line...
I suggest to try to increase the size of your image:
@SuppressWarnings("unchecked")
public Bitmap barrel (Bitmap input, float k, int r){
    this.radius = r;
    this.input = input;

    // Add an offset to the width and height equal to the radius
    // To avoid performing processing outside the bounds of the input image
    int []arr = new int[(input.getWidth() + this.radius) * (input.getHeight() + this.radius)];
    // Continue...

Again, this is my first guess, and I have no time to check right now, but surely, investigating the edge first, would be my recommendation.

A: just a guess, what happen if you put this
BitmapDrawable bmpd = new BitmapDrawable(input);
int []arr = new int[(bmpd.getIntrinsicWidth() + this.radius) * (bmpd. getIntrinsicHeight() + this.radius)];


A: Your problem most likely has to do with your assumed coordinate system of the image and of the spherize algorithm.
See MathWorks Image Coordinate Systems
I expect that you are treating your input/output images according to the Pixel Indices method, but the spherize algorithm is processing your data using the Spatial Coordinate System.  This often causes the outermost border of a processed image to be blank because the algorithm has translated your image up and to the left by 0.5 pixels.  Coordinate 3 in the original system is now 3.5 in the new system and has fallen outside the bounds of computation.
This is actually a huge problem in 2D to 3D image processing algorithms as the projection between the two spaces is not exactly trivial and tiny implementation differences cause noticeable problems.  Notice how the Pixel Indices coordinate system is 3x3, but the Spatial Coordinate system is essentially 4x4.
Try setting your spherize barrel to be width+1/height+1 instead of width/height and see if that fills out your missing row.
