2

Currently I am programming an example for a java program which uses basic Multithreading. I want to show the advantage of the data composition principle in an image processing application that resembles a monochromatic filter. I load a picture in a buffer and then spawn four Threads which all compute different parts of the Image.

The image is divided into four slices and the computation time alone is lowered according to my expectations (3 to 4 times faster on a quadcore). The problem is i try to avoid Race Conditions by giving each Thread a Buffer where the computed picture is saved. After the execution each Thread saves it's part of the picture in a jpg.

My question here is if there is a pattern i can use to save the different slices as one picture again while avoiding the dangers of the Shared mutable state variables. If i use a static Variable in my Processing Class to reassemble the picture I get times that are even worse than the singlethreaded solutions. How can i make the effiency that multithreading offers appearant in this example?

Thats my Code for the Multithreaded application:

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;


public class Main {
  static int threadCount=4;
  public static void main(String[] args) {
    // TODO Auto-generated method stub
      BufferedImage original=null;
      BufferedImage greyscale=null;

      //loading Picture into Buffer
    try{
           original = ImageIO.read(new File("Desert.jpg"));
         }
    catch (IOException e) 
    {
            e.printStackTrace();

    }


        ArrayList<Thread> threads = new ArrayList<Thread>();


        //Creating Threads, each Thread gets a Copy of the Image
        for( int i=0; i < threadCount; i++)

        {
            final int threadNumber =i;

            threads.add(new Thread(new Processor2(deepCopy(original),threadNumber,threadCount)));}

        //threads gets started
        long start = System.currentTimeMillis();
        for( int i=0; i < threadCount; i++){
            threads.get(i).start();
        }

        for( int i=0; i < threadCount; i++){
            try {
                threads.get(i).join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();


        long seconds = (end-start);
         System.out.println("Dauer: "+seconds+" ms.");

}

//Method that copies the Image
static BufferedImage deepCopy(BufferedImage bi) {
 ColorModel cm = bi.getColorModel();
 boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
 WritableRaster raster = bi.copyData(null);
 return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
 }


}

The Threads that get spawned Execute this code:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;


public class Processor2 implements Runnable  {




 BufferedImage greyscale;
 BufferedImage original;

int threadNumber, threadCount;

//The Constructor gets the Image, the total number of Threads and the own Threadnumber.
Processor2(BufferedImage image, int x, int y){
    this.original=image;

    threadNumber=x;
    threadCount=y;
}
Object lock =new Object();
@Override

// The run Method goes through the pixel of the assignes slide of the picture, renders it monochromatic and then saves it in an ImageBuffer. This image is saved after the loop has reached all pixels.
public void run() {
    // TODO Auto-generated method stub
int part =original.getWidth()/threadCount;
    greyscale = new BufferedImage(part,     original.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
    int x=0;
    try{for(int i=threadNumber*part; i<part*(threadNumber+1); i++) 
    {
        for(int j=0; j<original.getHeight(); j++)
        {

            // Get pixels
            int rgb = original.getRGB(i, j);
            int a = (rgb>>24)&0xff;
            int r = (rgb >> 16) & 0xFF;
            int g = (rgb >> 8) & 0xFF;
            int b = (rgb & 0xFF);

            int avg = (r + g + b) / 3;
            int gray = colorToRGB(a, avg, avg, avg);
            greyscale.setRGB(x, j, gray);

           } x++;
}}
    finally{
    saveImage(greyscale, threadNumber);
        }
}


public void start(){

}

private static int colorToRGB(int alpha, int red, int green, int blue) {
    int newPixel = 0;
    newPixel += alpha;
    newPixel = newPixel << 8;
    newPixel += red; newPixel = newPixel << 8;
    newPixel += green; newPixel = newPixel << 8;
    newPixel += blue;

    return newPixel;
}

static void saveImage(BufferedImage r,int threadNumber){

    try {
        ImageIO.write(r, "png",new    File("blackwhiteimageshared"+threadNumber+".png") );
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
  }

 }

This Code is around two to three times faster than going through every pixel in a loop in one thread. Would the Producer Consumer Pattern be a good method to change the Code to a state that after the execution i have one monochromatic image instead of 4 parts in a reasonable time?

Osmun
  • 21
  • 1

0 Answers0