nuwan.chamara
nuwan.chamara

Reputation: 487

Find dominant color in a camera frame in OpenCV Android

I want to get the dominant color in an Android CvCameraViewFrame object. I use the following OpenCV Android code to do that. This code is converted from OpenCV c++ code to OpenCV Android code. In the following code I loop through all the pixels in my camera frame and find the color of each pixel and store them in a HashMap to find the dominant color at the end of the loop. To loop through each pixel it takes about 30 seconds. This is unacceptable for me. Could somebody please review this code and point me how can I find the dominant color in a camera frame.

private String[] colors = {"cBLACK", "cWHITE", "cGREY", "cRED", "cORANGE", "cYELLOW", "cGREEN", "cAQUA", "cBLUE", "cPURPLE", "cPINK", "cRED"};

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        mRgba = inputFrame.rgba();

        if (mIsColorSelected) {
            Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_BGR2HSV);

            int h = mRgba.height();             // Pixel height
            int w = mRgba.width();              // Pixel width
            int rowSize = (int)mRgba.step1();       // Size of row in bytes, including extra padding

            float initialConfidence = 1.0f;

            Map<String, Integer> tallyColors = new HashMap<String, Integer>();

            byte[] pixelsTotal = new byte[h*rowSize];
            mRgba.get(0,0,pixelsTotal);

            //This for loop takes about 30 seconds to process for my camera frame
            for (int y=0; y<h; y++) {
                for (int x=0; x<w; x++) {
                    // Get the HSV pixel components

                    int hVal = (int)pixelsTotal[(y*rowSize) + x + 0];   // Hue
                    int sVal = (int)pixelsTotal[(y*rowSize) + x + 1];   // Saturation
                    int vVal = (int)pixelsTotal[(y*rowSize) + x + 2];   // Value (Brightness)


                    // Determine what type of color the HSV pixel is.
                    String ctype = getPixelColorType(hVal, sVal, vVal);
                    // Keep count of these colors.
                    int totalNum = 0;
                    try{
                        totalNum = tallyColors.get(ctype);
                    } catch(Exception ex){
                        totalNum = 0;
                    }
                    totalNum++;
                    tallyColors.put(ctype, totalNum);
                }
            }

            int tallyMaxIndex = 0;
            int tallyMaxCount = -1;
            int pixels = w * h;
            for (int i=0; i<colors.length; i++) {
                String v = colors[i];
                int pixCount;
                try{
                    pixCount = tallyColors.get(v);
                } catch(Exception e){
                    pixCount = 0;
                }
                Log.i(TAG, v + " - " + (pixCount*100/pixels) + "%, ");
                if (pixCount > tallyMaxCount) {
                    tallyMaxCount = pixCount;
                    tallyMaxIndex = i;
                }
            }
            float percentage = initialConfidence * (tallyMaxCount * 100 / pixels);
            Log.i(TAG, "Color of currency note: " + colors[tallyMaxIndex] + " (" + percentage + "% confidence).");

        }

        return mRgba;
    }

    private String getPixelColorType(int H, int S, int V)
    {
        String color;
        if (V < 75)
            color = "cBLACK";
        else if (V > 190 && S < 27)
            color = "cWHITE";
        else if (S < 53 && V < 185)
            color = "cGREY";
        else {  // Is a color
            if (H < 14)
                color = "cRED";
            else if (H < 25)
                color = "cORANGE";
            else if (H < 34)
                color = "cYELLOW";
            else if (H < 73)
                color = "cGREEN";
            else if (H < 102)
                color = "cAQUA";
            else if (H < 127)
                color = "cBLUE";
            else if (H < 149)
                color = "cPURPLE";
            else if (H < 175)
                color = "cPINK";
            else    // full circle 
                color = "cRED"; // back to Red
        }
        return color;
    }

Thank you very much.

Upvotes: 4

Views: 4377

Answers (3)

vijay singh Rajpurohit
vijay singh Rajpurohit

Reputation: 189

You could find dominant color using k-mean clustering method. this link will be useful. https://www.youtube.com/watch?v=f54-x3PckH8

Upvotes: -1

Rui Marques
Rui Marques

Reputation: 8904

OpenCV has an Histogram method which counts all image colors. After the histogram is calculated all you would have to do is to chose the one with the biggest count...

Check here for a tutorial (C++): Histogram Calculation.

You might also the this stackoverflow answer which shows an example on how to use Android's histogram function Imgproc.calcHist().

Upvotes: 5

Y.AL
Y.AL

Reputation: 1793

Think about to resize your images, then you may multiply the results by the same scale:

resize( larg_image, smallerImage , interpolation=cv.CV_INTER_CUBIC );

Or, you may check these solutions:

Upvotes: 4

Related Questions