/*******************************************************************************
* Copyright 2017 Ivan Shubin http://galenframework.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.galenframework.rainbow4j.filters;
import com.galenframework.rainbow4j.BufferUtils;
import com.galenframework.rainbow4j.ImageHandler;
import java.awt.*;
import java.nio.ByteBuffer;
public class DenoiseFilter implements ImageFilter {
private int radius;
public DenoiseFilter(int radius) {
this.radius = radius;
}
@Override
public void apply(ByteBuffer bytes, int width, int height, Rectangle area) {
radius = Math.min(radius, Math.min(width / 2, height / 2));
int normalThreshold = 100;
if (radius > 0) {
ByteBuffer copyBytes = BufferUtils.clone(bytes);
for (int yc = area.y; yc < area.y + area.height; yc++) {
for (int xc = area.x; xc < area.x + area.width; xc++) {
int startY = yc - radius;
int startX = xc - radius;
int endY = yc + radius;
int endX = xc + radius;
int ar = 0, ag = 0, ab = 0;
double sumWeight = 0;
double distance;
double dWeight;
int r, g, b;
for (int y = startY; y <= endY; y++) {
for (int x = startX; x <= endX; x++) {
if (x >= area.x && x < area.x + area.width
&& y >= area.y && y < area.y + area.height) {
int k = y * width * ImageHandler.BLOCK_SIZE + x * ImageHandler.BLOCK_SIZE;
r = copyBytes.get(k) & 0xff;
g = copyBytes.get(k + 1) & 0xff;
b = copyBytes.get(k + 2) & 0xff;
} else {
r = 0;
g = 0;
b = 0;
}
distance = Math.max(Math.abs(x - xc), Math.abs(y - yc));
dWeight = 1 - distance / (radius + 1);
sumWeight += dWeight;
ar += r * dWeight;
ag += g * dWeight;
ab += b * dWeight;
}
}
int k = yc * width * ImageHandler.BLOCK_SIZE + xc * ImageHandler.BLOCK_SIZE;
int blurredRed = (int) (ar / sumWeight);
int blurredGreen = (int) (ag / sumWeight);
int blurredBlue = (int) (ab / sumWeight);
if ( blurredRed < normalThreshold
&& blurredGreen < normalThreshold
&& blurredBlue < normalThreshold
) {
bytes.put(k, (byte) 0);
bytes.put(k + 1, (byte) 0);
bytes.put(k + 2, (byte) 0);
}
}
}
}
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
}