如何提取图像中的 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);
}
我需要在 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);
}