0

I have the following code in my backend. I need an equivalent of this in Android Bitmap.

public byte[] extractBytes (String ImageName) throws IOException {
    // open image
    File imgPath = new File(ImageName);
    BufferedImage bufferedImage = ImageIO.read(imgPath);

    // get DataBufferBytes from Raster
    WritableRaster raster = bufferedImage .getRaster();
    DataBufferByte data   = (DataBufferByte) raster.getDataBuffer();

    return ( data.getData() );
}

I have tried the following:

1) Using Bitmap.compress() function

src.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();

2) Using Bitmap.copyPixelsToBuffer() function

int size = src.getRowBytes() * src.getHeight();
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
src.copyPixelsToBuffer(byteBuffer);
byte[] byteArray = byteBuffer.array();

Both of the methods are giving me wrong results which don't match with my backend output.

I have the following code in my backend for Component Labelling Algorithm.

BlobDemo.java

public class BlobDemo
{
    static ListDisplayPanel gui2 = new ListDisplayPanel();
    public BlobDemo(String filename)
    {
        // Load Source image
        BufferedImage srcImage = null;
        try {
           File imgFile = new File(filename);
           srcImage = javax.imageio.ImageIO.read(imgFile);
        }
        catch (IOException ioE) {
          System.err.println(ioE);
          System.exit(1);
       }

        int width = srcImage.getWidth();
        int height = srcImage.getHeight();

        // Get raw image data
        Raster raster = srcImage.getRaster();
        DataBuffer buffer = raster.getDataBuffer();

        int type = buffer.getDataType();
        if (type != DataBuffer.TYPE_BYTE)
        {
            System.err.println("Wrong image data type");
            System.exit(1);
        }
        if (buffer.getNumBanks() != 1)
        {
            System.err.println("Wrong image data format");
            System.exit(1);
        }

        for(int i=0;i<10;i++){
            for(int j=0;j<10;j++){
                int pix = srcImage.getRGB(i, j);
                Color mycolor = new Color(pix);
                int red = mycolor.getRed();
                int green = mycolor.getGreen();
                int blue = mycolor.getBlue();
                String val ="("+red+","+green+","+blue+")";
                System.out.print(val);
            }
            System.out.println();
        }

        DataBufferByte byteBuffer = (DataBufferByte) buffer;
        byte[] srcData =( (DataBufferByte) (buffer)).getData();

        // Sanity check image
        if (width * height * 3 != srcData.length) {
            System.err.println("Unexpected image data size. Should be RGB image");
            System.exit(1);
        }

        // Output Image info
        System.out.printf("Loaded image: '%s', width: %d, height: %d, num bytes: %d\n", filename, width, height, srcData.length);

        // Create Monochrome version - using basic threshold technique
        byte[] monoData = new byte[width * height];
        int srcPtr = 0;
        int monoPtr = 0;

        while (srcPtr < srcData.length)
        {
            int val = ((srcData[srcPtr]&0xFF) + (srcData[srcPtr+1]&0xFF) + (srcData[srcPtr+2]&0xFF)) / 3;
            monoData[monoPtr] = (val > 128) ? 0 : (byte) 0xFF;

            srcPtr += 3;
            monoPtr += 1;
        }       

        byte[] dstData = new byte[srcData.length];

        // Create Blob Finder
        BlobFinder finder = new BlobFinder(width, height);

        ArrayList<BlobFinder.Blob> blobList = new ArrayList<BlobFinder.Blob>();
        finder.detectBlobs(monoData, dstData, 0, -1, (byte)0, blobList);

        // List Blobs
        System.out.printf("Found %d blobs:\n", blobList.size());
        for (BlobFinder.Blob blob : blobList){
            System.out.println(blob);
        }
    }

    public static void main(String[] args)
    {
        System.out.println("Blob Finder Demo");
        new BlobDemo("/home/maruthi/Desktop/images.jpg");
    }
}

BlobFinder.java

public class BlobFinder
{
    private byte[][] COLOUR_ARRAY = {{(byte)103, (byte)121, (byte)255},
                                                {(byte)249, (byte)255, (byte)139},
                                                {(byte)140, (byte)255, (byte)127},
                                                {(byte)167, (byte)254, (byte)255},
                                                {(byte)255, (byte)111, (byte)71}};

    private int width;
    private int height;

    private int[] labelBuffer;

    private int[] labelTable;
    private int[] xMinTable;
    private int[] xMaxTable;
    private int[] yMinTable;
    private int[] yMaxTable;
    private int[] massTable;

    static class Blob
    {
        public int xMin;
        public int xMax;
        public int yMin;
        public int yMax;
        public int mass;

        public Blob(int xMin, int xMax, int yMin, int yMax, int mass)
        {
            this.xMin = xMin;
            this.xMax = xMax;
            this.yMin = yMin;
            this.yMax = yMax;
            this.mass = mass;
        }

        public String toString()
        {
            return String.format("X: %4d -> %4d, Y: %4d -> %4d, mass: %6d", xMin, xMax, yMin, yMax, mass);
        }
    }

    public BlobFinder(int width, int height)
    {
        this.width = width;
        this.height = height;

        labelBuffer = new int[width * height];

        // The maximum number of blobs is given by an image filled with equally spaced single pixel
        // blobs. For images with less blobs, memory will be wasted, but this approach is simpler and
        // probably quicker than dynamically resizing arrays
        int tableSize = width * height / 4;

        labelTable = new int[tableSize];
        xMinTable = new int[tableSize];
        xMaxTable = new int[tableSize];
        yMinTable = new int[tableSize];
        yMaxTable = new int[tableSize];
        massTable = new int[tableSize];
    }

    public List<Blob> detectBlobs(byte[] srcData, byte[] dstData, int minBlobMass, int maxBlobMass, byte matchVal, List<Blob> blobList)
    {
        if (dstData != null && dstData.length != srcData.length * 3)
            throw new IllegalArgumentException("Bad array lengths: srcData 1 byte/pixel (mono), dstData 3 bytes/pixel (RGB)");

        // This is the neighbouring pixel pattern. For position X, A, B, C & D are checked
        // A B C
        // D X

        int srcPtr = 0;
        int aPtr = -width - 1;
        int bPtr = -width;
        int cPtr = -width + 1;
        int dPtr = -1;

        int label = 1;

        // Iterate through pixels looking for connected regions. Assigning labels
        for (int y=0 ; y<height ; y++)
        {
            for (int x=0 ; x<width ; x++)
            {
                labelBuffer[srcPtr] = 0;

                // Check if on foreground pixel
                if (srcData[srcPtr] == matchVal)
                {
                    // Find label for neighbours (0 if out of range)
                    int aLabel = (x > 0 && y > 0)           ? labelTable[labelBuffer[aPtr]] : 0;
                    int bLabel = (y > 0)                        ? labelTable[labelBuffer[bPtr]] : 0;
                    int cLabel = (x < width-1 && y > 0) ? labelTable[labelBuffer[cPtr]] : 0;
                    int dLabel = (x > 0)                        ? labelTable[labelBuffer[dPtr]] : 0;

                    // Look for label with least value
                    int min = Integer.MAX_VALUE;
                    if (aLabel != 0 && aLabel < min) min = aLabel;
                    if (bLabel != 0 && bLabel < min) min = bLabel;
                    if (cLabel != 0 && cLabel < min) min = cLabel;
                    if (dLabel != 0 && dLabel < min) min = dLabel;

                    // If no neighbours in foreground
                    if (min == Integer.MAX_VALUE)
                    {
                        labelBuffer[srcPtr] = label;
                        labelTable[label] = label;

                        // Initialise min/max x,y for label
                        yMinTable[label] = y;
                        yMaxTable[label] = y;
                        xMinTable[label] = x;
                        xMaxTable[label] = x;
                        massTable[label] = 1;

                        label ++;
                    }

                    // Neighbour found
                    else
                    {
                        // Label pixel with lowest label from neighbours
                        labelBuffer[srcPtr] = min;

                        // Update min/max x,y for label
                        yMaxTable[min] = y;
                        massTable[min]++;
                        if (x < xMinTable[min]) xMinTable[min] = x;
                        if (x > xMaxTable[min]) xMaxTable[min] = x;

                        if (aLabel != 0) labelTable[aLabel] = min;
                        if (bLabel != 0) labelTable[bLabel] = min;
                        if (cLabel != 0) labelTable[cLabel] = min;
                        if (dLabel != 0) labelTable[dLabel] = min;
                    }
                }

                srcPtr ++;
                aPtr ++;
                bPtr ++;
                cPtr ++;
                dPtr ++;
            }
        }

        // Iterate through labels pushing min/max x,y values towards minimum label
        if (blobList == null) blobList = new ArrayList<Blob>();

        for (int i=label-1 ; i>0 ; i--)
        {
            if (labelTable[i] != i)
            {
                if (xMaxTable[i] > xMaxTable[labelTable[i]]) xMaxTable[labelTable[i]] = xMaxTable[i];
                if (xMinTable[i] < xMinTable[labelTable[i]]) xMinTable[labelTable[i]] = xMinTable[i];
                if (yMaxTable[i] > yMaxTable[labelTable[i]]) yMaxTable[labelTable[i]] = yMaxTable[i];
                if (yMinTable[i] < yMinTable[labelTable[i]]) yMinTable[labelTable[i]] = yMinTable[i];
                massTable[labelTable[i]] += massTable[i];

                int l = i;
                while (l != labelTable[l]) l = labelTable[l];
                labelTable[i] = l;
            }
            else
            {
                // Ignore blobs that butt against corners
                if (i == labelBuffer[0]) continue;                                  // Top Left
                if (i == labelBuffer[width]) continue;                              // Top Right
                if (i == labelBuffer[(width*height) - width + 1]) continue; // Bottom Left
                if (i == labelBuffer[(width*height) - 1]) continue;         // Bottom Right

                if (massTable[i] >= minBlobMass && (massTable[i] <= maxBlobMass || maxBlobMass == -1))
                {
                    Blob blob = new Blob(xMinTable[i], xMaxTable[i], yMinTable[i], yMaxTable[i], massTable[i]);
                    blobList.add(blob);
                }
            }
        }

        // If dst buffer provided, fill with coloured blobs
        if (dstData != null)
        {
            for (int i=label-1 ; i>0 ; i--)
            {
                if (labelTable[i] != i)
                {
                    int l = i;
                    while (l != labelTable[l]) l = labelTable[l];
                    labelTable[i] = l;
                }
            }

            // Renumber lables into sequential numbers, starting with 0
            int newLabel = 0;
            for (int i=1 ; i<label ; i++)
            {
                if (labelTable[i] == i) labelTable[i] = newLabel++;
                else labelTable[i] = labelTable[labelTable[i]];
            }

            srcPtr = 0;
            int dstPtr = 0;
            while (srcPtr < srcData.length)
            {
                if (srcData[srcPtr] == matchVal)
                {
                    int c = labelTable[labelBuffer[srcPtr]] % COLOUR_ARRAY.length;
                    dstData[dstPtr] = COLOUR_ARRAY[c][0];
                    dstData[dstPtr+1]   = COLOUR_ARRAY[c][1];
                    dstData[dstPtr+2]   = COLOUR_ARRAY[c][2];
                }
                else
                {
                    dstData[dstPtr] = 0;
                    dstData[dstPtr+1]   = 0;
                    dstData[dstPtr+2]   = 0;
                }

                srcPtr ++;
                dstPtr += 3;
            }
        }
        return blobList;
    }
}

I need to convert the above code to Android. I am stuck here.

for(int i=0;i<10;i++) {
    for(int j=0;j<10;j++) {
        int pix= src.getPixel(i,j);
        int red = Color.red(pix);
        int green= Color.green(pix);
        int blue = Color.blue(pix);
        int alpha = Color.alpha(pix);
        String val ="("+red+","+green+","+blue+")";
        System.out.print(val);
    }
    System.out.println();
}

When I print these values, I get totally different results.

I also tried the following.

int[] pix1=new int[width*height];
src.getPixels(pix1, 0, width, 0, 0, width , height );
byte[] pixels= new byte[pix1.length*3];
for (int i = 0; i < pix1.length; i++) {
    int td = pix1[i];
    int tind = i * 3;
    pixels[tind++] = (byte) ((td >> 0) & 0xFF);
    pixels[tind++] = (byte) ((td >> 8) & 0xFF);
    pixels[tind++] = (byte) ((td >> 16) & 0xFF);
}

Example:

enter image description here

Backend Code:

for(int i=0;i<10;i++){
    for(int j=0;j<10;j++){
        int pix = srcImage.getRGB(i, j);
        Color mycolor = new Color(pix);
        int red = mycolor.getRed();
        int green = mycolor.getGreen();
        int blue = mycolor.getBlue();
        String val ="("+red+","+green+","+blue+")";
        System.out.print(val);
    }
    System.out.println();
}

Backend Output:

(253,253,253)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)

Android Code:

for(int i=0;i<10;i++ ){
    for(int j=0;j<10;j++){
        int pixel = test.getPixel(i,j);
        int red = Color.red(pixel);
        int green = Color.green(pixel);
        int blue= Color.blue(pixel);
        String val ="("+red+","+green+","+blue+")";
        System.out.print(val);
    }
    System.out.println();
}

Android Output:

(253,253,253)(254,254,254)(254,254,254)(253,253,253)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(255,255,255)(255,255,255)
(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)(255,255,255)
(253,253,253)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(254,254,254)(254,254,254)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(254,254,254)(255,255,255)(255,255,255)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(254,254,254)(254,254,254)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(255,255,255)
(254,254,254)(254,254,254)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(254,254,254)(255,255,255)(255,255,255)(255,255,255)

How can I get the same byte array in Android as given in the original function?

Fábio Nascimento
  • 2,644
  • 1
  • 21
  • 27
Phenomenal One
  • 2,501
  • 4
  • 19
  • 29
  • I suggest you add a sample image and full example for both Java SE and Android take 2 (Android 1 does the opposite of what you want). And the expected output, perhaps the byte array length and a hash. But even without this, I can say that using two different JPEG decoders may not yield exactly the same values. And color space may differ between the two versions adding another source of error. Why do you need byte array equality? – Harald K Jun 09 '19 at 09:05
  • @haraldK I have added my full code. My problem is that when I load the same image in Backend and Android , I get different values. I need this to implement Component Labelling Algorithm in Android. – Phenomenal One Jun 11 '19 at 03:07
  • When I said *"full example"* I was perhaps a little unclear. What I meant was ["everything needed to reproduce the problem"](https://stackoverflow.com/help/minimal-reproducible-example) (i.e. the different byte arrays), not "all the code you have". ;-) PS: Have you tried using a different format than JPEG, like PNG? PPS: As your Android code uses `Bitmap.getPixel` you are more likely to get the same results by using `BufferedImage.getRGB` in Java SE (as these both give you 32 bit packed ARGB values in sRGB color space). – Harald K Jun 11 '19 at 07:14
  • @haraldK I have added the sample image with output from both Backend and Android codes. Please take a look at them. A lot of pixels vary in values. – Phenomenal One Jun 11 '19 at 08:13
  • Yes they do. But the variations are not visibly significant. As I said in my first comment *"two different JPEG decoders may not yield exactly the same values"*. See for example [this](https://stackoverflow.com/q/27415320/1428606) and [this](https://stackoverflow.com/q/23565889/1428606) from SO. The variations you see are expected. If you can't live with this, either use a self-supplied JPEG decoder, where you can assure the values are always the same for a given output, or switch to another file format. The sample file you provided is a typical example of what JPEG is *not* designed for... – Harald K Jun 11 '19 at 12:15
  • I do of course mean "for a given input"... Sorry. – Harald K Jun 11 '19 at 13:18
  • @haraldK Thanks for your feedback. Can you help with me with converting this `pixel[] ()int array` from Bitmap input to `monodata[] (byte) array`.? I think that will solve my problem – Phenomenal One Jun 11 '19 at 13:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/194773/discussion-between-maruthi-adithya-and-haraldk). – Phenomenal One Jun 11 '19 at 16:33

0 Answers0