在 OpenCV Android 中的相机帧中查找主色

Posted

技术标签:

【中文标题】在 OpenCV Android 中的相机帧中查找主色【英文标题】:Find dominant color in a camera frame in OpenCV Android 【发布时间】:2014-03-21 15:23:44 【问题描述】:

我想在 android CvCameraViewFrame 对象中获取主色。我使用以下 OpenCV Android 代码来执行此操作。此代码从 OpenCV c++ 代码转换为 OpenCV Android 代码。在下面的代码中,我循环遍历相机帧中的所有像素并找到每个像素的颜色并将它们存储在 HashMap 中,以在循环结束时找到主色。循环遍历每个像素大约需要 30 秒。这对我来说是不可接受的。有人可以查看此代码并指出我如何在相机框架中找到主色。

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;
    

非常感谢。

【问题讨论】:

输出 h、w 和 rowSize。得到了什么结果? 我得到 h = 480, w = 640, rowSize = 1920 的输出值而不调整图像大小,当我按照@dervish 的建议调整图像大小时,我得到 h = 100 的输出值, w = 100,行大小 = 300。 【参考方案1】:

OpenCV 有一个Histogram method,它计算所有图像颜色。计算出直方图后,您所要做的就是选择计数最多的那个...

在此处查看教程 (C++):Histogram Calculation.

您还可以查看this *** answer,它显示了如何使用Android 的直方图函数Imgproc.calcHist()

【讨论】:

【参考方案2】:

考虑调整图像大小,然后将结果乘以相同的比例:

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

或者, 你可以查看these solutions:

【讨论】:

非常感谢。正如你所建议的,我通过这个将相机框架调整为 100x100 像素大小的图像。 Size sz = new Size(100, 100); Imgproc.resize(mRgba, mRgba, sz, 0 , 0, Imgproc.INTER_CUBIC ); 这确实提高了我的代码性能。现在我在上面的代码中遇到了另一个问题,它在大多数情况下将主色设为黑色或灰色。我觉得我找到主色的方式存在一些问题。你能帮我解决这个问题吗? 这是一个聪明的主意,但根据调整大小的方法,像素的颜色可能会略有变化。这可能是一个问题,也可能不是问题,这取决于人们需要得到的主色有多准确。【参考方案3】:

您可以使用 k-mean 聚类方法找到主色。 这个链接会很有用。 https://www.youtube.com/watch?v=f54-x3PckH8

【讨论】:

以上是关于在 OpenCV Android 中的相机帧中查找主色的主要内容,如果未能解决你的问题,请参考以下文章

获取相机焦距 OpenCV Android

OpenCV 对象检测 - 中心点

深度图 - 带有 OpenCV 的 Android 中的立体图像

在android上使用带有opencv的usb相机

OpenCV - 如何在 Android 中设置全屏相机视图?

无法在 android 上使用 C++ OpenCV 打开相机