Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to separate an image into two with java

I'm wondering if there is a "smart" way of splitting an image based on certain features.

The images are 300x57, black and white (actually grayscale, but most colors are either black or white), it is comprised of two main features (let's call them blobs) separated by black space, each blob slightly varies in width and height, the position of the blobs also varies, the blobs NEVER overlap!

Here is what an image "looks" like:

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

The resulting split would be something like this:

------------     -------------
----WWW-----     ----WWWWW----
---WWWWWWW--     --WWWWWW-----
-----WWWW---     ----WWW------
------------     -------------

Steps I plan to take in order to split the image:

  1. Scan the image from one side to the other.
  2. Determine the edges of the blobs.
  3. Take the distance between the two inside edges.
  4. Split the image at the middle of the inside distance.
  5. Save the two images as separate files.

It would be nice if I normalize the image widths, so all of my images have a uniform width when they're saved.

I have no experience in image manipulation, so I don't know what's an efficient way to do this. I'm currently using a BufferedImage, getting the width/height, iterating over each pixel, etc. There is no wrong solution for my problem, but I'm looking for a more efficient one (less code + faster). I've also been looking into java.awt.Graphics...

I would appreciate if I get some ideas for more efficient ways to do this task. I want to stick with Java's built-in libraries, so is BufferedImage or Graphics2D the most efficient thing to use in this case?

EDIT: Here is the code after reading the suggestions:

public void splitAndSaveImage( BufferedImage image ) throws IOException
{
    // Process image ------------------------------------------         
    int height = image.getHeight();
    int width = image.getWidth();
    boolean edgeDetected = false;
    double averageColor = 0;
    int threshold = -10;
    int rightEdge = 0;
    int leftEdge = 0;
    int middle = 0;

    // Scan the image and determine the edges of the blobs.
    for(int w = 0; w < width; ++w)
    {               
        for(int h = 0; h < height; ++h)
        {
            averageColor += image.getRGB(w, h);
        }

        averageColor = Math.round(averageColor/(double)height);

        if( averageColor /*!=-1*/< threshold && !edgeDetected )
        {
            // Detected the beginning of the right blob
            edgeDetected = true;
            rightEdge = w;
        }else if( averageColor >= threshold && edgeDetected )
        {
            // Detected the end of the left blob
            edgeDetected = false;
            leftEdge = leftEdge==0? w:leftEdge;
        }

        averageColor = 0;
    }

    // Split the image at the middle of the inside distance.
    middle = (leftEdge + rightEdge)/2;

    // Crop the image
    BufferedImage leftImage = image.getSubimage(0, 0, middle, height);

    BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height);

    // Save the image
    // Save to file -------------------------------------------
    ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg"));

    ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg"));
}
like image 523
Kiril Avatar asked Jan 27 '10 17:01

Kiril


People also ask

How do you split a picture exactly in half?

To split images in half in Photoshop, select the marquee tool by pressing M, then click and drag over half of your image to create a rectangular selection. With the selection active, right-click and select New Layer Via Cut. This will cut the image in half and place the selected half on a new layer.


1 Answers

A simple way to do this is to sum the pixel values in each column (going down) to create a single array (the same width as your input image) of average values. Starting in the middle of the array, search for the minimum value. This will be the column where you can split the image.

This column probably won't be the center of the gap between your blobs. You can do another outward search from this column, going left first to find all similar columns, and then going right.

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

col avg:

---wwWWwww-----wWWWWww---

Depending on how blank the space is (pixel value wise) between the two blobs, you can set your threshold value pretty low. If there is some noise, it will have to be a little higher.

Finding the right threshold value can be a chore, unless you can determine it algorithmically.

like image 167
Trevor Harrison Avatar answered Sep 26 '22 00:09

Trevor Harrison