Skip to content
38 changes: 38 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
26 changes: 26 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.andrewla</groupId>
<artifactId>convolution</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.11.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

13 changes: 13 additions & 0 deletions src/main/java/org/andrewla/ImageProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.andrewla;

import javax.imageio.ImageReader;
import java.awt.image.BufferedImage;
import java.util.List;

public interface ImageProcessor {
void addKernel(Kernel kernel);

void addImageReader(ImageReader reader);

List<BufferedImage> applyFilters();
}
15 changes: 15 additions & 0 deletions src/main/java/org/andrewla/Kernel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.andrewla;

public interface Kernel {
int getSize();

double getValue(int x, int y);

double getBias();

double getFactor();

Kernel getResized(int newSize);

Kernel getExpanded(int newSize);
}
7 changes: 7 additions & 0 deletions src/main/java/org/andrewla/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.andrewla;

public class Main {
public static void main(String[] args) {
System.out.println("Image filters");
}
}
111 changes: 111 additions & 0 deletions src/main/java/org/andrewla/kernels/AbstractKernel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

import java.util.Objects;

public abstract class AbstractKernel implements Kernel {
private int size;

private double[][] data;

private double factor;
private double bias;

protected AbstractKernel(int size) {
if (size % 2 == 0) {
throw new IllegalArgumentException("Size of kernel matrix should be odd");
}

this.size = size;
this.data = new double[size][size];
this.factor = 1;
this.bias = 0;
}

@Override
public int getSize() {
return size;
}

@Override
public double getValue(int x, int y) {
if (x < 0 || x > size) {
throw new IllegalArgumentException("Invalid X coordinate");
}

if (y < 0 || y > size) {
throw new IllegalArgumentException("Invalid Y coordinate");
}

return data[y][x];
}

protected void setValue(int x, int y, double value) {
if (x < 0 || x > size) {
throw new IllegalArgumentException("Invalid X coordinate");
}

if (y < 0 || y > size) {
throw new IllegalArgumentException("Invalid Y coordinate");
}

data[y][x] = value;
}

@Override
public double getBias() {
return bias;
}

protected void setBias(double bias) {
this.bias = bias;
}

@Override
public double getFactor() {
return factor;
}

protected void setFactor() {
var sum = 0.0;

for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
sum += data[i][j];
}
}

factor = 1 / sum;
}

protected Kernel expandWithZeros(int newSize) {
if (newSize <= this.size) {
return this;
}

if (newSize % 2 == 0) {
throw new IllegalArgumentException("Size of kernel matrix should be odd");
}

var newData = new double[newSize][newSize];
var expansion = newSize - size;

for (int i = 0; i < size; i++) {
System.arraycopy(data[i], 0, newData[i + expansion], expansion, size);
}

this.data = newData;
this.size = newSize;

return this;
}

@Override
public boolean equals(Object other) {
if (other == null || getClass() != other.getClass()) return false;

AbstractKernel that = (AbstractKernel) other;
return size == that.size && Double.compare(factor, that.factor) == 0 && Objects.deepEquals(data, that.data);
}
}
22 changes: 22 additions & 0 deletions src/main/java/org/andrewla/kernels/BoxBlur.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

public class BoxBlur extends AbstractKernel {
private final double blurRadius;

public BoxBlur(int size, double blurRadius) {
super(size);
this.blurRadius = blurRadius;
}

@Override
public Kernel getResized(int newSize) {
return null;
}

@Override
public Kernel getExpanded(int newSize) {
return new BoxBlur(getSize(), blurRadius).expandWithZeros(newSize);
}
}
34 changes: 34 additions & 0 deletions src/main/java/org/andrewla/kernels/Emboss.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

public class Emboss extends AbstractKernel {
public Emboss(int size) {
super(size);

for (int i = 0; i < size; i++) {
for (int j = 0; j <= i; j++) {
setValue(i, j, -1);
}

setValue(i, size - 1 - i, 0);

for (int j = i + 1; j < size; j++) {
setValue(i, j, 1);
}
}

setFactor();
setBias(128);
}

@Override
public Kernel getResized(int newSize) {
return new Emboss(newSize);
}

@Override
public Kernel getExpanded(int newSize) {
return new Emboss(getSize()).expandWithZeros(newSize);
}
}
41 changes: 41 additions & 0 deletions src/main/java/org/andrewla/kernels/GaussianBlur.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

public class GaussianBlur extends AbstractKernel {
private final double blurRadius;

public GaussianBlur(int size, double blurRadius) {
super(size);
this.blurRadius = blurRadius;

var center = size / 2;

for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
var x = (double) (j - center);
var y = (double) (i - center);

var s2 = 2 * blurRadius * blurRadius;
var r2 = x * x + y * y;

var value = Math.exp(-r2 / s2) / (Math.PI * s2);

setValue(i, j, value);
}
}

setFactor();
setBias(0);
}

@Override
public Kernel getResized(int newSize) {
return new GaussianBlur(newSize, blurRadius);
}

@Override
public Kernel getExpanded(int newSize) {
return new GaussianBlur(getSize(), blurRadius).expandWithZeros(newSize);
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/andrewla/kernels/Identity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

public class Identity extends AbstractKernel {
public Identity(int size) {
super(size);

var center = size / 2;

for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
setValue(i, j, 0);
}
}

setValue(center, center, 1);
}

@Override
public Kernel getResized(int newSize) {
return new Identity(newSize);
}

@Override
public Kernel getExpanded(int newSize) {
return new Identity(newSize);
}
}
40 changes: 40 additions & 0 deletions src/main/java/org/andrewla/kernels/MotionBlur.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.andrewla.kernels;

import org.andrewla.Kernel;

public class MotionBlur extends AbstractKernel {
private final double angle;

public MotionBlur(int size, double angle) {
super(size);
this.angle = angle;

var angleRadians = Math.toRadians(angle);

var sin = Math.sin(angleRadians);
var cos = Math.cos(angleRadians);

var center = size / 2;

for (int i = 0; i < size; i++) {
int x = (int) Math.round((i - center) * cos);
int y = (int) Math.round((i - center) * sin);
if (Math.abs(x) <= center && Math.abs(y) <= center) {
setValue(x + center, y + center, 1);
}
}

setFactor();
setBias(0.0);
}

@Override
public Kernel getResized(int newSize) {
return new MotionBlur(newSize, angle);
}

@Override
public Kernel getExpanded(int newSize) {
return new MotionBlur(newSize, angle).expandWithZeros(newSize);
}
}
Loading