Как создать гистограмму изображения в Android?

Я попытался сгенерировать гистограмму изображения, используя следующий код,

package com.example.viewfinderee368;

import java.nio.ByteBuffer;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

@SuppressLint("DrawAllocation")
public class HistogramDemo extends Activity {

    Bitmap mainImage;
    Bitmap histroImage;

    ImageView mainImageView;
    LinearLayout histroImageView;

    private DrawOnTop mDrawOnTop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.histrogram);

        mainImageView = (ImageView) findViewById(R.id.img);
        histroImageView = (LinearLayout) findViewById(R.id.histroImg);

        mainImage = ((BitmapDrawable) mainImageView.getDrawable()).getBitmap();
        histroImage = Bitmap.createBitmap(mainImage);

        mDrawOnTop = new DrawOnTop(this);

          mDrawOnTop.mImageWidth = mainImage.getWidth();
          mDrawOnTop.mImageHeight = mainImage.getHeight();
          mDrawOnTop.mBitmap = Bitmap.createBitmap(mDrawOnTop.mImageWidth, 
                  mDrawOnTop.mImageHeight, Bitmap.Config.RGB_565);
          mDrawOnTop.mRGBData = new int[mDrawOnTop.mImageWidth * mDrawOnTop.mImageHeight]; 

          int bytes = mainImage.getByteCount();
          //or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
          //int bytes = b.getWidth()*b.getHeight()*4; 

            ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
            mainImage.copyPixelsToBuffer(buffer); //Move the byte data to the buffer


            byte[] array = buffer.array();
          mDrawOnTop.mYUVData =array;  

          System.arraycopy(array, 0, mDrawOnTop.mYUVData, 0, array.length);
//        mDrawOnTop.invalidate();
          histroImageView.addView(mDrawOnTop);

    }

    class DrawOnTop extends View {
        Bitmap mBitmap;
        Paint mPaintBlack;
        Paint mPaintYellow;
        Paint mPaintRed;
        Paint mPaintGreen;
        Paint mPaintBlue;
        Paint mPaintGray;

        byte[] mYUVData;
        int[] mRGBData;
        int mImageWidth, mImageHeight;
        int[] mRedHistogram;
        int[] mGreenHistogram;
        int[] mBlueHistogram;
        double[] mBinSquared;

        private DrawOnTop(Context context) {
            super(context);

            mPaintBlack = new Paint();
            mPaintBlack.setStyle(Paint.Style.FILL);
            mPaintBlack.setColor(Color.BLACK);
            mPaintBlack.setTextSize(25);

            mPaintYellow = new Paint();
            mPaintYellow.setStyle(Paint.Style.FILL);
            mPaintYellow.setColor(Color.YELLOW);
            mPaintYellow.setTextSize(25);

            mPaintRed = new Paint();
            mPaintRed.setStyle(Paint.Style.FILL);
            mPaintRed.setColor(Color.RED);
            mPaintRed.setTextSize(25);

            mPaintGreen = new Paint();
            mPaintGreen.setStyle(Paint.Style.FILL);
            mPaintGreen.setColor(Color.GREEN);
            mPaintGreen.setTextSize(25);

            mPaintBlue = new Paint();
            mPaintBlue.setStyle(Paint.Style.FILL);
            mPaintBlue.setColor(Color.BLUE);
            mPaintBlue.setTextSize(25);

            mPaintGray = new Paint();
            mPaintGray.setStyle(Paint.Style.FILL);
            mPaintGray.setColor(Color.GRAY);
            mPaintGray.setTextSize(25);


            mBitmap = null;
            mYUVData = null;
            mRGBData = null;
            mRedHistogram = new int[256];
            mGreenHistogram = new int[256];
            mBlueHistogram = new int[256];
            mBinSquared = new double[256];
            for (int bin = 0; bin < 256; bin++)
            {
                mBinSquared[bin] = ((double)bin) * bin;
            } // bin
        }
        @Override
        protected void onDraw(Canvas canvas) {
            if (mBitmap != null)
            {
                canvas.drawColor(Color.WHITE);

                int canvasWidth = 255;
                int canvasHeight =255;
                int newImageWidth = canvasWidth;
                int newImageHeight = canvasHeight;
                int marginWidth = (canvasWidth - newImageWidth)/2;

                // Convert from YUV to RGB
                decodeYUV420SP(mRGBData, mYUVData, mImageWidth, mImageHeight);

                // Draw bitmap
                mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0, 
                        mImageWidth, mImageHeight);

                // Draw black borders                       
                canvas.drawRect(0, 0, marginWidth, canvasHeight, mPaintBlack);
                canvas.drawRect(canvasWidth - marginWidth, 0, 
                        canvasWidth, canvasHeight, mPaintBlack);

                // Calculate histogram
                calculateIntensityHistogram(mRGBData, mRedHistogram, 
                        mImageWidth, mImageHeight, 0);
                calculateIntensityHistogram(mRGBData, mGreenHistogram, 
                        mImageWidth, mImageHeight, 1);
                calculateIntensityHistogram(mRGBData, mBlueHistogram, 
                        mImageWidth, mImageHeight, 2);

                // Calculate mean
                double imageRedMean = 0, imageGreenMean = 0, imageBlueMean = 0;
                double redHistogramSum = 0, greenHistogramSum = 0, blueHistogramSum = 0;

                    for (int bin = 0; bin < 256; bin++)
                {
                    imageRedMean += mRedHistogram[bin] * bin;
                    redHistogramSum += mRedHistogram[bin];
                    imageGreenMean += mGreenHistogram[bin] * bin;
                    greenHistogramSum += mGreenHistogram[bin];
                    imageBlueMean += mBlueHistogram[bin] * bin;
                    blueHistogramSum += mBlueHistogram[bin];
                } // bin
                imageRedMean /= redHistogramSum;
                imageGreenMean /= greenHistogramSum;
                imageBlueMean /= blueHistogramSum;

                // Draw red intensity histogram
                float barMaxHeight = 5000;
                float barWidth = ((float)newImageWidth) / 256;
                float barMarginHeight = 2;
                RectF barRect = new RectF();
                barRect.bottom = canvasHeight -50 ;
                barRect.left = marginWidth;
                barRect.right = barRect.left + barWidth;
                for (int bin = 0; bin < 255; bin++)
                {
                    float prob = (float)mRedHistogram[bin] / (float)redHistogramSum;
                    barRect.top = barRect.bottom - 
                        Math.min(100,prob*barMaxHeight) - barMarginHeight;
                    canvas.drawRect(barRect, mPaintBlack);
                    barRect.top += barMarginHeight;
                    canvas.drawRect(barRect, mPaintGray);
                    barRect.left += barWidth;
                    barRect.right += barWidth;
                } // bin

                // Draw green intensity histogram
                barRect.bottom = canvasHeight -50 ;
                barRect.left = marginWidth;
                barRect.right = barRect.left + barWidth;
                for (int bin = 0; bin < 255; bin++)
                {
                    barRect.top = barRect.bottom - Math.min(100, ((float)mGreenHistogram[bin])/((float)greenHistogramSum) * barMaxHeight) - barMarginHeight;
                    canvas.drawRect(barRect, mPaintBlack);
                    barRect.top += barMarginHeight;
                    canvas.drawRect(barRect, mPaintGray);
                    barRect.left += barWidth;
                    barRect.right += barWidth;
                } // bin

                // Draw blue intensity histogram
                barRect.bottom = canvasHeight -50 ;
                barRect.left = marginWidth;
                barRect.right = barRect.left + barWidth;
                for (int bin = 0; bin < 255; bin++)
                {
                    barRect.top = barRect.bottom - Math.min(100, ((float)mBlueHistogram[bin])/((float)blueHistogramSum) * barMaxHeight) - barMarginHeight;
                    canvas.drawRect(barRect, mPaintBlack);
                    barRect.top += barMarginHeight;
                    canvas.drawRect(barRect, mPaintGray);
                    barRect.left += barWidth;
                    barRect.right += barWidth;
                } // bin
            } // end if statement

            super.onDraw(canvas);

        }

        private void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
            final int frameSize = width * height;

            for (int j = 0, yp = 0; j < height; j++) {
                int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
                for (int i = 0; i < width; i++, yp++) {
                    int y = (0xff & ((int) yuv420sp[yp])) - 16;
                    if (y < 0) y = 0;
                    if ((i & 1) == 0) {
                        v = (0xff & yuv420sp[uvp++]) - 128;
                        u = (0xff & yuv420sp[uvp++]) - 128;
                    }

                    int y1192 = 1192 * y;
                    int r = (y1192 + 1634 * v);
                    int g = (y1192 - 833 * v - 400 * u);
                    int b = (y1192 + 2066 * u);

                    if (r < 0) r = 0; else if (r > 262143) r = 262143;
                    if (g < 0) g = 0; else if (g > 262143) g = 262143;
                    if (b < 0) b = 0; else if (b > 262143) b = 262143;

                    rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
                }
            }
        }


        private void calculateIntensityHistogram(int[] rgb, int[] histogram, int width, int height, int component)
        {
            for (int bin = 0; bin < 256; bin++)
            {
                histogram[bin] = 0;
            } // bin
            if (component == 0) // red
            {
                for (int pix = 0; pix < width*height; pix += 3)
                {
                    int pixVal = (rgb[pix] >> 16) & 0xff;
                    histogram[ pixVal ]++;
                } // pix
            }
            else if (component == 1) // green
            {
                for (int pix = 0; pix < width*height; pix += 3)
                {
                    int pixVal = (rgb[pix] >> 8) & 0xff;
                    histogram[ pixVal ]++;
                } // pix
            }
            else // blue
            {
                for (int pix = 0; pix < width*height; pix += 3)
                {
                    int pixVal = rgb[pix] & 0xff;
                    histogram[ pixVal ]++;
                } // pix
            }
        }
    } 
}



Но это не генерирует надежную гистограмму, мне нужно генерировать ту же гистограмму, что и в Adobe Photoshop.
ВИОС он генерирует ту же гистограмму, что и в Adobe Photoshop, используя следующий код.

 -(void)readImage:(UIImage*)image
{
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
//    NSLog(@"histogram width:- %d",width);
//    NSLog(@"histogram height:- %d",height);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    for (int yy=0;yy<height; yy++)
    {
        for (int xx=0; xx<width; xx++)
        {
            // Now your rawData contains the image data in the RGBA8888 pixel format.
            int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
            for (int ii = 0 ; ii < 1 ; ++ii)
            {
                CGFloat red   = (rawData[byteIndex]     * 1.0) ;
                CGFloat green = (rawData[byteIndex + 1] * 1.0) ;
                CGFloat blue  = (rawData[byteIndex + 2] * 1.0) ;
                // CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
                byteIndex += 4;

                // TYPE CASTING ABOVE FLOAT VALUES TO THAT THEY CAN BE MATCHED WITH ARRAY'S INDEX.

                int redValue = (int)red;
                int greenValue = (int)green;
                int blueValue = (int)blue;


                // THESE COUNTERS COUNT " TOTAL NUMBER OF PIXELS " FOR THAT  Red , Green or Blue Value IN ENTIRE IMAGE.

                fltR[redValue]++;
                fltG[greenValue]++;
                fltB[blueValue]++;
            }
        }
    }
    [self makeArrays];


//    for (int yy=0;yy<height; yy++)
//    {
//        for (int xx=0; xx<width; xx++)
//        {
//            int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
//            rawData [byteIndex] = nil;
//        }
//    }
//    rawData = 0;
//    rawData = nil;
    static unsigned updateCounter = 0;
    memset(rawData, updateCounter & 0xff, width*height*4);
    free(rawData);
    rawData = NULL;

    for(int i=0;i<=255;i++){
        fltR[i]=0;
        fltG[i]=0;
        fltB[i]=0;
    }
    colorSpace = nil;
}

-(void)makeArrays
{
    float max=0;
    int maxR=0;
    int maxG=0;
    int maxB=0;



    // PERFORMING SUMMESION OF ALL RED , GREEN AND BLUE VLAUES GRADUALLY TO TAKE AVERAGE OF THEM
//    NSLog(@"makeArray :- ,fltR[i]  = %f ,fltG[i]  = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i])
    for (int i=0; i<=255; i++)
    {
//        NSLog(@"makeArray :- ,fltR[i]  = %f ,fltG[i]  = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i]);
        maxR += fltR[i];
        maxG += fltG[i];
        maxB += fltB[i];
    }


    // CALCULATING AVERAGE OF ALL red, green and blue values.
    maxR = maxR/255;
    maxG = maxG/255;
    maxB = maxB/255;


    // As  I AM GENERATING 3 GRAPHS , ITS COMPULSARY TO KEEP THEM ON SCREEN SO TAKING THEIR AVERAGE.
    max = (maxR+maxG+maxB)/3;

    // DEVIDED BY 8 TO GET GRAPH OF THE SAME SIZE AS ITS IN PREVIEW
    max = max*2.5;
    arrAllPoints = [[NSMutableArray alloc] init];
    for (int i=0; i<=255; i++)
    {
        ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
        objPoint.x = i;
        objPoint.y = fltR[i]*scale/max;
        [arrAllPoints addObject:objPoint];
    }

    redGraphView.arrRedPoints = arrAllPoints;
//    redGraphView.graphColor = [UIColor redColor];
    redGraphView.graphColor = [UIColor whiteColor];
    [redGraphView drawGraphForArray:arrAllPoints];       /* redGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */

    arrAllPoints = [[NSMutableArray alloc] init];

    for (int i=0; i<=255; i++)
    {
        ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
        objPoint.x = i;
        objPoint.y = fltG[i]*scale/max;
        [arrAllPoints addObject:objPoint];
    }

    greenGraphView.arrRedPoints = arrAllPoints;
//    greenGraphView.graphColor = [UIColor greenColor];
    greenGraphView.graphColor = [UIColor whiteColor];
    [greenGraphView drawGraphForArray:arrAllPoints];         /* greenGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */

    arrAllPoints = [[NSMutableArray alloc] init];

    for (int i=0; i<=255; i++)
    {
        ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
        objPoint.x = i;
        objPoint.y = fltB[i]*scale/max;
        [arrAllPoints addObject:objPoint];
    }
    blueGraphView.arrRedPoints = arrAllPoints;
//    blueGraphView.graphColor = [UIColor blueColor];
    blueGraphView.graphColor = [UIColor whiteColor];
    [blueGraphView drawGraphForArray:arrAllPoints];         /* blueGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */


    // THE COORDINATE SYSTEM OF IOS IS TOTALLY OPPOSITE TO THAT OF THE MAC'S SO ROTATED IT WITH REFERENCE TO X - axis.
    blueGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
    redGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
    greenGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
}

Я пытался найти Adobe Photoshop Android API для этого, но я не нашел. Есть ли другие API для разработки приложения гистограммы?



Спасибо,

Ответы на вопрос(1)

Ваш ответ на вопрос