如何提取图像中的 red/green 像素

How to extract red/green pixels in an image

我需要在 bitmap/Image 中提取 red/green 像素,但我不知道该怎么做。 使用 OpenCV 是一个选择,但我不知道如何使用它,此外它会增加我的应用程序的大小,所以我更喜欢一段代码或其他更轻的库来这样做。'顺便说一句,上下文是 android.

更新

这是我目前使用的代码,但效果不佳,我想要更自动化的东西。

public int getDominantColor(Bitmap bitmap,int RGB_SELECTOR, int Rval, int Gval, int Bval) {//RGB_SELECTOR => 0==getting red colors and 1==getting green color
    if (null == bitmap) return Color.TRANSPARENT;
    //Log.e("func called with",Integer.toString(RGB_SELECTOR));

    int redBucket = 0;
    int greenBucket = 0;
    int blueBucket = 0;
    int alphaBucket = 0;

    boolean hasAlpha = bitmap.hasAlpha();
    int pixelCount = bitmap.getWidth() * bitmap.getHeight();
    int[] pixels = new int[pixelCount];
    bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    int true_pixels_count = 0;

    for (int y = 0, h = bitmap.getHeight(); y < h; y++)
    {
        for (int x = 0, w = bitmap.getWidth(); x < w; x++)
        {
            int color = pixels[x + y * w]; // x + y * width
            if(RGB_SELECTOR == 0 && ((color >> 16) & 0xFF)>Rval &&
                    ((color >> 8) & 0xFF)<Gval && ((color & 0xFF))<Bval){//R
                redBucket += (color >> 16) & 0xFF; // Color.red
                greenBucket += (color >> 8) & 0xFF; // Color.green
                blueBucket += (color & 0xFF); // Color.blue
                if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
                true_pixels_count++;
            }else if(RGB_SELECTOR == 1 && (((color >> 16) & 0xFF)<Rval &&
                    ((color >> 8) & 0xFF)>Gval && ((color & 0xFF))<Bval) ||
                    (((color >> 16) & 0xFF)<0x96 &&
                            ((color >> 8) & 0xFF)>0xBE && ((color & 0xFF))<0x14)){//G
                redBucket += (color >> 16) & 0xFF; // Color.red
                greenBucket += (color >> 8) & 0xFF; // Color.green
                blueBucket += (color & 0xFF); // Color.blue
                if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
                true_pixels_count++;

            }else if(RGB_SELECTOR == 2 && ((color >> 16) & 0xFF)<Rval &&
                    ((color >> 8) & 0xFF)<Gval && ((color & 0xFF))>Bval) {//B
                redBucket += (color >> 16) & 0xFF; // Color.red
                greenBucket += (color >> 8) & 0xFF; // Color.green
                blueBucket += (color & 0xFF); // Color.blue
                if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
                true_pixels_count++;
            }
            else {
                bitmap.setPixel(x,y,Color.WHITE);
            }

        }
    }
    //Log.e("func ended with",Integer.toString(RGB_SELECTOR));
    return Color.argb(
            (hasAlpha) ? (alphaBucket / true_pixels_count) : 255,
            redBucket / true_pixels_count,
            greenBucket / true_pixels_count,
            blueBucket / true_pixels_count);
}

您从位图中使用了 2 种方法。

  • getPixel(int x, int y) // Returns in the int the Color at the specified location.
  • getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) // Returns 像素[ ] 位图中数据的副本。

您可以使用

打开位图
Bitmap img = BitmapFactory.decodeFile("path/to/img.jpg");


然后您可以使用

提取像素值
int pixel = img.getPixel(x,y);


并提取特定的 RGB 值

int red = Color.red(pixel);
int green = Color.green(pixel);


然后您可以遍历像素,检查您感兴趣的值,当值不是 "green-enough" 时,您可以将像素的值设置为例如white(这个没有测试,凭记忆写的)

for (int row = 0; row < img.getWidth(); row++) {
    for (int col = 0; col < img.getHeight(); row++) {
        // Use the previous functions to get the
        // color you are interested in.
        int interestingColor = getMyColor(row, col);

        // Check if the color is within certain
        // range that is "acceptable". If not,
        // make it white.       
        if(!isInRange(interestingColor))
            img.setPixel(row, col, Color.WHITE);
    }
}   


然后您可以检查边缘从哪里开始并仅提取图像的那部分。
如果您需要更复杂的东西,您可能会重新考虑使用 OpenCV。还有例如这个http://libccv.org/。但是,我以前没有用过它,所以我不能说它是否完全符合你的要求。

考虑到我的背景是黑色,我想出了这个方法希望它适用于其他人(因为它是基于 java 它不是那么有效所以你应该考虑在处理之前压缩图像):

public int getDominantColor(Bitmap bitmap) {//gets dominiant color and filters image at the same time
    if (null == bitmap) return Color.TRANSPARENT;

    final int recognitionThreshold = 0x30;
    int redBucket = 0;
    int greenBucket = 0;
    int blueBucket = 0;
    int alphaBucket = 0;

    boolean hasAlpha = bitmap.hasAlpha();
    int pixelCount = bitmap.getWidth() * bitmap.getHeight();
    int[] pixels = new int[pixelCount];
    bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    pixelCount = 0;
    float[] hsl = new float[3];
    for (int y = 0, h = bitmap.getHeight(); y < h; y++)
    {
        for (int x = 0, w = bitmap.getWidth(); x < w; x++)
        {

            int color = pixels[x + y * w]; // x + y * width
            Color.colorToHSV(color,hsl);
            if((hsl[2]>=0.2f && hsl[2]<=0.8f) && ((((color>>16)&0xFF) > recognitionThreshold) ||(((color>>8)&0xFF) > recognitionThreshold))){//you can change Luminiance threshold and green/red threshold for better results but this worked for my case pretty well
                redBucket += (color >> 16) & 0xFF; // Color.red
                greenBucket += (color >> 8) & 0xFF; // Color.green
                blueBucket += (color & 0xFF); // Color.blue
                pixelCount++;
                if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
            }else {
                //this pixel is not my favorite so I color it to white
                bitmap.setPixel(x,y,Color.WHITE);
            }

        }
    }

    return Color.argb(
            (hasAlpha) ? (alphaBucket / pixelCount) : 255,
            redBucket / pixelCount,
            greenBucket / pixelCount,
            blueBucket / pixelCount);
}