Eliminate red tint from image

Hi, is it possible to eliminate the red tint from this image using some filter? I need to find in this image the orange ball, but i cannot make the difference between ball and background.

imgL6

1 Like

as a first step could try a usual photo program
just to see how it would turn out by just changing colors
edit

and i think it will be difficult to find a recognition algorithm for the ball.

1 Like

You could remove the red from the image using the filters provided in Processing: https://processing.org/reference/PImage.html

For the recognition algorithm, you can try any of the libraries that you can install using the Contribution Manager in the PDE. Some libraries that come into mind are BoofCV, Blobscanner and OpenCV for Processing.

I tried this silly attempt to pick and group pixels based on color.

Instructions:

There are three functionalities:

  1. mouse clicked will select a pixel in the image
  2. key pressed will reset the image
    • or - to increase or decrease the threshold

When you click and select any pixel in the image, processing will detect all the pixels in the image that are within the color threshold. You can adjust the color threshold using the + and - keys.

In your image, the ball is not an uniform color but it is affected buy the lightning conditions as yuou can see.

Kf

//===========================================================================
// GLOBAL VARIABLES:

PImage pic;
int pickedRed;
int pickedGreen;
int pickedBlue;
color col_threshold;

//===========================================================================
// PROCESSING DEFAULT FUNCTIONS:

void settings() {
  pic = loadImage("orange-ball.jpg", "jpg");
  size(pic.width, pic.height);
}

void setup() {
  //Init values
  resetColorPicked();
  col_threshold = 15;
  noLoop();
}

void draw() {
  image(pic, 0, 0);
  loadPixels();

  for (int i = 0; i < width*height; i++) {

    color argb = pixels[i];
    int a = (argb >> 24) & 0xFF;
    int r = (argb >> 16) & 0xFF;  // Faster way of getting red(argb)
    int g = (argb >> 8) & 0xFF;   // Faster way of getting green(argb)
    int b = argb & 0xFF;          // Faster way of getting blue(argb) 

    if (dist(pickedRed, pickedGreen, pickedBlue, r, g, b)<col_threshold) {
      pixels[i]=color(0);
    }
  }
  updatePixels();
}

void keyReleased() {

  if (key=='+')
    col_threshold++;

  if (key=='-')
    col_threshold--;

  col_threshold=constrain(col_threshold, 0, 50);
  resetColorPicked();
  redraw();

  surface.setTitle("Reset & Thresh: " + col_threshold);
}

void mousePressed() {
  redraw();
  color picked = pixels[mouseX+width*mouseY];
  pickedRed = (picked >> 16) & 0xFF;  
  pickedGreen = (picked >> 8) & 0xFF;   
  pickedBlue = picked & 0xFF;
  surface.setTitle("Thresh: " + col_threshold + " Col "+ pickedRed + ' ' + pickedGreen + ' ' + pickedBlue);
}

//===========================================================================
// OTHER FUNCTIONS:
void resetColorPicked() {
  pickedRed=0; 
  pickedGreen=0; 
  pickedBlue=0;
}
3 Likes

Like @kll l said it’s difficult to find a recognition algorithm for the ball. I like @kfrajer 's code but tried a different approach namely an edge detection method, and then searched in pixelarray for black neighbor pixels in a circular way to find best match. But that is awful slow. I would like to know if someone has a better idea to go further with this method to detect a circle.

PImage g_img; 
int edge_tolerance = 50;
boolean working;

SobelEdgeDetection sobel;

void setup() {
  size(640, 480);
  g_img = loadImage("Ball.jpg"); 
  image(g_img,0,0,width,height);
  sobel = new SobelEdgeDetection();
  textAlign(CENTER);
  textSize(40);
  fill(0);
}

void draw(){
  if(working){
    working = false;
    g_img = sobel.findEdgesAll(g_img, edge_tolerance);
    g_img = sobel.noiseReduction(g_img, 1);
    image(g_img, 0 , 0, width, height);
  }  
}

void mousePressed() {  
  text("WAIT WORKING", width/2, 80);
  working = true;
}

// *******************************************
// Edge Detection
// Credits to: http://www.pages.drexel.edu/~weg22/edge.html for description and source
// *******************************************

class SobelEdgeDetection {
  // Sobel Edge Detection strandard, this applies the edge detection algorithm across the entire image and returns the edge image 
  public PImage findEdgesAll(PImage img, int tolerance) {
    PImage buf = createImage( img.width, img.height, ARGB );
    int GX[][] = new int[3][3];
    int GY[][] = new int[3][3];
    int sumRx = 0;
    int sumGx = 0;
    int sumBx = 0;
    int sumRy = 0;
    int sumGy = 0;
    int sumBy = 0;
    int finalSumR = 0;
    int finalSumG = 0;
    int finalSumB = 0;
    // 3x3 Sobel Mask for X
    GX[0][0] = -1; 
    GX[0][1] = 0; 
    GX[0][2] = 1;
    GX[1][0] = -2; 
    GX[1][1] = 0; 
    GX[1][2] = 2;
    GX[2][0] = -1; 
    GX[2][1] = 0; 
    GX[2][2] = 1;
    // 3x3 Sobel Mask for Y
    GY[0][0] =  1; 
    GY[0][1] =  2; 
    GY[0][2] =  1;
    GY[1][0] =  0; 
    GY[1][1] =  0; 
    GY[1][2] =  0;
    GY[2][0] = -1; 
    GY[2][1] = -2; 
    GY[2][2] = -1; 
    buf.loadPixels();  
    for(int y = 0; y < img.height; y++) {
      for(int x = 0; x < img.width; x++) {
        if(y==0 || y==img.height-1) {
        } else if( x==0 || x == img.width-1 ) {
        } else {
          // Convolve across the X axis and return gradiant aproximation
          for(int i = -1; i <= 1; i++)
            for(int j = -1; j <= 1; j++) {
              color col =  img.get(x + i, y + j);
              float r = red(col);
              float g = green(col);
              float b = blue(col);
              sumRx += r * GX[ i + 1][ j + 1];
              sumGx += g * GX[ i + 1][ j + 1];
              sumBx += b * GX[ i + 1][ j + 1];
            }
          // Convolve across the Y axis and return gradiant aproximation
          for(int i = -1; i <= 1; i++)
            for(int j = -1; j <= 1; j++) {
              color col =  img.get(x + i, y + j);
              float r = red(col);
              float g = green(col);
              float b = blue(col);
              sumRy += r * GY[ i + 1][ j + 1];
              sumGy += g * GY[ i + 1][ j + 1];
              sumBy += b * GY[ i + 1][ j + 1];
            }
          finalSumR = abs(sumRx) + abs(sumRy);
          finalSumG = abs(sumGx) + abs(sumGy);
          finalSumB = abs(sumBx) + abs(sumBy);

          // I only want to return a black or a white value, here I determine the greyscale value,
          // and if it is above a tolerance, then set the colour to white

          float gray = (finalSumR + finalSumG + finalSumB) / 3;
          if(gray > tolerance) {
            finalSumR = 0;
            finalSumG = 0;
            finalSumB = 0;
          } else {
            finalSumR = 255;
            finalSumG = 255;
            finalSumB = 255;
          }
          buf.pixels[ x + (y * img.width) ] = color(finalSumR, finalSumG, finalSumB);
          sumRx=0;
          sumGx=0;
          sumBx=0;
          sumRy=0;
          sumGy=0;
          sumBy=0;
        }
      }
    }
    buf.updatePixels();
    return buf;
  }
  public PImage noiseReduction(PImage img, int kernel) {
    PImage buf = createImage( img.width, img.height, ARGB );
    buf.loadPixels();
    for(int y = 0; y < img.height; y++) {
      for(int x = 0; x < img.width; x++) {
        int sumR = 0;
        int sumG = 0;
        int sumB = 0;
        // Convolute across the image, averages out the pixels to remove noise
        for(int i = -kernel; i <= kernel; i++) {
          for(int j = -kernel; j <= kernel; j++) {
            color col = img.get(x+i,y+j);
            float r = red(col);
            float g = green(col);
            float b = blue(col);
            if(r==255) sumR++;
            if(g==255) sumG++;
            if(b==255) sumB++;
          }
        }
        int halfKernel = (((kernel*2)+1) * ((kernel*2)+1)) / 2 ;
        if(sumR > halfKernel  ) sumR=255; 
        else sumR= 0;
        if(sumG > halfKernel  ) sumG=255; 
        else sumG= 0;
        if(sumB > halfKernel  ) sumB=255; 
        else sumB= 0;
        buf.pixels[ x + (y * img.width) ] = color(sumR, sumG, sumB);
      }
    }
    buf.updatePixels();
    return buf;
  }
}

Ball

3 Likes

thank you for the answer ,it’s working :grin:

1 Like