Skip to content

Commit 619f22e

Browse files
committed
initial push
1 parent ee8ab75 commit 619f22e

File tree

12 files changed

+1062
-0
lines changed

12 files changed

+1062
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
import java.awt.image.BufferedImage;
4+
5+
public abstract class BaseBufferedFilter extends Block {
6+
ImageData _dataBuffer;
7+
public BaseBufferedFilter(int width, int height) {
8+
_dataBuffer = new ImageData(width, height);
9+
_dataBuffer.clear(1,0,0,0);
10+
11+
}
12+
13+
/**
14+
* @throws IllegalStateException if dimension of the image is different than the buffer.
15+
*/
16+
void assertSize(ImageData image) {
17+
int w = _dataBuffer.getWidth();
18+
int h = _dataBuffer.getHeight();
19+
if(w != image.getWidth() || h != image.getHeight()){
20+
throw new IllegalStateException("dimensions of given image are not matched with dimensions of this " + getClass().toString());
21+
}
22+
}
23+
24+
public void convertToDifferences(ImageData data) {
25+
26+
27+
float[] result = _dataBuffer.getRawData();
28+
float[] source = data.getRawData();
29+
int length = source.length;
30+
for(int i = 0; i < length;) {
31+
result[i] = Math.abs(source[i] - result[i]);
32+
i++;
33+
result[i] = Math.abs(source[i] - result[i]);
34+
i++;
35+
result[i] = Math.abs(source[i] - result[i]);
36+
i++;
37+
38+
i++;
39+
}
40+
}
41+
42+
void copyRedToGreenBlue() {
43+
44+
copyRedToGreenBlue(_dataBuffer);
45+
}
46+
47+
public BufferedImage toBufferedImage() {
48+
return _dataBuffer.toBufferedImage();
49+
}
50+
51+
public ImageData getBuffer() {
52+
return _dataBuffer;
53+
}
54+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
import java.util.ArrayList;
4+
5+
public abstract class Block {
6+
7+
private Object[] _inputs;
8+
private ArrayList<Connection> _connections;
9+
private int _setInputCount;
10+
11+
public Block() {
12+
_inputs = new Object[numberOfInputs()];
13+
_setInputCount = 0;
14+
_connections = new ArrayList<>();
15+
}
16+
17+
public <T> T getInput(int id) {
18+
return (T) _inputs[id];
19+
}
20+
21+
public int numberOfInputs() {
22+
return 1;
23+
}
24+
public int numberOfOutputs() {
25+
return 1;
26+
}
27+
28+
public void setInput(int index, Object data){
29+
if(_inputs[index] == null){
30+
_setInputCount++;
31+
}
32+
_inputs[index] = data;
33+
if(_setInputCount == numberOfInputs()){
34+
performOperation();
35+
_setInputCount = 0;
36+
for(int i = 0; i < _inputs.length; i++) {
37+
_inputs[i] = null;
38+
}
39+
}
40+
}
41+
public void setInput(Object data){
42+
setInput(0, data);
43+
}
44+
public abstract void performOperation();
45+
46+
public void connectOutput(int outputIndex, Block block, int inputIndex) {
47+
Connection c = new Connection();
48+
c.output = outputIndex;
49+
c.input = inputIndex;
50+
c.target = block;
51+
_connections.add(c);
52+
}
53+
public void connectOutput(Block block){
54+
connectOutput(0, block, 0);
55+
}
56+
57+
public void sendOutput(Object data, int outputIndex){
58+
for(int i = 0; i < _connections.size(); i++){
59+
Connection c = _connections.get(i);
60+
if(c.output == outputIndex) {
61+
c.sendData(data);
62+
}
63+
}
64+
}
65+
66+
void copyRedToGreenBlue(ImageData image) {
67+
68+
float[] rawData = image.getRawData();
69+
int offset;
70+
// copy the value of the red channel to other channels
71+
for(int i = 0; i < rawData.length; i += ImageData.BYTES_PER_PIXEL){
72+
float nextValue = rawData[i + ImageData.OFFSET_R];
73+
rawData[i+ ImageData.OFFSET_G] = nextValue;
74+
rawData[i+ ImageData.OFFSET_B] = nextValue;
75+
}
76+
}
77+
private static class Connection{
78+
int input;
79+
int output;
80+
Block target;
81+
void sendData(Object data){
82+
target.setInput(input, data);
83+
}
84+
}
85+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
public class BlockIn extends Block{
4+
@Override
5+
public void performOperation() {
6+
sendOutput(getInput(0), 0);
7+
}
8+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
public class BlockOut extends Block {
4+
private Listener _listener;
5+
@Override
6+
public void performOperation() {
7+
_listener.resultIsReady(getInput(0));
8+
}
9+
public void setListener(Listener l){
10+
_listener = l;
11+
}
12+
public interface Listener<T>{
13+
void resultIsReady(T data);
14+
}
15+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
4+
public class BoxBlurFilter extends BaseBufferedFilter {
5+
6+
7+
private Configuration _configuration;
8+
9+
private ImageData _dataBuffer2;
10+
11+
public BoxBlurFilter(int width, int height) {
12+
super(width, height);
13+
_dataBuffer2 = new ImageData(width, height);
14+
}
15+
public BoxBlurFilter setConfiguration(Configuration configuration){
16+
_configuration = configuration;
17+
return this;
18+
}
19+
20+
@Override
21+
public void performOperation() {
22+
ImageData image = getInput(0);
23+
assertSize(image);
24+
_dataBuffer.copyFrom(image);
25+
for(int i = 0; i < _configuration.repeat; i++){
26+
blur();
27+
}
28+
29+
copyRedToGreenBlue();
30+
sendOutput(_dataBuffer, 0);
31+
}
32+
33+
private void swapBuffers() {
34+
ImageData temp = _dataBuffer2;
35+
_dataBuffer2 = _dataBuffer;
36+
_dataBuffer = temp;
37+
}
38+
39+
private void blur() {
40+
int w = _dataBuffer.getWidth();
41+
int h = _dataBuffer.getHeight();
42+
int r = _configuration.radius;
43+
accumH(w, h, r);
44+
accumV(w, h, r);
45+
}
46+
private void accumV(int w, int h, int r) {
47+
final int bbp = ImageData.BYTES_PER_PIXEL;
48+
final int stride = w * bbp;
49+
accum(w, h, bbp, stride, r);
50+
}
51+
private void accumH(int w, int h, int r) {
52+
final int bbp = ImageData.BYTES_PER_PIXEL;
53+
final int stride = w * bbp;
54+
accum(h, w, stride, bbp, r);
55+
}
56+
private void accum(int rowCount, int columnCount,
57+
int offStep, int indexStep,
58+
int radius) {
59+
float[] source = _dataBuffer.getRawData();
60+
float[] target = _dataBuffer2.getRawData();
61+
final float normalizer = 1.0f / (radius + radius + 1);
62+
final int bR = radius * indexStep;
63+
final int stride = columnCount * indexStep;
64+
int endOffset = rowCount * offStep + ImageData.OFFSET_R;
65+
for (int offset = ImageData.OFFSET_R; offset < endOffset; offset += offStep) {
66+
float firstValue = source[offset];
67+
// assume off screen values are the same with pixel on the edge
68+
// and predict accumulation value according to that
69+
float accumulation = firstValue * radius;
70+
int i = offset;
71+
int end = offset + bR;
72+
for (; i < end; i += indexStep) {
73+
accumulation += source[i];
74+
}
75+
76+
// calculate blur for range x = 0 -> r
77+
i = offset;
78+
for (; i < end; i += indexStep) {
79+
accumulation += source[i + bR];
80+
target[i] = accumulation * normalizer;
81+
accumulation -= firstValue;
82+
}
83+
84+
// calculate blur for range x = r -> (width - r)
85+
end = stride - bR + offset;
86+
for (; i < end; i += indexStep) {
87+
accumulation += source[i + bR];
88+
target[i] = accumulation * normalizer;
89+
accumulation -= source[i - bR];
90+
}
91+
92+
// calculate blur for range x = (width - r) -> width
93+
end = offset + stride;
94+
float lastValue = source[end - indexStep];
95+
for (; i < end; i += indexStep) {
96+
accumulation += lastValue;
97+
target[i] = accumulation * normalizer;
98+
accumulation -= source[i - bR];
99+
}
100+
}
101+
swapBuffers();
102+
}
103+
104+
105+
public static class Configuration {
106+
int radius;
107+
int repeat;
108+
109+
/**
110+
* Creates a configuration object to perform a box blur.
111+
* @param radius a radius for box blur operation. One dimension of box is
112+
* calculated as (2 * radius + 1).
113+
* @param repeat repeat count that box blur operation will be performed.
114+
* Multiple passes of the box blur approximates to gaussian blur.
115+
*/
116+
public Configuration(int radius, int repeat){
117+
this.radius = radius;
118+
this.repeat = repeat;
119+
}
120+
}
121+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.mobge.simpleimageprocessing;
2+
3+
4+
public class CurvatureFilter extends BaseBufferedFilter{
5+
public CurvatureFilter(int width, int height) {
6+
super(width, height);
7+
}
8+
9+
10+
@Override
11+
public void performOperation() {
12+
ImageData image = getInput(0);
13+
super.assertSize(image);
14+
15+
int w = image.getWidth();
16+
int h = image.getHeight();
17+
18+
final float[] source = image.getRawData();
19+
final float[] target = _dataBuffer.getRawData();
20+
21+
final int bbp = ImageData.BYTES_PER_PIXEL;
22+
final int stride = bbp * w;
23+
24+
int offset = ImageData.OFFSET_R;
25+
int end = source.length - stride;
26+
int lineEnd = stride - bbp;
27+
offset += stride;
28+
for(; offset < end; offset += stride) {
29+
for(int x = bbp; x < lineEnd; x += bbp) {
30+
int iCenter = offset + x;
31+
float value = source[iCenter];
32+
33+
float dif = 0;
34+
int count = 0;
35+
float next;
36+
37+
next = source[iCenter + stride];
38+
if(next != 0){
39+
count++;
40+
dif += next;
41+
}
42+
next = source[iCenter - stride];
43+
if(next != 0){
44+
count++;
45+
dif += next;
46+
}
47+
next = source[iCenter + bbp];
48+
if(next != 0){
49+
count++;
50+
dif += next;
51+
}
52+
next = source[iCenter - bbp];
53+
if(next != 0){
54+
count++;
55+
dif += next;
56+
}
57+
58+
float result;
59+
if(count > 0){
60+
result = dif / count - value + 0.5f;
61+
}
62+
else{
63+
result = value;
64+
}
65+
target[iCenter] = result;
66+
}
67+
}
68+
69+
copyRedToGreenBlue();
70+
sendOutput(_dataBuffer, 0);
71+
}
72+
73+
}

0 commit comments

Comments
 (0)