How to implement 1-Bit Dithering using Java? - java

Recently, our teacher gave us the task to convert a colorful image to a 1-bit image using Java. After a little experimentation I had the following result:
BufferedImage image = ...
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int clr = image.getRGB(x, y);
int r = (clr & 0x00ff0000) >> 16;
int g = (clr & 0x0000ff00) >> 8;
int b = clr & 0x000000ff;
double mono = 0.2126*r + 0.7152*g + 0.0722*b;
int c = mono < 128 ? 1 : 0;
//Adding to image buffer
buffer.add(c);
}
}
Well, it works but a lot of details are unfortunately lost. Here is a comparison:
Original:
Output:
What I want: (HQ: https://i.stack.imgur.com/vlEAE.png)
I was considering adding dithering to my converter, but I haven't found a working way yet, let alone any pseudo code.
Can anyone help me?
Edit:
So I created a DitheringUtils-class:
import java.awt.Color;
import java.awt.image.BufferedImage;
public class DitheringUtils {
public static BufferedImage dithering(BufferedImage image) {
Color3i[] palette = new Color3i[] {
new Color3i(0, 0, 0),
new Color3i(255, 255, 255)
};
int width = image.getWidth();
int height = image.getHeight();
Color3i[][] buffer = new Color3i[height][width];
for(int y=0;y<height;y++) {
for(int x=0;x<width;x++) {
buffer[y][x] = new Color3i(image.getRGB(x, y));
}
}
for(int y=0; y<image.getHeight();y++) {
for(int x=0; x<image.getWidth();x++) {
Color3i old = buffer[y][x];
Color3i nem = findClosestPaletteColor(old, palette);
image.setRGB(x, y, nem.toColor().getRGB());
Color3i error = old.sub(nem);
if (x+1 < width) buffer[y ][x+1] = buffer[y ][x+1].add(error.mul(7./16));
if (x-1>=0 && y+1<height) buffer[y+1][x-1] = buffer[y+1][x-1].add(error.mul(3./16));
if (y+1 < height) buffer[y+1][x ] = buffer[y+1][x ].add(error.mul(5./16));
if (x+1<width && y+1<height) buffer[y+1][x+1] = buffer[y+1][x+1].add(error.mul(1./16));
}
}
return image;
}
private static Color3i findClosestPaletteColor(Color3i match, Color3i[] palette) {
Color3i closest = palette[0];
for(Color3i color : palette) {
if(color.diff(match) < closest.diff(match)) {
closest = color;
}
}
return closest;
}
}
class Color3i {
private int r, g, b;
public Color3i(int c) {
Color color = new Color(c);
this.r = color.getRed();
this.g = color.getGreen();
this.b = color.getBlue();
}
public Color3i(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
public Color3i add(Color3i o) {
return new Color3i(r + o.r, g + o.g, b + o.b);
}
public Color3i sub(Color3i o) {
return new Color3i(r - o.r, g - o.g, b - o.b);
}
public Color3i mul(double d) {
return new Color3i((int) (d * r), (int) (d * g), (int) (d * b));
}
public int diff(Color3i o) {
return Math.abs(r - o.r) + Math.abs(g - o.g) + Math.abs(b - o.b);
}
public int toRGB() {
return toColor().getRGB();
}
public Color toColor() {
return new Color(clamp(r), clamp(g), clamp(b));
}
public int clamp(int c) {
return Math.max(0, Math.min(255, c));
}
}
And changed my function to this:
for (int y = 0; y < dithImage.getHeight(); ++y) {
for (int x = 0; x < dithImage.getWidth(); ++x) {
final int clr = dithImage.getRGB(x, y);
final int r = (clr & 0xFF0000) >> 16;
final int g = (clr & 0xFF00) >> 8;
final int b = clr & 0xFF;
if(382.5>(r+g+b)) {
buffer.add(0);
} else {
buffer.add(1);
}
}
}
But the output ends up looking... strange?
I really don't get why there are such waves.

I finally got it working! I improved the diff function and changed if(382.5>(r+g+b)) to if(765==(r+g+b)).
My DitheringUtils-class:
import java.awt.Color;
import java.awt.image.BufferedImage;
public class DitheringUtils {
public static BufferedImage dithering(BufferedImage image) {
Color3i[] palette = new Color3i[] {
new Color3i(0, 0, 0),
new Color3i(255, 255, 255)
};
int width = image.getWidth();
int height = image.getHeight();
Color3i[][] buffer = new Color3i[height][width];
for(int y=0;y<height;y++) {
for(int x=0;x<width;x++) {
buffer[y][x] = new Color3i(image.getRGB(x, y));
}
}
for(int y=0; y<image.getHeight();y++) {
for(int x=0; x<image.getWidth();x++) {
Color3i old = buffer[y][x];
Color3i nem = findClosestPaletteColor(old, palette);
image.setRGB(x, y, nem.toColor().getRGB());
Color3i error = old.sub(nem);
if (x+1 < width) buffer[y ][x+1] = buffer[y ][x+1].add(error.mul(7./16));
if (x-1>=0 && y+1<height) buffer[y+1][x-1] = buffer[y+1][x-1].add(error.mul(3./16));
if (y+1 < height) buffer[y+1][x ] = buffer[y+1][x ].add(error.mul(5./16));
if (x+1<width && y+1<height) buffer[y+1][x+1] = buffer[y+1][x+1].add(error.mul(1./16));
}
}
return image;
}
private static Color3i findClosestPaletteColor(Color3i match, Color3i[] palette) {
Color3i closest = palette[0];
for(Color3i color : palette) {
if(color.diff(match) < closest.diff(match)) {
closest = color;
}
}
return closest;
}
}
class Color3i {
private int r, g, b;
public Color3i(int c) {
Color color = new Color(c);
this.r = color.getRed();
this.g = color.getGreen();
this.b = color.getBlue();
}
public Color3i(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
public Color3i add(Color3i o) {
return new Color3i(r + o.r, g + o.g, b + o.b);
}
public Color3i sub(Color3i o) {
return new Color3i(r - o.r, g - o.g, b - o.b);
}
public Color3i mul(double d) {
return new Color3i((int) (d * r), (int) (d * g), (int) (d * b));
}
public int diff(Color3i o) {
int Rdiff = o.r - r;
int Gdiff = o.g - g;
int Bdiff = o.b - b;
int distanceSquared = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
return distanceSquared;
}
public int toRGB() {
return toColor().getRGB();
}
public Color toColor() {
return new Color(clamp(r), clamp(g), clamp(b));
}
public int clamp(int c) {
return Math.max(0, Math.min(255, c));
}
}
The final writing function:
for (int y = 0; y < dithImage.getHeight(); ++y) {
for (int x = 0; x < dithImage.getWidth(); ++x) {
final int clr = dithImage.getRGB(x, y);
final int r = (clr & 0xFF0000) >> 16;
final int g = (clr & 0xFF00) >> 8;
final int b = clr & 0xFF;
if(765==(r+g+b)) {
buffer.add(0);
} else {
buffer.add(1);
}
}
}
Thanks everyone!

BufferedImage image = ...
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
Color color = new Color(image.getRGB(x, y));
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
int mono = (red+green+blue)/255;
//Adding to image buffer
int col = (0 << 24) | (mono << 16) | (mono << 8) | mono;
image.setRGB(x,y,col);
}
}
Try this out
What you were doing wrong was, instead of trying to convert the picture to grayscale you were trying to convert to black and white.

Related

Gaussian Blur Higher Radius Darkens Image

I implemented Gaussian Blur in Java, it seems to work on smaller radiuses but not on bigger ones. I'm not sure why on bigger radiuses the image darkens, I followed the same formula and the steps to apply the blur. Generating the blur matrix and applying it on the original image, and setting the pixel value to be the sum of the result of multiplying the image matrix with the blur matrix. I added the code I wrote below:
public class GaussianBlur extends ImageFilter {
private int radius;
private double sigma;
public GaussianBlur(String imageFilename, int radius) {
super(imageFilename);
this.radius = radius;
this.sigma = ((2.0 * radius) + 1.0) / 2.0;
}
#Override
public void applyFilter() throws IOException {
init();
Matrix<Double> gaussianMatrix = getGaussianMatrix();
Matrix<Color> imageMatrix, weightedImageMatrix;
Color weightedPixelSum;
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
imageMatrix = getImageMatrix(i, j);
weightedImageMatrix = multiplyImageMatrixWithWeight(imageMatrix, gaussianMatrix);
weightedPixelSum = getWeightedGaussianBlurValue(weightedImageMatrix);
getFilter().setRGB(i, j, weightedPixelSum.getRGB());
}
}
}
private Matrix<Double> getGaussianMatrix() {
Matrix<Double> gaussianMatrix = new Matrix<>(Double.class, radius);
double weightedSum = 0.0;
int matrixI = 0, matrixJ;
double gaussianValue;
for(int i = -radius; i <= radius; i++) {
matrixJ = 0;
for(int j = -radius; j <= radius; j++) {
gaussianValue = getGaussianValue(i, j);
weightedSum += gaussianValue;
gaussianMatrix.setValue(matrixI, matrixJ, gaussianValue);
matrixJ++;
}
matrixI++;
}
for(int i = 0; i < gaussianMatrix.getMatrix().length; i++) {
for(int j = 0; j < gaussianMatrix.getMatrix()[i].length; j++) {
gaussianMatrix.setValue(i, j, gaussianMatrix.getValue(i, j) / weightedSum);
}
}
return gaussianMatrix;
}
private double getGaussianValue(int x, int y) {
return 1.0 / (2.0 * Math.PI * sigma * sigma) * Math.pow(Math.E, -((x * x) + (y * y)) / (2.0 * (sigma * sigma)));
}
private Color getWeightedGaussianBlurValue(Matrix<Color> weightedImageMatrix) {
int r = 0, g = 0, b = 0;
for(int i = 0; i < weightedImageMatrix.getMatrix().length; i++) {
for(int j = 0; j < weightedImageMatrix.getMatrix()[i].length; j++) {
if(weightedImageMatrix.getValue(i, j) != null) {
r += weightedImageMatrix.getValue(i, j).getRed();
g += weightedImageMatrix.getValue(i, j).getGreen();
b += weightedImageMatrix.getValue(i, j).getBlue();
}
}
}
return new Color(r, g, b);
}
/*
* Multiply each image pixel with its matrix value to get a new matrix with the weighted pixel values.
*/
private Matrix<Color> multiplyImageMatrixWithWeight(Matrix<Color> imageMatrix, Matrix<Double> gaussianMatrix) {
Matrix<Color> weightedImageMatrix = new Matrix<>(Color.class, this.radius);
Color weightedValue;
for(int i = 0; i < weightedImageMatrix.getMatrix().length; i++) {
for(int j = 0; j < weightedImageMatrix.getMatrix()[i].length; j++) {
if(imageMatrix.getValue(i, j) != null) {
weightedValue = new Color(
(int) ((double) imageMatrix.getValue(i, j).getRed() * gaussianMatrix.getValue(i, j)),
(int) ((double) imageMatrix.getValue(i, j).getGreen() * gaussianMatrix.getValue(i, j)),
(int) ((double) imageMatrix.getValue(i, j).getBlue() * gaussianMatrix.getValue(i, j))
);
weightedImageMatrix.setValue(i, j, weightedValue);
} else {
weightedImageMatrix.setValue(i, j, null);
}
}
}
return weightedImageMatrix;
}
/*
* Given the center points (i, j), construct a matrix from the image to blur.
*/
private Matrix<Color> getImageMatrix(int i, int j) {
Matrix<Color> imageMatrix = new Matrix<>(Color.class, radius);
int matrixI = 0, matrixJ;
for(int x = i - radius; x <= i + radius; x++) {
matrixJ = 0;
for(int y = j - radius; y <= j + radius; y++) {
if(x > -1 && y > -1 && x < getOriginal().getWidth() && y < getOriginal().getHeight()) {
imageMatrix.setValue(matrixI, matrixJ, new Color(getOriginal().getRGB(x, y)));
} else {
imageMatrix.setValue(matrixI, matrixJ, null);
}
matrixJ++;
}
matrixI++;
}
return imageMatrix;
}
private class Color {
private int r, g, b;
public Color(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
public Color(int rgb) {
this((rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff);
}
public int getRed() {
return r;
}
public int getGreen() {
return g;
}
public int getBlue() {
return b;
}
public int getRGB() {
return (r << 16) | (g << 8) | b;
}
#Override
public String toString() {
return "(" + r + "," + g + "," + b + ")";
}
}
private class Matrix<T> {
private T[][] matrix;
public Matrix(Class<T> clazz, int radius) {
int length = (2 * radius) + 1;
matrix = (T[][]) Array.newInstance(clazz, length, length);
}
public T getValue(int i, int j) {
return matrix[i][j];
}
public void setValue(int i, int j, T value) {
matrix[i][j] = value;
}
public T[][] getMatrix() {
return matrix;
}
}
}
The class ImageFilter is just an abstract class with two instances of BufferedImage (one for the original image and one for the blurred image), and the displayImage function just displays the image in a message dialog.
The main method using this class is
public static void main(String[] args) throws IOException {
String filename = "res" + File.separator + "TajMahal.jpeg";
GaussianBlur gaussianBlur = new GaussianBlur(filename, 2);
gaussianBlur.applyFilter();
gaussianBlur.displayImage();
}
And below are the resulting images
The original image:
Blurred with radius 2:
Blurred with radius 7:
How come blurring it with radius 7 is darkening the image? Is there something missing in the formula or something that I have missed?

Divide canvas into multiple stripes using RGB

I want to divide the canvas into 8 vertical black and white Stripes. I wrote a method changeValue to change the value of the color everytime the loop is executed but the canvas is complete white. I think my changeValue method doesn't do as supposed but I can't explain why.
So far I got this:
public class Stripe {
public boolean switch = false;
private void stripes(int[] pixels, int width, int height) {
// TODO set some values here
int counter = 1;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pos = y * width + x;
int r, g, b;
// TODO code for the flag.
r = 255;
g = 255;
b = 255;
for (int i = 0; i < 8; i++) {
if (x < (counter * (width - 1)) / 8) {
r = changeValue();
g = changeValue();
b = changeValue();
}
counter++;
switch ^= true;
}
pixels[pos] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
}
public int changeValue() {
if (switch) {
return 255;
} else {
return 0;
}
}
}
I am supposed not to write 8 If statements for the 8 stripes but this for example is the code for the Italian flag which are 3 vertical Stripes but which actually works:
private void flagItalian(int[] pixels, int width, int height) {
// TODO set some values here
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pos = y * width + x;
int r, g, b;
// TODO code for the flag.
r = 255;
g = 0;
b = 0;
if (x < 2 * (width - 1) / 3) {
r = 255;
g = 255;
b = 255;
}
if (x < (width - 1) / 3) {
r = 0;
g = 255;
b = 0;
}
pixels[pos] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
}
If you need alternating color stripes then you could go for the classic odd/even checks. Instead of you below code block
for (int i = 0; i < 8; i++) {
if (x < (counter * (width - 1)) / 8) {
r = changeValue();
g = changeValue();
b = changeValue();
}
counter++;
switch ^= true;
}
Try replacing with this one
if (x%2) {
r = 255;
g = 255;
b = 255
} else {
r = 0;
g = 0;
b = 0;
}

Swapping colors of two pixels

I must do n rounds of row pixel sorting of a buffered image, looping through each row and comparing the brightness of the current pixel to the one to the left of the current pixel. If the brightness of the current is less than the one to the left, I need to swap the colors of the pixels. This is my current code.
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int m = 0; m<n;m++){
for (int y=0;y<img.getHeight();y++){
for(int x =1; x<img.getWidth();x++){
int temp = img.getRGB(x-1,y);
int temp2 = img.getRGB(x, y);
int gr = (int)brightness(temp);
int gr2 = (int)brightness(temp2);
if(gr2<gr){
result.setRGB(x, y, rgbColour(temp2,temp2,temp2));
result.setRGB(x-1, y, rgbColour(temp,temp,temp));
}
}
}
}
The methods I've been given are as follows.
public static int getRed(int rgb) { return (rgb >> 16) & 0xff; }
public static int getGreen(int rgb) { return (rgb >> 8) & 0xff; }
public static int getBlue(int rgb) { return rgb & 0xff; }
public static int rgbColour(int r, int g, int b) {
return (r << 16) | (g << 8) | b;
}
public static double brightness(int rgb) {
int r = getRed(rgb);
int g = getGreen(rgb);
int b = getBlue(rgb);
return 0.21*r + 0.72*g + 0.07*b;
}
public static BufferedImage convertToGrayscale(BufferedImage img) {
BufferedImage result = new BufferedImage(
img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB
);
for(int x = 0; x < img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
int col = img.getRGB(x, y);
int gr = (int)brightness(col);
result.setRGB(x, y, rgbColour(gr, gr, gr));
}
}
return result;
}
You are not switching the values properly after the comparison:
for(int x =1; x<img.getWidth();x++){
int temp = img.getRGB(x-1,y);
int temp2 = img.getRGB(x, y);
...
if (gr2 < gr) {
result.setRGB(x, y, rgbColour(temp2,temp2,temp2)); // same as in img
result.setRGB(x-1, y, rgbColour(temp,temp,temp)); // same as in img
}
}
Try this if-clause instead:
...
if (gr2 < gr) { // swap values in result
result.setRGB(x-1, y, rgbColour(temp2,temp2,temp2));
result.setRGB(x, y, rgbColour(temp,temp,temp));
} else { // keep values in result same as in img
result.setRGB(x, y, rgbColour(temp2,temp2,temp2));
result.setRGB(x-1, y, rgbColour(temp,temp,temp));
}

Assign color to a pixel based on its neighbors

I've put all the black pixels of the image in an array and I want them to get the color of their left neighbor. I run the code without errors but the result is not really what I'm expecting.
Where those black stripes comes form? I was expecting it to be all red.
Here's my code and results.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.*;
public class ImageTest {
public static BufferedImage Threshold(BufferedImage img) {
int height = img.getHeight();
int width = img.getWidth();
BufferedImage finalImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
int r = 0;
int g = 0;
int b = 0;
List<Integer> blackpixels = new ArrayList<Integer>();
for (int x = 0; x < width; x++) {
try {
for (int y = 0; y < height; y++) {
//Get RGB values of pixels
int rgb = img.getRGB(x, y);
r = ImageTest.getRed(rgb);
g = ImageTest.getGreen(rgb);
b = ImageTest.getBlue(rgb);
int leftLoc = (x-1) + y*width;
if ((r < 5) && (g < 5) && (b < 5)) {
blackpixels.add(rgb);
Integer[] simpleArray = new Integer[ blackpixels.size() ];
System.out.print(simpleArray.length);
int pix = 0;
while(pix < simpleArray.length) {
r = leftLoc;
pix = pix +1;
}
}
finalImage.setRGB(x,y,ImageTest.mixColor(r, g,b));
}
}
catch (Exception e) {
e.getMessage();
}
}
return finalImage;
}
private static int mixColor(int red, int g, int b) {
return red<<16|g<<8|b;
}
public static int getRed(int rgb) {
return (rgb & 0x00ff0000) >> 16;
}
public static int getGreen(int rgb) {
return (rgb & 0x0000ff00) >> 8;
}
public static int getBlue(int rgb) {
return (rgb & 0x000000ff) >> 0;
}
}
The following might work.
The main change is that it first collects the locations of ALL dark pixels, then goes over them to assign the colour from their left neighbours.
import java.awt.image.BufferedImage;
import java.util.*;
public class BlackRedImage
{
public static BufferedImage Threshold( BufferedImage img )
{
int height = img.getHeight();
int width = img.getWidth();
BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
List<Integer> blackpixels = new ArrayList<Integer>();
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
int rgb = img.getRGB(x, y); // Get the pixel in question
int r = BlackRedImage.getRed(rgb);
int g = BlackRedImage.getGreen(rgb);
int b = BlackRedImage.getBlue(rgb);
if ( (r < 5) && (g < 5) && (b < 5) )
{ // record location of any "black" pixels found
blackpixels.add(x + (y * width));
}
finalImage.setRGB(x, y, rgb);
}
}
// Now loop through all "black" pixels, setting them to the colour found to their left
for ( int blackPixelLocation: blackpixels )
{
if ( blackPixelLocation % width == 0 )
{ // these pixels are on the left most edge, therefore they do not have a left neighbour!
continue;
}
int y = blackPixelLocation / width;
int x = blackPixelLocation - (width * y);
int rgb = img.getRGB(x - 1, y); // Get the pixel to the left of the "black" pixel
System.out.println("x = " + x + ", y = " + y + ", rgb = " + rgb);
finalImage.setRGB(x, y, rgb);
}
return finalImage;
}
private static int mixColor( int red, int g, int b )
{
return red << 16 | g << 8 | b;
}
public static int getRed( int rgb )
{
return (rgb & 0x00ff0000) >> 16;
}
public static int getGreen( int rgb )
{
return (rgb & 0x0000ff00) >> 8;
}
public static int getBlue( int rgb )
{
return (rgb & 0x000000ff) >> 0;
}
}
EDIT: Here is a simpler version (doesn't collect the black pixels)
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.*;
public class ColourMove
{
public static BufferedImage Threshold( BufferedImage img )
{
int width = img.getWidth();
int height = img.getHeight();
BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for ( int x = 1; x < width; x++ ) // Start at 1 as the left most edge doesn't have a left neighbour
{
for ( int y = 0; y < height; y++ )
{
Color colour = new Color(img.getRGB(x, y));
int red = colour.getRed();
int green = colour.getGreen();
int blue = colour.getBlue();
if ( (red < 5) && (green < 5) && (blue < 5) )
{ // Encountered a "black" pixel, now replace it with it's left neighbour
finalImage.setRGB(x, y, img.getRGB(x - 1, y));
}
else
{ // Non-black pixel
finalImage.setRGB(x, y, colour.getRGB());
}
}
}
return finalImage;
}
}

Java Code Color Function Error

Aloha,
i have trouble finding the error in my java code. In my opinion everything is fine and correct but the function is not executed correctly and I dont understand why. The function should detect the difference between the colors and calculate the arithmetic mean of them.
The resilt of it should be draw under the original picture. What did I miss, please help me?
package edge;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import javax.swing.JComponent;
import javax.swing.JFrame;
/**
*
* #author Alaska
*/
public class Edge extends JComponent {
final int W = 500;
final int H = 300;
Image m_TrgImg, m_SrcImg;
public Edge(JFrame father) {
try {
FileDialog diag = new FileDialog(father);
diag.setVisible(true);
m_SrcImg = getToolkit().getImage(diag.getDirectory() + diag.getFile()).getScaledInstance(W, H, Image.SCALE_SMOOTH);
MediaTracker mt = new MediaTracker(this);
mt.addImage(m_SrcImg, 0);
mt.waitForAll();
int[] srcPix = new int[W * H];
int[] trgPix = new int[W * H];
PixelGrabber grab = new PixelGrabber(m_SrcImg, 0, 0, W, H, srcPix, 0, W);
grab.getPixels();
MemoryImageSource imgProd = new MemoryImageSource(W, H, trgPix, 0, W);
m_TrgImg = createImage(imgProd);
detectEdges(srcPix, trgPix);
m_TrgImg.flush();
} catch (InterruptedException e) {
System.out.println(e);
}
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(m_SrcImg, 0, 0, this);
g.drawImage(m_TrgImg, 0, H, this);
}
#Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
#Override
public Dimension getMinimumSize() {
return new Dimension(W, H * 2);
}
private void detectEdges(int[] srcPix, int[] trgPix) {
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
trgPix[y * W + x] = compColor(srcPix, x, y);
}
}
}
private int getRed(int col) {
return (col >> 16) & 255;
}
private int getGreen(int col) {
return (col >> 8) & 255;
}
private int getBlue(int col) {
return col & 255;
}
private int compColor(int[] srcPix, int x, int y) {
int red = 0;
int green = 0;
int blue = 0;
int cnt = 0;
final int IDX = y * W + x;
final int RED = getRed(srcPix[IDX]);
final int GREEN = getGreen(srcPix[IDX]);
final int BLUE = getBlue(srcPix[IDX]);
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (dx != 0 || dy != 0) {
final int X = x + dx;
final int Y = y + dy;
final int LOCAL_IDX = Y * W + X;
if (0 <= X && X < W && 0 <= Y && Y < H) {
++cnt;
red += Math.abs(RED - getRed(srcPix[LOCAL_IDX]));
green += Math.abs(GREEN - getGreen(srcPix[LOCAL_IDX]));
blue += Math.abs(BLUE - getBlue(srcPix[LOCAL_IDX]));
}
}
}
}
return 0xff000000 | (255 - (red / cnt) << 16) | (255 - (green / cnt) << 8) | (255 - (blue / cnt));
}
public static void main(String[] args) throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.getContentPane().add(new Edge(f));
f.pack();
f.setVisible(true);
}
}
You need to grab.grabPixels(), not grab.getPixels().
http://docs.oracle.com/javase/7/docs/api/java/awt/image/PixelGrabber.html
Also what trashgod said about Initial Threads. You need to create your GUI with SwingUtilities.invokeLater().
Edit
The method is executed correctly but you are getting all black values on the input because your pixel array contains only the initialized values which is 0.

Categories