Sigma effect for image


#1

Hi, I found a nice effect for video in vlc : sigma
sigma
Here is the original
original

There is a way to do the same with PImage, something like a filter?


#2

You can try to make your own function by using :

  • loadPixels();

and find a way to reproduce this effect.
Anyway these are all the filters effects in Processing :


#3

I know these thinks, thanks.
I’m just asking a way to do this between load and updatePixels.


#4

It looks like an over saturated image like this ? :


#5

Looks funny. How did you do it? Convert colors to HSV and then turn up saturation to max.?


#6

I googled this sigma thing and I think it’s some kind of sharpening. So you propably have to figure out the color difference between two pixels (or all 8 pixels that are surrounding the one you are looking at) and if it’s a huge difference make it even bigger somehow.

Afaik there is no finished filter that you can simply overlay, at least not in Processing.


#7

I just found this one on Internet by searching “over saturated image” but you can do this with Photoshop :


#8

This makes me happy:

PImage img;
float MAX_VALUE = 255;
float SATURATION = 255;

void setup() {
  img = loadImage("image.jpg");
}

void draw() {
  colorMode(HSB, MAX_VALUE);
  
  img.loadPixels();
  
  PGraphics out = new PGraphics();
  out = createGraphics(img.width, img.height);
  out.beginDraw();
  out.loadPixels();
  for (int i = 0; i < img.pixels.length; i++) {
    float h = hue(img.pixels[i]);
    float b = brightness(img.pixels[i]);
    color c = color(h, SATURATION, b);
    out.pixels[i] = c;
  }
  out.updatePixels();
  out.endDraw();
  out.save("saturated.png");
  
  exit();
}

Feel free to reuse. Put image as “image.jpg” in data folder.


#9

I tried your code with my picture and I have this :
saturated
I thought already about saturation but this sigma is something else and I don’t find what.


#10

Hey !

Here is what I get :

Example

I simply used a high pass filter, bumped up the contrast and merge it to the original one using the color dodge mode.

Hope it helps =)


#11

ok thanks, there is a way to do this with code ?


#12

Of course there is.

You can start by reading this page :
https://lodev.org/cgtutor/filtering.html

See the sharpen matrix. You can adjust the values to get more or less sharpening effect. That’s the first step.

For the second step, I think you can easily find some references on how to bump up the contrast of an image.

And for the blending part see that link :
https://processing.org/reference/blend_.html


#13

Hey,

As an exercice, I tried to recreate your sigma effect with processing.

Here’s the result :

Result

It is not perfect but I think that with some fine tuning you might get the result you wanted.

As for the code :

PImage originalPic, desaturatePic, highPassPic, clampedPic, darkenedPic;
float[][] highPassFilter = { { -1, -1 ,-1 }, 
                             {-1, 9, -1 }, 
                             { -1, -1 , -1 } };
float highPassFactor = 0.8;
                           

void setup() {
  size(1536, 192);
  originalPic = loadImage("testPic.png");
  desaturatePic = desaturate(originalPic);
  highPassPic = applyFilter(desaturatePic, highPassFilter, highPassFactor);
  clampedPic = clamp(highPassPic, 0, 400);
  darkenedPic = multiply(clampedPic, 0.7);
  image(originalPic, 0, 0);
  image(desaturatePic, originalPic.width, 0);
  image(highPassPic, originalPic.width * 2, 0);
  image(clampedPic, originalPic.width * 3, 0);
  image(darkenedPic, originalPic.width * 4, 0);
  
  image(originalPic, originalPic.width * 5, 0);
  int w = originalPic.width;
  int h = originalPic.height;
  blend(darkenedPic, 0, 0, w, h, originalPic.width * 5, 0, w, h, LIGHTEST      );
  
}


void draw() {
}


PImage multiply(PImage img, float factor) {
  PImage result = createImage(img.width, img.height, RGB);
  
  img.loadPixels();
  result.loadPixels();
  
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int idx = getIndex(x, y, img.width);
      float rVal = (img.pixels[idx] >> 16 & 0xFF);
      float gVal = (img.pixels[idx] >> 8 & 0xFF);
      float bVal = (img.pixels[idx] & 0xFF);
      
      result.pixels[idx] = color(rVal * factor, gVal * factor, bVal * factor);
    }
  }
  
  result.updatePixels();
  
  return result;
}


PImage desaturate(PImage img) {
  PImage result = createImage(img.width, img.height, RGB);
  
  img.loadPixels();
  result.loadPixels();
  
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int idx = getIndex(x, y, img.width);
      float rVal = (img.pixels[idx] >> 16 & 0xFF);
      float gVal = (img.pixels[idx] >> 8 & 0xFF);
      float bVal = (img.pixels[idx] & 0xFF);
      
      result.pixels[idx] = color((rVal + gVal + bVal) / 3.0);
    }
  }
  
  result.updatePixels();
  
  return result;
}


PImage clamp(PImage img, int lowLimit, int highLimit) {
  PImage result = createImage(img.width, img.height, RGB);
  
  img.loadPixels();
  result.loadPixels();
  
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int idx = getIndex(x, y, img.width);
      float rVal = (img.pixels[idx] >> 16 & 0xFF);
      float gVal = (img.pixels[idx] >> 8 & 0xFF);
      float bVal = (img.pixels[idx] & 0xFF);
      float sumRGB = rVal + gVal + bVal;
      
      if (sumRGB < lowLimit) {
        result.pixels[idx] = color(0, 0, 0);
      } else if (sumRGB > highLimit) {
        result.pixels[idx] = color(255, 255, 255);
      } else {
        result.pixels[idx] = img.pixels[idx];
      }
    }
  }
  
  result.updatePixels();
  
  return result;
}


PImage applyFilter(PImage img, float[][] filter, float filterFactor) {
  PImage result = createImage(img.width, img.height, RGB);
  int filterDim = filter.length;
  int offset = filterDim / 2;
  
  img.loadPixels();
  result.loadPixels();
  
  for (int imgX = 0; imgX < img.width; imgX++) {
    for (int imgY = 0; imgY < img.height; imgY++) {
      float rVal = 0.0;
      float gVal = 0.0;
      float bVal = 0.0;
      
      for (int filterX = 0; filterX < filterDim; filterX++) {
        for (int filterY = 0; filterY < filterDim; filterY++) {
          int x = imgX + filterX - offset;
          int y = imgY + filterY - offset;
          int idx = getIndex(x, y, img.width);
          
          if (idx > -1 && idx < img.pixels.length) { //for pixels inside the limit of the image process normally
            rVal += ((img.pixels[idx] >> 16 & 0xFF) * filter[filterX][filterY] * filterFactor);
            gVal += ((img.pixels[idx] >> 8 & 0xFF) * filter[filterX][filterY] * filterFactor);
            bVal += ((img.pixels[idx] & 0xFF) * filter[filterX][filterY] * filterFactor);
          } else { //for pixels outside the limit of the image assume pixel is black --> do nothing (other solution can be used)
            
          }
        }
      }
      
      rVal = constrain(rVal, 0 ,255);
      gVal = constrain(gVal, 0 ,255);
      bVal = constrain(bVal, 0 ,255);
      result.pixels[getIndex(imgX, imgY, img.width)] = color(rVal, gVal, bVal);
          
    }
  }
  result.updatePixels();
  
  return result;
}


int getIndex(int x, int y, int w) {
 return x + y * w; 
}

#14

Whoa, thanks a lot !